def test_lazy_loop_calculator_cls():
    """Test the lazy loop calculator class."""
    calc = {'formula': 'pythagorian_thm',
            'args': {'data': {'adjacent': 'a', 'opposite': 'b'}, 'outputs': {}},
            'returns': ['c']}
    formula_reg = FormulaRegistry()
    formula_reg.register(
        {'pythagorian_thm': UREG.wraps(*PYTHAGOREAN_UNITS)(f_pythagorian_thm)},
        args={'pythagorian_thm': ['adjacent', 'opposite']},
        units={'pythagorian_thm': PYTHAGOREAN_UNITS},
        isconstant={'pythagorian_thm': None}
    )
    data_reg = DataRegistry()
    data_reg.register(
        {'a': [3., 5., 7., 9., 11.] * UREG('cm'),
         'b': [4., 12., 24., 40., 60.] * UREG('cm')},
        uncertainty=None,
        variance=None,
        isconstant={'a': True, 'b': True}
    )
    out_reg = OutputRegistry()
    out_reg.register({'c': np.zeros(5) * UREG.m})
    # repeat args are listed as formula names, not data reg names!
    calculator = LazyLoopingCalculator(repeat_args=['adjacent', 'opposite'])
    calculator.calculate(calc, formula_reg, data_reg, out_reg)
    assert np.allclose(out_reg['c'].m, PYTHAGOREAN_TRIPLES)  # check magnitudes
    assert out_reg['c'].u == UREG.m  # output units are meters
    return out_reg
Example #2
0
    def __init__(self):
        # check for path listed in param file
        path = getattr(self._meta, 'path', None)
        if path is None:
            proxy_file = self.param_file if self.param_file else __file__
            # use the same path as the param file or this file if no param file
            self._meta.path = os.path.dirname(proxy_file)

        # check for path listed in param file
        formula_importer = getattr(self._meta, 'formula_importer', None)
        if formula_importer is None:
            #: formula importer class, default is ``PyModuleImporter``
            self._meta.formula_importer = PyModuleImporter

        meta = getattr(self, '_meta', None)  # options for formulas
        importer_instance = self._meta.formula_importer(self.parameters, meta)
        #: formulas loaded by the importer using specified parameters
        self.formulas = importer_instance.import_formulas()
        #: linearity determined by each data source?
        self.islinear = {}
        #: positional arguments
        self.args = {}
        #: expected units of returns and arguments as pair of tuples
        self.units = {}
        #: constant arguments that are not included in covariance calculation
        self.isconstant = {}
        # sequence of formulas, don't propagate uncertainty or units
        for f in self.formulas:
            self.islinear[f] = True
            self.args[f] = inspect.getargspec(self.formulas[f]).args
        formula_param = self.parameters  # formulas key
        # if formulas is a list or if it can't be iterated as a dictionary
        # then log warning and return
        try:
            formula_param_generator = formula_param.iteritems()
        except AttributeError as err:
            LOGGER.warning('Attribute Error: %s', err.message)
            return
        # formula dictionary
        for k, v in formula_param_generator:
            if not v:
                # skip formula if attributes are null or empty
                continue
            # get islinear formula attribute
            is_linear = v.get('islinear')
            if is_linear is not None:
                self.islinear[k] = is_linear
            # get positional arguments
            f_args = v.get('args')
            if f_args is not None:
                self.args[k] = f_args
            # get constant arguments to exclude from covariance
            self.isconstant[k] = v.get('isconstant')
            if self.isconstant[k] is not None:
                argn = [
                    n for n, a in enumerate(self.args[k])
                    if a not in self.isconstant[k]
                ]
                LOGGER.debug('%s arg nums: %r', k, argn)
                self.formulas[k] = unc_wrapper_args(*argn)(self.formulas[k])
            # get units of returns and arguments
            self.units[k] = v.get('units')
            if self.units[k] is not None:
                # append units for covariance and Jacobian if all args
                # constant and more than one return output
                if self.isconstant[k] is not None:
                    # check if retval units is a string or None before adding
                    # extra units for Jacobian and covariance
                    ret_units = self.units[k][0]
                    if isinstance(ret_units, basestring) or ret_units is None:
                        self.units[k][0] = [ret_units]
                    try:
                        self.units[k][0] += [None, None]
                    except TypeError:
                        self.units[k][0] += (None, None)
                # wrap function with Pint's unit wrapper
                self.formulas[k] = UREG.wraps(*self.units[k])(self.formulas[k])