code: """
  act.qc.qctests
  ------------------------------
  
  Here we define the methods for performing the tests and putting the
  results in the ancillary quality control varible. If you add a test
  to this file you will need to add a method reference in the main
  qcfilter class definition to make it callable.
  
  """
  
  import numpy as np
  import pandas as pd
  import xarray as xr
  import warnings
  from act.utils import get_missing_value, convert_units
  
  
  # This is a Mixins class used to allow using qcfilter class that is already
  # registered to the xarray object. All the methods in this class will be added
  # to the qcfilter class. Doing this to make the code spread across more files
  # so it is more manageable and readable. Additinal files of tests can be added
  # to qcfilter by creating a new class in the new file and adding to qcfilter
  # class declaration.
  class QCTests:
      """
      This is a Mixins class used to allow using qcfilter class that is already
      registered to the xarray object. All the methods in this class will be added
      to the qcfilter class. Doing this to make the code spread across more files
      so it is more manageable and readable. Additinal files of tests can be added
      to qcfilter by creating a new class in the new file and adding to qcfilter
      class declaration.
  
      """
      def __init__(self, obj, **kwargs):
          self._obj = obj
  
      def add_missing_value_test(self, var_name, missing_value=None,
                                 missing_value_att_name='missing_value',
                                 test_number=None, test_assessment='Bad',
                                 test_meaning=None, flag_value=False,
                                 prepend_text=None):
          """
          Method to add indication in quality control variable
          where data value is set to missing value.
  
          Parameters
          ----------
          var_name : str
              Data variable name.
          missing_value : int or float
              Optional missing value to use. If not provided will attempt
              to get it from the variable attribute or use NaN.
          missing_value_att_name : str
              Optional attribute name to use.
          test_meaning : str
              The optional text description to add to flag_meanings
              describing the test. Will add a default if not set.
          test_assessment : str
              Optional single word describing the assessment of the test.
              Will set a default if not set.
          test_number : int
              Optional test number to use. If not set will ues next
              available test number.
          flag_value : boolean
              Indicates that the tests are stored as integers
              not bit packed values in quality control variable.
          prepend_text : str
              Optional text to prepend to the test meaning.
              Example is indicate what institution added the test.
  
          Returns
          -------
          test_info : tuple
              A tuple containing test information including var_name, qc variable name,
              test_number, test_meaning, test_assessment
  
          """
          if test_meaning is None:
              test_meaning = 'Value is set to missing_value.'
  
          if prepend_text is not None:
              test_meaning = ': '.join((prepend_text, test_meaning))
  
          if missing_value is None:
              missing_value = get_missing_value(self._obj, var_name, nodefault=True)
              if (missing_value is None and
                      self._obj[var_name].values.dtype.type in
                      (type(0.0), np.float16, np.float32, np.float64)):
                  missing_value = float('nan')
              else:
                  missing_value = -9999
  
          # Ensure missing_value attribute is matching data type
          missing_value = np.array(missing_value, dtype=self._obj[var_name].values.dtype.type)
  
          # New method using straight numpy instead of masked array
          with warnings.catch_warnings():
              warnings.filterwarnings("ignore", category=RuntimeWarning)
              if np.isnan(missing_value) is False:
                  index = np.equal(self._obj[var_name].values, missing_value)
              else:
                  index = np.isnan(self._obj[var_name].values)
  
          test_dict = self._obj.qcfilter.add_test(
              var_name, index=index,
              test_number=test_number,
              test_meaning=test_meaning,
              test_assessment=test_assessment,
              flag_value=flag_value)
  
          try:
              self._obj[var_name].attrs[missing_value_att_name]
          except KeyError:
              self._obj[var_name].attrs[missing_value_att_name] = missing_value
  
          return test_dict
  
      def add_less_test(self, var_name, limit_value, test_meaning=None,
                        test_assessment='Bad', test_number=None,
                        flag_value=False, limit_attr_name=None,
                        prepend_text=None):
          """
          Method to perform a less than test (i.e. minimum value) and add
          result to ancillary quality control variable. If ancillary
          quality control variable does not exist it will be created.
  
          Parameters
          ----------
          var_name : str
              Data variable name.
          limit_value : int or float or None
              Limit value to use in test. The value will be written
              to the quality control variable as an attribute. If set
              to None, will return without adding test.
          test_meaning : str
              The optional text description to add to flag_meanings
              describing the test. Will add a default if not set.
          test_assessment : str
              Optional single word describing the assessment of the test.
              Will set a default if not set.
          test_number : int
              Optional test number to use. If not set will ues next
              available test number.
          flag_value : boolean
              Indicates that the tests are stored as integers
              not bit packed values in quality control variable.
          limit_attr_name : str
              Optional attribute name to store the limit_value under
              quality control ancillary variable.
          prepend_text : str
              Optional text to prepend to the test meaning.
              Example is indicate what institution added the test.
  
          Returns
          -------
          test_info : tuple
              A tuple containing test information including var_name, qc variable name,
              test_number, test_meaning, test_assessment
  
          """
          if limit_value is None:
              return
  
          if limit_attr_name is None:
              if test_assessment == 'Suspect' or test_assessment == 'Indeterminate':
                  attr_name = 'warn_min'
              else:
                  attr_name = 'fail_min'
          else:
              attr_name = limit_attr_name
  
          if test_meaning is None:
              test_meaning = ('Data value less than {}.').format(attr_name)
  
          if prepend_text is not None:
              test_meaning = ': '.join((prepend_text, test_meaning))
  
          # New method with straight numpy
          with warnings.catch_warnings():
              warnings.filterwarnings("ignore", category=RuntimeWarning)
              index = np.less(self._obj[var_name].values, limit_value)
  
          result = self._obj.qcfilter.add_test(
              var_name, index=index,
              test_number=test_number,
              test_meaning=test_meaning,
              test_assessment=test_assessment,
              flag_value=flag_value)
  
          # Ensure limit_value attribute is matching data type
          limit_value = np.array(limit_value, dtype=self._obj[var_name].values.dtype.type)
  
          qc_var_name = result['qc_variable_name']
          self._obj[qc_var_name].attrs[attr_name] = limit_value
  
          return result
  
      def add_greater_test(self, var_name, limit_value, test_meaning=None,
                           test_assessment='Bad', test_number=None,
                           flag_value=False, limit_attr_name=None,
                           prepend_text=None):
          """
          Method to perform a greater than test (i.e. maximum value) and add
          result to ancillary quality control variable. If ancillary
          quality control variable does not exist it will be created.
  
          Parameters
          ----------
          var_name : str
              Data variable name.
          limit_value : int or float or None
              Limit value to use in test. The value will be written
              to the quality control variable as an attribute. If set
              to None will return without setting test.
          test_meaning : str
              The optional text description to add to flag_meanings
              describing the test. Will add a default if not set.
          test_assessment : str
              Optional single word describing the assessment of the test.
              Will set a default if not set.
          test_number : int
              Optional test number to use. If not set will ues next
              available test number.
          flag_value : boolean
              Indicates that the tests are stored as integers
              not bit packed values in quality control variable.
          limit_attr_name : str
              Optional attribute name to store the limit_value under
              quality control ancillary variable.
          prepend_text : str
              Optional text to prepend to the test meaning.
              Example is indicate what institution added the test.
  
          Returns
          -------
          test_info : tuple
              A tuple containing test information including var_name, qc variable name,
              test_number, test_meaning, test_assessment
  
          """
          if limit_value is None:
              return
  
          if limit_attr_name is None:
              if test_assessment == 'Suspect' or test_assessment == 'Indeterminate':
                  attr_name = 'warn_max'
              else:
                  attr_name = 'fail_max'
          else:
              attr_name = limit_attr_name
  
          if test_meaning is None:
              test_meaning = ('Data value greater than {}.').format(attr_name)
  
          if prepend_text is not None:
              test_meaning = ': '.join((prepend_text, test_meaning))
  
          with warnings.catch_warnings():
              warnings.filterwarnings("ignore", category=RuntimeWarning)
              index = np.greater(self._obj[var_name].values, limit_value)
  
          result = self._obj.qcfilter.add_test(
              var_name, index=index,
              test_number=test_number,
              test_meaning=test_meaning,
              test_assessment=test_assessment,
              flag_value=flag_value)
  
          # Ensure limit_value attribute is matching data type
          limit_value = np.array(limit_value, dtype=self._obj[var_name].values.dtype.type)
  
          qc_var_name = result['qc_variable_name']
          self._obj[qc_var_name].attrs[attr_name] = limit_value
  
          return result
  
      def add_less_equal_test(self, var_name, limit_value, test_meaning=None,
                              test_assessment='Bad', test_number=None,
                              flag_value=False, limit_attr_name=None,
                              prepend_text=None):
          """
          Method to perform a less than or equal to test
          (i.e. minimum value) and add result to ancillary quality control
          variable. If ancillary quality control variable does not exist it
          will be created.
  
          Parameters
          ----------
          var_name : str
              Data variable name.
          limit_value : int or float or None
              Limit value to use in test. The value will be written
              to the quality control variable as an attribute. If set
              to None will return without setttin test.
          test_meaning : str
              The optional text description to add to flag_meanings
              describing the test. Will add a default if not set.
          test_assessment : str
              Optional single word describing the assessment of the test.
              Will set a default if not set.
          test_number : int
              Optional test number to use. If not set will ues next
              available test number.
          flag_value : boolean
              Indicates that the tests are stored as integers
              not bit packed values in quality control variable.
          limit_attr_name : str
              Optional attribute name to store the limit_value under
              quality control ancillary variable.
          prepend_text : str
              Optional text to prepend to the test meaning.
              Example is indicate what institution added the test.
  
          Returns
          -------
          test_info : tuple
              A tuple containing test information including var_name, qc variable name,
              test_number, test_meaning, test_assessment
  
          """
          if limit_value is None:
              return
  
          if limit_attr_name is None:
              if test_assessment == 'Suspect' or test_assessment == 'Indeterminate':
                  attr_name = 'warn_min'
              else:
                  attr_name = 'fail_min'
          else:
              attr_name = limit_attr_name
  
          if test_meaning is None:
              test_meaning = ('Data value less than '
                              'or equal to {}.').format(attr_name)
  
          if prepend_text is not None:
              test_meaning = ': '.join((prepend_text, test_meaning))
  
          with warnings.catch_warnings():
              warnings.filterwarnings("ignore", category=RuntimeWarning)
              index = np.less_equal(self._obj[var_name].values, limit_value)
  
          result = self._obj.qcfilter.add_test(
              var_name, index=index,
              test_number=test_number,
              test_meaning=test_meaning,
              test_assessment=test_assessment,
              flag_value=flag_value)
  
          # Ensure limit_value attribute is matching data type
          limit_value = np.array(limit_value, dtype=self._obj[var_name].values.dtype.type)
  
          qc_var_name = result['qc_variable_name']
          self._obj[qc_var_name].attrs[attr_name] = limit_value
  
          return result
  
      def add_greater_equal_test(self, var_name, limit_value, test_meaning=None,
                                 test_assessment='Bad', test_number=None,
                                 flag_value=False, limit_attr_name=None,
                                 prepend_text=None):
          """
          Method to perform a greater than or equal to test
          (i.e. maximum value) and add result to ancillary quality control
          variable. If ancillary quality control variable does not exist it
          will be created.
  
          Parameters
          ----------
          var_name : str
              Data variable name.
          limit_value : int or float or None
              Limit value to use in test. The value will be written
              to the quality control variable as an attribute. If set
              to None will return without setttin test.
          test_meaning : str
              The optional text description to add to flag_meanings
              describing the test. Will add a default if not set.
          test_assessment : str
              Optional single word describing the assessment of the test.
              Will set a default if not set.
          test_number : int
              Optional test number to use. If not set will ues next
              available test number.
          flag_value : boolean
              Indicates that the tests are stored as integers
              not bit packed values in quality control variable.
          limit_attr_name : str
              Optional attribute name to store the limit_value under
              quality control ancillary variable.
          prepend_text : str
              Optional text to prepend to the test meaning.
              Example is indicate what institution added the test.
  
          Returns
          -------
          test_info : tuple
              A tuple containing test information including var_name, qc variable name,
              test_number, test_meaning, test_assessment
  
          """
          if limit_value is None:
              return
  
          if limit_attr_name is None:
              if test_assessment == 'Suspect' or test_assessment == 'Indeterminate':
                  attr_name = 'warn_max'
              else:
                  attr_name = 'fail_max'
          else:
              attr_name = limit_attr_name
  
          if test_meaning is None:
              test_meaning = ('Data value greater than '
                              'or equal to {}.').format(attr_name)
  
          if prepend_text is not None:
              test_meaning = ': '.join((prepend_text, test_meaning))
  
          with warnings.catch_warnings():
              warnings.filterwarnings("ignore", category=RuntimeWarning)
              index = np.greater_equal(self._obj[var_name].values, limit_value)
  
          result = self._obj.qcfilter.add_test(
              var_name, index=index,
              test_number=test_number,
              test_meaning=test_meaning,
              test_assessment=test_assessment,
              flag_value=flag_value)
  
          # Ensure limit_value attribute is matching data type
          limit_value = np.array(limit_value, dtype=self._obj[var_name].values.dtype.type)
  
          qc_var_name = result['qc_variable_name']
          self._obj[qc_var_name].attrs[attr_name] = limit_value
  
          return result
  
      def add_equal_to_test(self, var_name, limit_value, test_meaning=None,
                            test_assessment='Bad', test_number=None,
                            flag_value=False, limit_attr_name=None,
                            prepend_text=None):
          """
          Method to perform an equal test and add result to ancillary quality
          control variable. If ancillary quality control variable does not
          exist it will be created.
  
          Parameters
          ----------
          var_name : str
              Data variable name.
          limit_value : int or float or None
              Limit value to use in test. The value will be written
              to the quality control variable as an attribute. If set
              to None will return without setttin test.
          test_meaning : str
              The optional text description to add to flag_meanings
              describing the test. Will add a default if not set.
          test_assessment : str
              Optional single word describing the assessment of the test.
              Will set a default if not set.
          test_number : int
              Optional test number to use. If not set will ues next
              available test number.
          flag_value : boolean
              Indicates that the tests are stored as integers
              not bit packed values in quality control variable.
          limit_attr_name : str
              Optional attribute name to store the limit_value under
              quality control ancillary variable.
          prepend_text : str
              Optional text to prepend to the test meaning.
              Example is indicate what institution added the test.
  
          Returns
          -------
          test_info : tuple
              A tuple containing test information including var_name, qc variable name,
              test_number, test_meaning, test_assessment
  
          """
          if limit_value is None:
              return
  
          if limit_attr_name is None:
              if test_assessment == 'Suspect' or test_assessment == 'Indeterminate':
                  attr_name = 'warn_equal_to'
              else:
                  attr_name = 'fail_equal_to'
          else:
              attr_name = limit_attr_name
  
          if test_meaning is None:
              test_meaning = 'Data value equal to {}.'.format(attr_name)
  
          if prepend_text is not None:
              test_meaning = ': '.join((prepend_text, test_meaning))
  
          with warnings.catch_warnings():
              warnings.filterwarnings("ignore", category=RuntimeWarning)
              index = np.equal(self._obj[var_name].values, limit_value)
  
          result = self._obj.qcfilter.add_test(
              var_name, index=index,
              test_number=test_number,
              test_meaning=test_meaning,
              test_assessment=test_assessment,
              flag_value=flag_value)
  
          # Ensure limit_value attribute is matching data type
          limit_value = np.array(limit_value, dtype=self._obj[var_name].values.dtype.type)
  
          qc_var_name = result['qc_variable_name']
          self._obj[qc_var_name].attrs[attr_name] = limit_value
  
          return result
  
      def add_not_equal_to_test(self, var_name, limit_value, test_meaning=None,
                                test_assessment='Bad', test_number=None,
                                flag_value=False, limit_attr_name=None,
                                prepend_text=None):
          """
          Method to perform a not equal to test and add result to ancillary
          quality control variable. If ancillary quality control variable does
          not exist it will be created.
  
          Parameters
          ----------
          var_name : str
              Data variable name.
          limit_value : int or float or None
              Limit value to use in test. The value will be written
              to the quality control variable as an attribute. If set
              to None will return without setttin test.
          test_meaning : str
              The optional text description to add to flag_meanings
              describing the test. Will add a default if not set.
          test_assessment : str
              Optional single word describing the assessment of the test.
              Will set a default if not set.
          test_number : int
              Optional test number to use. If not set will ues next
              available test number.
          flag_value : boolean
              Indicates that the tests are stored as integers
              not bit packed values in quality control variable.
          limit_attr_name : str
              Optional attribute name to store the limit_value under
              quality control ancillary variable.
          prepend_text : str
              Optional text to prepend to the test meaning.
              Example is indicate what institution added the test.
  
          Returns
          -------
          test_info : tuple
              A tuple containing test information including var_name, qc variable name,
              test_number, test_meaning, test_assessment
  
          """
          if limit_value is None:
              return
  
          if limit_attr_name is None:
              if test_assessment == 'Suspect' or test_assessment == 'Indeterminate':
                  attr_name = 'warn_not_equal_to'
              else:
                  attr_name = 'fail_not_equal_to'
          else:
              attr_name = limit_attr_name
  
          if test_meaning is None:
              test_meaning = 'Data value not equal to {}.'.format(attr_name)
  
          if prepend_text is not None:
              test_meaning = ': '.join((prepend_text, test_meaning))
  
          with warnings.catch_warnings():
              warnings.filterwarnings("ignore", category=RuntimeWarning)
              index = np.not_equal(self._obj[var_name].values, limit_value)
  
          result = self._obj.qcfilter.add_test(
              var_name, index=index,
              test_number=test_number,
              test_meaning=test_meaning,
              test_assessment=test_assessment,
              flag_value=flag_value)
  
          # Ensure limit_value attribute is matching data type
          limit_value = np.array(limit_value, dtype=self._obj[var_name].values.dtype.type)
  
          qc_var_name = result['qc_variable_name']
          self._obj[qc_var_name].attrs[attr_name] = limit_value
  
          return result
  
      def add_outside_test(self, var_name, limit_value_lower, limit_value_upper,
                           test_meaning=None,
                           test_assessment='Bad', test_number=None,
                           flag_value=False, limit_attr_names=None,
                           prepend_text=None):
          """
          Method to perform a less than or greater than test
          (i.e. outide minimum and maximum value) and add
          result to ancillary quality control variable. If ancillary
          quality control variable does not exist it will be created.
  
          Parameters
          ----------
          var_name : str
              Data variable name.
          limit_value_lower : int or float
              Lower limit value to use in test. The value will be written
              to the quality control variable as an attribute.
          limit_value_upper : int or float
              Upper limit value to use in test. The value will be written
              to the quality control variable as an attribute.
          test_meaning : str
              The optional text description to add to flag_meanings
              describing the test. Will add a default if not set.
          test_assessment : str
              Optional single word describing the assessment of the test.
              Will set a default if not set.
          test_number : int
              Optional test number to use. If not set will ues next
              available test number.
          flag_value : boolean
              Indicates that the tests are stored as integers
              not bit packed values in quality control variable.
          limit_attr_names : list of str
              Optional attribute name to store the limit_value under
              quality control ancillary variable. First value is
              lower limit attribute name and second value is
              upper limit attribute name.
          prepend_text : str
              Optional text to prepend to the test meaning.
              Example is indicate what institution added the test.
  
          Returns
          -------
          test_info : tuple
              A tuple containing test information including var_name, qc variable name,
              test_number, test_meaning, test_assessment
  
          """
  
          if limit_attr_names is None:
              if test_assessment == 'Suspect' or test_assessment == 'Indeterminate':
                  attr_name_lower = 'warn_lower_range'
                  attr_name_upper = 'warn_upper_range'
              else:
                  attr_name_lower = 'fail_lower_range'
                  attr_name_upper = 'fail_upper_range'
          else:
              attr_name_lower = limit_attr_names[0]
              attr_name_upper = limit_attr_names[1]
  
          if test_meaning is None:
              test_meaning = ('Data value less than {} '
                              'or greater than {}.').format(attr_name_lower,
                                                            attr_name_upper)
  
          if prepend_text is not None:
              test_meaning = ': '.join((prepend_text, test_meaning))
  
          with warnings.catch_warnings():
              warnings.filterwarnings("ignore", category=RuntimeWarning)
              data = np.ma.masked_outside(self._obj[var_name].values,
                                          limit_value_lower, limit_value_upper)
          if data.mask.size == 1:
              data.mask = np.full(data.data.shape, data.mask, dtype=bool)
  
          index = data.mask
  
          result = self._obj.qcfilter.add_test(
              var_name, index=index,
              test_number=test_number,
              test_meaning=test_meaning,
              test_assessment=test_assessment,
              flag_value=flag_value)
  
          # Ensure limit_value attribute is matching data type
          limit_value_lower = np.array(limit_value_lower, dtype=self._obj[var_name].values.dtype.type)
          limit_value_upper = np.array(limit_value_upper, dtype=self._obj[var_name].values.dtype.type)
  
          qc_var_name = result['qc_variable_name']
          self._obj[qc_var_name].attrs[attr_name_lower] = limit_value_lower
          self._obj[qc_var_name].attrs[attr_name_upper] = limit_value_upper
  
          return result
  
      def add_inside_test(self, var_name, limit_value_lower, limit_value_upper,
                          test_meaning=None, test_assessment='Bad',
                          test_number=None, flag_value=False,
                          limit_attr_names=None,
                          prepend_text=None):
          """
          Method to perform a greater than or less than test
          (i.e. between minimum and maximum value) and add
          result to ancillary quality control variable. If ancillary
          quality control variable does not exist it will be created.
  
          Parameters
          ----------
          var_name : str
              Data variable name.
          limit_value_lower : int or float
              Lower limit value to use in test. The value will be written
              to the quality control variable as an attribute.
          limit_value_upper : int or float
              Upper limit value to use in test. The value will be written
              to the quality control variable as an attribute.
          test_meaning : str
              The optional text description to add to flag_meanings
              describing the test. Will add a default if not set.
          test_assessment : str
              Optional single word describing the assessment of the test.
              Will set a default if not set.
          test_number : int
              Optional test number to use. If not set will ues next
              available test number.
          flag_value : boolean
              Indicates that the tests are stored as integers
              not bit packed values in quality control variable.
          limit_attr_names : list of str
              Optional attribute name to store the limit_value under
              quality control ancillary variable. First value is
              lower limit attribute name and second value is
              upper limit attribute name.
          prepend_text : str
              Optional text to prepend to the test meaning.
              Example is indicate what institution added the test.
  
          Returns
          -------
          test_info : tuple
              A tuple containing test information including var_name, qc variable name,
              test_number, test_meaning, test_assessment
  
          """
  
          if limit_attr_names is None:
              if test_assessment == 'Suspect' or test_assessment == 'Indeterminate':
                  attr_name_lower = 'warn_lower_range_inner'
                  attr_name_upper = 'warn_upper_range_inner'
              else:
                  attr_name_lower = 'fail_lower_range_inner'
                  attr_name_upper = 'fail_upper_range_inner'
          else:
              attr_name_lower = limit_attr_names[0]
              attr_name_upper = limit_attr_names[1]
  
          if test_meaning is None:
              test_meaning = ('Data value greater than {} '
                              'or less than {}.').format(attr_name_lower,
                                                         attr_name_upper)
  
          if prepend_text is not None:
              test_meaning = ': '.join((prepend_text, test_meaning))
  
          with warnings.catch_warnings():
              warnings.filterwarnings("ignore", category=RuntimeWarning)
              data = np.ma.masked_inside(self._obj[var_name].values,
                                         limit_value_lower, limit_value_upper)
          if data.mask.size == 1:
              data.mask = np.full(data.data.shape, data.mask, dtype=bool)
  
          index = data.mask
  
          result = self._obj.qcfilter.add_test(
              var_name, index=index,
              test_number=test_number,
              test_meaning=test_meaning,
              test_assessment=test_assessment,
              flag_value=flag_value)
  
          # Ensure limit_value attribute is matching data type
          limit_value_lower = np.array(limit_value_lower, dtype=self._obj[var_name].values.dtype.type)
          limit_value_upper = np.array(limit_value_upper, dtype=self._obj[var_name].values.dtype.type)
  
          qc_var_name = result['qc_variable_name']
          self._obj[qc_var_name].attrs[attr_name_lower] = limit_value_lower
          self._obj[qc_var_name].attrs[attr_name_upper] = limit_value_upper
  
          return result
  
      def add_persistence_test(self, var_name, window=10, test_limit=0.0001,
                               min_periods=1, center=True, test_meaning=None,
                               test_assessment='Bad', test_number=None,
                               flag_value=False, prepend_text=None):
          """
          Method to perform a persistence test over 1-D data..
  
          Parameters
          ----------
          var_name : str
              Data variable name.
          window : int
              Optional number of data samples to use in the calculation of
              standard deviation to test for consistent data.
          test_limit : float
              Optional test limit to use where the standard deviation less
              than will trigger the test.
          min_periods : int
              Optional number of minimum values to use in the moving window.
              Setting to 1 so this correctly handles NaNs.
          center : boolean
              Optional where within the moving window to report the standard
              deviation values. Used in the .rolling.std() calculation with xarray.
          test_meaning : str
              The optional text description to add to flag_meanings
              describing the test. Will add a default if not set.
          test_assessment : str
              Optional single word describing the assessment of the test.
              Will set a default if not set.
          test_number : int
              Optional test number to use. If not set will ues next
              available test number.
          flag_value : boolean
              Indicates that the tests are stored as integers
              not bit packed values in quality control variable.
          prepend_text : str
              Optional text to prepend to the test meaning.
              Example is indicate what institution added the test.
  
          Returns
          -------
          test_info : tuple
              A tuple containing test information including var_name, qc variable name,
              test_number, test_meaning, test_assessment
  
          """
          data = self._obj[var_name]
          if window > data.size:
              window = data.size
  
          if test_meaning is None:
              test_meaning = ('Data failing persistence test. '
                              'Standard Deviation over a window of {} values '
                              'less than {}.').format(window, test_limit)
  
          if prepend_text is not None:
              test_meaning = ': '.join((prepend_text, test_meaning))
  
          with warnings.catch_warnings():
              warnings.filterwarnings("ignore", category=RuntimeWarning)
              stddev = data.rolling(time=window, min_periods=min_periods, center=True).std()
              index = stddev < test_limit
  
          result = self._obj.qcfilter.add_test(
              var_name, index=index,
              test_number=test_number,
              test_meaning=test_meaning,
              test_assessment=test_assessment,
              flag_value=flag_value)
  
          return result
  
      def add_difference_test(self, var_name, dataset2_dict=None, ds2_var_name=None,
                              diff_limit=None, tolerance="1m",
                              set_test_regardless=True,
                              apply_assessment_to_dataset2=None,
                              apply_tests_to_dataset2=None,
                              test_meaning=None, test_assessment='Bad',
                              test_number=None, flag_value=False,
                              prepend_text=None):
          """
          Method to perform a comparison test on time series data. Tested on 1-D
          data only. Will check if units and long_name indicate a direction and
          compensate for 0 to 360 degree transition.
  
          Parameters
          ----------
          var_name : str
              Data variable name.
          dataset2_dict : dict
              Dictionary with key equal to datastream name and value
              equal to xarray dataset containging variable to compare. If no provided
              will assume second dataset is the same as self dataset.
          ds2_var_name : str
              Comparison dataset variable name to compare.
          diff_limit : int or float
              Difference limit for comparison.
          apply_assessment_to_dataset2 : str or list of str
              Option to filter comparison dataset variable using corresponsing
              quality control variable using assessments. Example would be
              ['Bad'], where all quality control data with assessment Bad will
              not be used in this test.
          apply_tests_to_dataset2 : int or list of int
              Option to filter comparison dataset variable using corresponding
              quality control variable using test numbers. Example would be
              [2,4], where all quality control data with test numbers 2 or 4 set
              will not be used in this test.
          tolerance : str
              Optional text indicating the time tolerance for aligning two
              DataArrays.
          set_test_regardless : boolean
              Option to set test description even if no data in comparison data
              set.
          test_meaning : str
              Optional text description to add to flag_meanings
              describing the test. Will use a default if not set.
          test_assessment : str
              Optional single word describing the assessment of the test.
              Will use a default if not set.
          test_number : int
              Optional test number to use. If not set will use next available
              test number.
          flag_value : boolean
              Indicates that the tests are stored as integers
              not bit packed values in quality control variable.
          prepend_text : str
              Optional text to prepend to the test meaning.
              Example is indicate what institution added the test.
  
          Returns
          -------
          test_info : tuple
              A tuple containing test information including var_name, qc variable name,
              test_number, test_meaning, test_assessment
  
          """
          if dataset2_dict is None:
              dataset2_dict = {'second_dataset': self._obj}
  
          if not isinstance(dataset2_dict, dict):
              raise ValueError('You did not provide a dictionary containing the '
                               'datastream name as the key and xarray dataset as '
                               'the value for dataset2_dict for add_difference_test().')
  
          if diff_limit is None:
              raise ValueError('You did not provide a test limit for add_difference_test().')
  
          datastream2 = list(dataset2_dict.keys())[0]
          dataset2 = dataset2_dict[datastream2]
  
          if set_test_regardless is False and type(dataset2) != xr.core.dataset.Dataset:
              return
  
          if test_meaning is None:
              if dataset2 is self._obj:
                  var_name2 = f'{ds2_var_name}'
              else:
                  var_name2 = f'{datastream2}:{ds2_var_name}'
  
              test_meaning = (f'Difference between {var_name} and {var_name2} '
                              f'greater than {diff_limit} {self._obj[var_name].attrs["units"]}')
  
          if prepend_text is not None:
              test_meaning = ': '.join((prepend_text, test_meaning))
  
          if tolerance is not None:
              tolerance = pd.Timedelta(tolerance)
  
          index = []
          if type(dataset2) == xr.core.dataset.Dataset:
              if apply_assessment_to_dataset2 is not None or apply_tests_to_dataset2 is not None:
                  dataset2[ds2_var_name].values = dataset2.qcfilter.get_masked_data(
                      ds2_var_name, rm_assessments=apply_assessment_to_dataset2,
                      rm_tests=apply_tests_to_dataset2, return_nan_array=True)
  
              df_a = pd.DataFrame({'time': self._obj['time'].values,
                                   var_name: self._obj[var_name].values})
              data_b = convert_units(dataset2[ds2_var_name].values,
                                     dataset2[ds2_var_name].attrs['units'],
                                     self._obj[var_name].attrs['units'])
              ds2_var_name = ds2_var_name + '_newname'
              df_b = pd.DataFrame({'time': dataset2['time'].values,
                                   ds2_var_name: data_b})
  
              if tolerance is not None:
                  tolerance = pd.Timedelta(tolerance)
  
              pd_c = pd.merge_asof(df_a, df_b, on='time', tolerance=tolerance,
                                   direction="nearest")
  
              with warnings.catch_warnings():
                  warnings.filterwarnings("ignore", category=RuntimeWarning)
                  # Check if variable is for wind direction comparisons. Fix
                  # for 0 - 360 degrees transition. This is done by adding 360 degrees to
                  # all wind values and using modulus to get the minimum difference number.
                  # This is done for both a-b and b-a and then choosing the minimum number
                  # to compensate for large differences.
                  wdir_units = ['deg', 'degree', 'degrees', 'degs']
                  if (self._obj[var_name].attrs['units'] in wdir_units and
                          'direction' in self._obj[var_name].attrs['long_name'].lower()):
                      diff1 = np.mod(np.absolute((pd_c[var_name] + 360.) -
                                     (pd_c[ds2_var_name] + 360.)), 360)
                      diff2 = np.mod(np.absolute((pd_c[ds2_var_name] + 360.) -
                                     (pd_c[var_name] + 360.)), 360)
                      diff = np.array([diff1, diff2])
                      diff = np.nanmin(diff, axis=0)
  
                  else:
                      diff = np.absolute(pd_c[var_name] - pd_c[ds2_var_name])
  
                  index = diff > diff_limit
  
          result = self._obj.qcfilter.add_test(
              var_name, index=index,
              test_number=test_number,
              test_meaning=test_meaning,
              test_assessment=test_assessment,
              flag_value=flag_value)
  
          return result
  
      def add_delta_test(self, var_name, diff_limit=1, test_meaning=None,
                         limit_attr_name=None,
                         test_assessment='Indeterminate', test_number=None,
                         flag_value=False, prepend_text=None):
          """
          Method to perform a difference test on adjacent values in time series.
          Will flag both values where a difference is greater
          than or equal to the difference limit. Tested with 1-D data only. Not
          sure what will happen with higher dimentioned data.
  
          Parameters
          ----------
          var_name : str
              Data variable name.
          diff_limit : int or float
              Difference limit
          test_meaning : str
              Optional text description to add to flag_meanings
              describing the test. Will use a default if not set.
          limit_attr_name : str
              Optional attribute name to store the limit_value under
              quality control ancillary variable.
          test_assessment : str
              Optional single word describing the assessment of the test.
              Will use a default if not set.
          test_number : int
              Optional test number to use. If not set will use next available
              test number.
          flag_value : boolean
              Indicates that the tests are stored as integers
              not bit packed values in quality control variable.
          prepend_text : str
              Optional text to prepend to the test meaning.
              Example is indicate what institution added the test.
  
          Returns
          -------
          test_info : tuple
              A tuple containing test information including var_name, qc variable name,
              test_number, test_meaning, test_assessment
  
          """
  
          if limit_attr_name is None:
              if test_assessment == 'Suspect' or test_assessment == 'Indeterminate':
                  attr_name = 'warn_delta'
              else:
                  attr_name = 'fail_delta'
          else:
              attr_name = limit_attr_name
  
          if test_meaning is None:
              test_meaning = f'Difference between current and previous values exceeds {attr_name}.'
  
          if prepend_text is not None:
              test_meaning = ': '.join((prepend_text, test_meaning))
  
          with warnings.catch_warnings():
              warnings.filterwarnings("ignore", category=RuntimeWarning)
              # Check if variable is for wind direction comparisons by units. Fix
              # for 0 - 360 degrees transition. This is done by adding 360 degrees to
              # all wind values and using modulus to get the minimum difference number.
              wdir_units = ['deg', 'degree', 'degrees', 'degs']
              if (self._obj[var_name].attrs['units'] in wdir_units and
                      'direction' in self._obj[var_name].attrs['long_name'].lower()):
                  abs_diff = np.mod(np.abs(np.diff(self._obj[var_name].values)), 360)
              else:
                  abs_diff = np.abs(np.diff(self._obj[var_name].values))
  
              index = np.where(abs_diff >= diff_limit)[0]
              if index.size > 0:
                  index = np.append(index, index + 1)
                  index = np.unique(index)
  
          result = self._obj.qcfilter.add_test(var_name, index=index,
                                               test_number=test_number,
                                               test_meaning=test_meaning,
                                               test_assessment=test_assessment,
                                               flag_value=flag_value)
  
          # Ensure min value attribute is matching data type
          diff_limit = np.array(diff_limit, dtype=self._obj[var_name].values.dtype.type)
  
          qc_var_name = result['qc_variable_name']
          self._obj[qc_var_name].attrs[attr_name] = diff_limit
  
          return result
  
apis: numpy.diff numpy.less numpy.greater_equal numpy.append numpy.ma.masked_outside pandas.merge_asof numpy.absolute numpy.isnan numpy.ma.masked_inside numpy.where numpy.unique numpy.equal numpy.greater pandas.Timedelta numpy.not_equal pandas.DataFrame numpy.nanmin numpy.less_equal numpy.array numpy.full