예제 #1
0
 def __init__(self):
     #: outputs initial value
     self.initial_value = {}
     #: size of outputs
     self.size = {}
     #: outputs uncertainty
     self.uncertainty = {}
     #: variance
     self.variance = {}
     #: jacobian
     self.jacobian = {}
     #: outputs isconstant flag
     self.isconstant = {}
     #: outputs isproperty flag
     self.isproperty = {}
     #: name of corresponding time series, ``None`` if no time series
     self.timeseries = {}
     #: name of :class:`Output` superclass
     self.output_source = {}
     #: calculation outputs
     self.outputs = {}
     for k, v in self.parameters.iteritems():
         self.initial_value[k] = v.get('init')  # returns None if missing
         self.size[k] = v.get('size') or 1  # minimum size is 1
         self.uncertainty[k] = None  # uncertainty for outputs is calculated
         self.isconstant[k] = v.get('isconstant', False)  # True or False
         self.isproperty[k] = v.get('isproperty', False)  # True or False
         units = str(v.get('units', ''))  # default is non-dimensional
         # NOTE: np.empty is faster than zeros!
         self.outputs[k] = Q_(np.zeros((1, self.size[k])), UREG(units))
         # NOTE: Initial values are assigned and outputs resized when
         # simulation "start" method is called from the model.
         self.timeseries[k] = v.get('timeseries')  # None if not time series
         self.output_source[k] = self.__class__.__name__  # output source
예제 #2
0
    def apply_units_to_cache(self, data):
        """
        Apply units to data read using :class:`JSONReader`.

        :param data: cached data
        :return: data with units applied
        :rtype: :class:`~pint.unit.Quantity`
        """
        for k, val in self.parameters.iteritems():
            if 'units' in val:
                data[k] = Q_(data[k], val.get('units'))
        return data
예제 #3
0
def test_pv_context():
    """
    Test Pint PV context - specifically suns to power flux and v.v.
    """
    esun = Q_(876.5, UREG.W / UREG.m / UREG.m)
    eq_(esun.to('suns', 'pv'), 0.8765 * UREG.suns)
    esun = Q_(0.8765, UREG.suns)
    ok_(esun.dimensionless)
    eq_(esun.to('W / m ** 2', 'pv'), 876.5 * UREG.W / UREG.m / UREG.m)
예제 #4
0
    def apply_units_to_cache(self, data):
        """
        Applies units to data when a proxy reader is used. For example if the
        data is cached as JSON and retrieved using the
        :class:`~carousel.core.data_readers.JSONReader`, then units can be
        applied from the original parameter schema.

        :param data: Data read by proxy reader.
        :return: data with units applied
        """
        # if units key exists then apply
        for k, v in self.parameters.iteritems():
            if v and v.get('units'):
                data[k] = Q_(data[k], v.get('units'))
        return data
예제 #5
0
    def calculate(self, calc, formula_reg, data_reg, out_reg,
                  timestep=None, idx=None):
        """
        Calculate looping over specified repeat arguments.

        :param calc: Calculation to loop over.
        :param formula_reg: Formula registry
        :param data_reg: Data registry
        :param out_reg: Outputs registry
        :param timestep: timestep used for dynamic calcs
        :param idx: index used in dynamic calcs
        """
        # the superclass Calculator.calculate() method
        base_calculator = super(LazyLoopingCalculator, self).calculate
        # call base calculator and return if there are no repeat args
        if not self.repeat_args:
            base_calculator(calc, formula_reg, data_reg, out_reg, timestep, idx)
            return
        # make dictionaries of the calculation data and outputs argument maps
        # this maps what the formulas and registries call the repeats arguments
        data_rargs, out_rargs = {}, {}  # allocate dictionaries for repeat args
        calc_data = calc['args'].get('data')
        calc_outs = calc['args'].get('outputs')
        # get dictionaries of repeat args from calculation data and outputs
        for rarg in self.repeat_args:
            # rarg could be either data or output so try both
            try:
                data_rargs[rarg] = calc_data[rarg]
            except (KeyError, TypeError):
                out_rargs[rarg] = calc_outs[rarg]
        # get values of repeat data and outputs from registries
        rargs = dict(index_registry(data_rargs, data_reg, timestep, idx),
                     **index_registry(out_rargs, out_reg, timestep, idx))
        rargkeys, rargvals = zip(*rargs.iteritems())  # split keys and values
        rargvals = zip(*rargvals)  # reshuffle values, should be same size?
        # allocate dictionary of empty numpy arrays for each return value
        returns = calc['returns']  # return keys
        retvals = {rv: [] for rv in returns}  # empty dictionary of return vals
        retvalu = {rv: None for rv in returns}  # dictionary of return units
        ret_var = {rv: {rv: [] for rv in returns}
                   for rv in returns}  # variances
        ret_unc = {rv: {rv: [] for rv in returns}
                   for rv in returns}  # uncertainty
        ret_jac = dict.fromkeys(returns)  # jacobian
        # get calc data and outputs keys to copy from registries
        try:
            calc_data_keys = calc_data.values()
        except (AttributeError, TypeError):
            calc_data_keys = []  # if there are no data, leave it empty
        try:
            calc_outs_keys = calc_outs.values()
        except (AttributeError, TypeError):
            calc_outs_keys = []  # if there are no outputs, leave it empty
        # copy returns and this calculations output arguments from output reg
        data_reg_copy = reg_copy(data_reg, calc_data_keys)
        out_reg_copy = reg_copy(out_reg, returns + calc_outs_keys)
        # loop over first repeat arg values and enumerate numpy indices as n
        for vals in rargvals:
            rargs_keys = dict(zip(rargkeys, vals))
            # this is the magic or garbage depending on how you look at it,
            # change the registry copies to only contain the values for this
            # iteration of the repeats
            # TODO: instead of using copies rewrite index_registry to do this
            # copies means that calculations can't use a registry backend that
            # uses shared memory, which will limit ability to run asynchronously
            for k, v in data_rargs.iteritems():
                data_reg_copy[v] = rargs_keys[k]
            for k, v in out_rargs.iteritems():
                out_reg_copy[v] = rargs_keys[k]
            # run base calculator to get retvals, var, unc and jac
            base_calculator(calc, formula_reg, data_reg_copy, out_reg_copy,
                            timestep, idx)
            # re-assign retvals for this index of repeats
            for rv, rval in retvals.iteritems():
                rval.append(out_reg_copy[rv].m)  # append magnitude to returns
                retvalu[rv] = out_reg_copy[rv].u  # save units for this repeat
                # re-assign variance for this index of repeats
                if out_reg_copy.variance.get(rv) is None:
                    continue
                for rv2, rval2 in ret_var.iteritems():
                    rval2[rv].append(out_reg_copy.variance[rv2][rv])
                    # uncertainty only on diagonal of variance
                    if rv == rv2:
                        ret_unc[rv][rv2].append(out_reg_copy.uncertainty[rv][rv2])
                    else:
                        # FIXME: inefficient to get length every iteration!
                        unc_size = len(out_reg_copy.uncertainty[rv][rv])
                        ret_unc[rv][rv2].append(Q_([0.]*unc_size, 'percent'))
                # jacobian is dictionary of returns versus arguments
                if ret_jac[rv] is None:
                    # first time through create dictionary of sensitivities
                    ret_jac[rv] = {o: v for o, v in
                                   out_reg_copy.jacobian[rv].iteritems()}
                else:
                    # next time through, vstack the sensitivities to existing
                    for o, v in out_reg_copy.jacobian[rv].iteritems():
                        ret_jac[rv][o] = np.vstack((ret_jac[rv][o], v))
        LOGGER.debug('ret_jac:\n%r', ret_jac)
        # TODO: handle jacobian for repeat args and for dynamic simulations
        # apply units if they were
        for k in retvals:
            if retvalu[k] is not None:
                if retvalu[k] == out_reg[k].u:
                    retvals[k] = Q_(retvals[k], retvalu[k])
                else:
                    retvals[k] = Q_(retvals[k], retvalu[k]).to(out_reg[k].u)
        # put return values into output registry
        if idx is None:
            out_reg.update(retvals)
            out_reg.variance.update(ret_var)
            out_reg.uncertainty.update(ret_unc)
            out_reg.jacobian.update(ret_jac)
        else:
            for k, v in retvals:
                out_reg[k][idx] = v