diff --git a/src/ValuedParamHandler.py b/src/ValuedParamHandler.py index 1e30aa63..bac154d0 100644 --- a/src/ValuedParamHandler.py +++ b/src/ValuedParamHandler.py @@ -26,32 +26,7 @@ class ValuedParamHandler(MessageUser): with a variety of sources (fixed values, parametric values, data histories, function evaluations, etc). """ - @classmethod - def get_input_specs(cls, name, descr=""): - """ - Template for parameters that can take a scalar, an ARMA history, or a function - @ In, name, string, name for spec (tag) - @ In, descr, string, base description for item (this will add to it) - @ Out, spec, InputData, value-based spec - """ - spec = InputData.parameterInputFactory(name, - descr=descr + r"""This value can be taken from any \emph{one} of the sources described below.""") - # VP sources - for vp_type in VPFactory.knownTypes(): - spec.addSub(vp_type.get_input_specs()) - # addons - spec.addSub(InputData.parameterInputFactory('multiplier', contentType=InputTypes.FloatType, - descr=r"""Multiplies any value obtained by this parameter by the given value. \default{1}""")) - # for when the result obtained needs to grow from year to year - # TODO - # growth = InputData.parameterInputFactory('growth', contentType=InputTypes.FloatType, - # descr=r"""if this node is given, the value will be adjusted from cycle to cycle by the provided amount.""") - # growth_mode = InputTypes.makeEnumType('growthType', 'growthType', ['linear', 'exponential']) - # growth.addParam('mode', param_type=growth_mode, required=True, - # descr=r"""determines whether the growth factor should be taken as linear or exponential (compounding).""") - # spec.addSub(growth) - return spec - + # NOTE: the inputSpec is defined in the ValuedParams Factory module. def __init__(self, name): """ Constructor. @@ -59,11 +34,12 @@ def __init__(self, name): @ Out, None """ super().__init__() - self.name = name # member whom this ValuedParam provides values, e.g. Component.economics.alpha - self._vp = None # ValuedParam instance - self._multiplier = None # scalar multiplier for evaluation values - self._growth_val = None # used to grow the value year-by-year - self._growth_mode = None # mode for growth (e.g. exponenetial, linear) + self.name = name # member whom this ValuedParam provides values, e.g. Component.economics.alpha + self._vp = None # ValuedParam instance + self._multiplier = None # scalar multiplier for evaluation values + self._growth_val = None # used to grow the value year-by-year + self._growth_mode = None # mode for growth (e.g. exponenetial, linear) + self._custom_input = None # additional info from input to pass through def __repr__(self): """ @@ -116,6 +92,8 @@ def read(self, comp_name: str, spec: InputData.ParameterInput, mode: str, alias_ # elif sub.getName() == 'growth': # self._growth_val = sub.value # self._growth_mode = sub.parameterValues['mode'] + elif sub.getName() == 'AdditionalInfo': + self._custom_input = sub.additionalInput if not found: self.raiseAnError(IOError, f'Component "{comp_name}" node <{spec.getName()}> expected a ValuedParam ' + f'to define its value source, but none was found! Options include: {knownVPs}') @@ -203,14 +181,14 @@ def set_object(self, obj): """ self._vp.set_object(obj) - def evaluate(self, *args, util_factor=False, **kwargs): + def evaluate(self, *args, **kwargs): """ Evaluate the ValuedParam, wherever it gets its data from @ In, args, list, positional arguments for ValuedParam @ In, kwargs, dict, keyword arguements for ValuedParam @ Out, evaluate, object, stuff from ValuedParam evaluation """ - data, meta = self._vp.evaluate(*args, **kwargs) + data, meta = self._vp.evaluate(*args, custom_input=self._custom_input, **kwargs) if self._multiplier is not None: for key in data: data[key] *= self._multiplier diff --git a/src/ValuedParams/Activity.py b/src/ValuedParams/Activity.py index 2a432e34..54a653a3 100644 --- a/src/ValuedParams/Activity.py +++ b/src/ValuedParams/Activity.py @@ -86,12 +86,13 @@ def crosscheck(self, interaction): 'was not found among this Component\'s input/output resources; options are:' + f'{", ".join(str_avail)}') - def evaluate(self, inputs, target_var=None, aliases=None): + def evaluate(self, inputs, target_var=None, aliases=None, custom_input=None): """ Evaluate this ValuedParam, wherever it gets its data from @ In, inputs, dict, stuff from RAVEN, particularly including the keys 'meta' and 'raven_vars' @ In, target_var, str, optional, requested outgoing variable name if not None @ In, aliases, dict, optional, alternate variable names for searching in variables + @ In, custom_input, list, optional, additional input nodes from user input @ Out, value, dict, dictionary of resulting evaluation as {vars: vals} @ Out, meta, dict, dictionary of meta (possibly changed during evaluation) """ diff --git a/src/ValuedParams/Factory.py b/src/ValuedParams/Factory.py index d758d51c..4dbd2122 100644 --- a/src/ValuedParams/Factory.py +++ b/src/ValuedParams/Factory.py @@ -51,7 +51,7 @@ def make_input_specs(self, name, descr=None, allowed=None, kind='singular'): for typ, klass in self._registeredTypes.items(): if typ in allowed: spec.addSub(klass.get_input_specs()) - # addons + # addons spec.addSub( InputData.parameterInputFactory( 'multiplier', @@ -59,6 +59,17 @@ def make_input_specs(self, name, descr=None, allowed=None, kind='singular'): descr=r"""Multiplies any value obtained by this parameter by the given value. \default{1}""" ) ) + addl_spec = InputData.parameterInputFactory( + 'AdditionalInfo', + descr=r"""Additional arbitrary input information. For custom-defined parameters, such as \xmlNode{Function}, + the additional information will be passed as part of the `texttt{meta[``HERON''][``custom_input'']} + passed to the user-supplied custom evaluation definition. + In the case of the \xmlNode{Function}, this is passed to the method in the Python module indicated by + the user, and will be unique for each use of the \xmlNode{Function} in the HERON input. Note that + the custom input nodes are not checked in any way by the input parsing.""" + ) + addl_spec.setStrictMode(False) + spec.addSub(addl_spec) return spec factory = ValuedParamFactory('ValuedParam') diff --git a/src/ValuedParams/Function.py b/src/ValuedParams/Function.py index 58bc765e..f65fef18 100644 --- a/src/ValuedParams/Function.py +++ b/src/ValuedParams/Function.py @@ -53,17 +53,20 @@ def read(self, comp_name, spec, mode, alias_dict=None): self._method_name = spec.parameterValues['method'] return [self._method_name] - def evaluate(self, inputs, target_var=None, aliases=None): + def evaluate(self, inputs, target_var=None, aliases=None, custom_input=None): """ Evaluate this ValuedParam, wherever it gets its data from @ In, inputs, dict, stuff from RAVEN, particularly including the keys 'meta' and 'raven_vars' @ In, target_var, str, optional, requested outgoing variable name if not None @ In, aliases, dict, optional, alternate variable names for searching in variables + @ In, custom_input, list, optional, additional input nodes from user input @ Out, data, dict, dictionary of resulting evaluation as {vars: vals} @ Out, meta, dict, dictionary of meta (possibly changed during evaluation) """ if aliases is None: aliases = {} + if custom_input is not None: + inputs['HERON']['custom_input'] = custom_input # TODO how to handle aliases for functions? # the "request" is what we're asking for from the function, the first argument given. # -> note it can be None if the function is not a transfer-type function diff --git a/src/ValuedParams/Parametric.py b/src/ValuedParams/Parametric.py index 6b1c6e0a..57e9e124 100644 --- a/src/ValuedParams/Parametric.py +++ b/src/ValuedParams/Parametric.py @@ -76,12 +76,13 @@ def set_value(self, value): """ self._parametric = value - def evaluate(self, inputs, target_var=None, aliases=None): + def evaluate(self, inputs, target_var=None, aliases=None, custom_input=None): """ Evaluate this ValuedParam, wherever it gets its data from @ In, inputs, dict, stuff from RAVEN, particularly including the keys 'meta' and 'raven_vars' @ In, target_var, str, optional, requested outgoing variable name if not None @ In, aliases, dict, optional, alternate variable names for searching in variables + @ In, custom_input, list, optional, additional input nodes from user input @ Out, value, dict, dictionary of resulting evaluation as {vars: vals} @ Out, meta, dict, dictionary of meta (possibly changed during evaluation) """ diff --git a/src/ValuedParams/ROM.py b/src/ValuedParams/ROM.py index 829c7819..fd11001e 100644 --- a/src/ValuedParams/ROM.py +++ b/src/ValuedParams/ROM.py @@ -98,12 +98,13 @@ def make_sub_vp(self, name, comp, spec, mode): self._inputs[name] = {'vp': vp, 'signals': [signal]} return signal - def evaluate(self, inputs, target_var=None, aliases=None): + def evaluate(self, inputs, target_var=None, aliases=None, custom_input=None): """ Evaluate this ValuedParam, wherever it gets its data from @ In, inputs, dict, run information from RAVEN, including meta and other run info @ In, target_var, str, optional, requested outgoing variable name if not None @ In, aliases, dict, optional, alternate variable names for searching in variables + @ In, custom_input, list, optional, additional input nodes from user input @ Out, value, dict, dictionary of resulting evaluation as {vars: vals} @ Out, inputs, dict, possibly-modified dictionary of run information """ diff --git a/src/ValuedParams/RandomVariable.py b/src/ValuedParams/RandomVariable.py index 5cdca0b5..b5b7135a 100644 --- a/src/ValuedParams/RandomVariable.py +++ b/src/ValuedParams/RandomVariable.py @@ -80,12 +80,13 @@ def read(self, comp_name, spec, mode, alias_dict=None): self._distribution = self.convert_spec_to_xml(sub_distribution) return [] - def evaluate(self, inputs, target_var=None, aliases=None): + def evaluate(self, inputs, target_var=None, aliases=None, custom_input=None): """ Evaluate this ValuedParam, wherever it gets its data from @ In, inputs, dict, stuff from RAVEN, particularly including the keys 'meta' and 'raven_vars' @ In, target_var, str, optional, requested outgoing variable name if not None @ In, aliases, dict, optional, alternate variable names for searching in variables + @ In, custom_input, list, optional, additional input nodes from user input @ Out, value, dict, dictionary of resulting evaluation as {vars: vals} @ Out, meta, dict, dictionary of meta (possibly changed during evaluation) """ diff --git a/src/ValuedParams/StaticHistory.py b/src/ValuedParams/StaticHistory.py index 0943d0b3..6dd10ec6 100644 --- a/src/ValuedParams/StaticHistory.py +++ b/src/ValuedParams/StaticHistory.py @@ -61,12 +61,13 @@ def read(self, comp_name, spec, mode, alias_dict=None): self._var_name = spec.parameterValues['variable'] return [self._var_name] - def evaluate(self, inputs, target_var=None, aliases=None): + def evaluate(self, inputs, target_var=None, aliases=None, custom_input=None): """ Evaluate this ValuedParam, wherever it gets its data from @ In, inputs, dict, stuff from RAVEN, particularly including the keys 'meta' and 'raven_vars' @ In, target_var, str, optional, requested outgoing variable name if not None @ In, aliases, dict, optional, alternate variable names for searching in variables + @ In, custom_input, list, optional, additional input nodes from user input @ Out, value, dict, dictionary of resulting evaluation as {vars: vals} @ Out, meta, dict, dictionary of meta (possibly changed during evaluation) """ diff --git a/src/ValuedParams/SyntheticHistory.py b/src/ValuedParams/SyntheticHistory.py index 57af31ac..df52ad5d 100644 --- a/src/ValuedParams/SyntheticHistory.py +++ b/src/ValuedParams/SyntheticHistory.py @@ -59,12 +59,13 @@ def read(self, comp_name, spec, mode, alias_dict=None): self._var_name = spec.parameterValues['variable'] return [self._var_name] - def evaluate(self, inputs, target_var=None, aliases=None): + def evaluate(self, inputs, target_var=None, aliases=None, custom_input=None): """ Evaluate this ValuedParam, wherever it gets its data from @ In, inputs, dict, stuff from RAVEN, particularly including the keys 'meta' and 'raven_vars' @ In, target_var, str, optional, requested outgoing variable name if not None @ In, aliases, dict, optional, alternate variable names for searching in variables + @ In, custom_input, list, optional, additional input nodes from user input @ Out, value, dict, dictionary of resulting evaluation as {vars: vals} @ Out, meta, dict, dictionary of meta (possibly changed during evaluation) """ diff --git a/src/ValuedParams/ValuedParam.py b/src/ValuedParams/ValuedParam.py index 051f6c93..6cc86af2 100644 --- a/src/ValuedParams/ValuedParam.py +++ b/src/ValuedParams/ValuedParam.py @@ -106,12 +106,13 @@ def set_object(self, obj): """ self._target_obj = obj - def evaluate(self, inputs, target_var=None, aliases=None): + def evaluate(self, inputs, target_var=None, aliases=None, custom_input=None): """ Evaluate this ValuedParam, wherever it gets its data from @ In, inputs, dict, stuff from RAVEN, particularly including the keys 'meta' and 'raven_vars' @ In, target_var, str, optional, requested outgoing variable name if not None @ In, aliases, dict, optional, alternate variable names for searching in variables + @ In, custom_input, list, optional, additional custom inputs @ Out, value, dict, dictionary of resulting evaluation as {vars: vals} @ Out, meta, dict, dictionary of meta (possibly changed during evaluation) """ diff --git a/src/ValuedParams/Variable.py b/src/ValuedParams/Variable.py index 7e5bea59..96a7a45b 100644 --- a/src/ValuedParams/Variable.py +++ b/src/ValuedParams/Variable.py @@ -45,12 +45,13 @@ def read(self, comp_name, spec, mode, alias_dict=None): self._raven_var = spec.value return [self._raven_var] - def evaluate(self, inputs, target_var=None, aliases=None): + def evaluate(self, inputs, target_var=None, aliases=None, custom_input=None): """ Evaluate this ValuedParam, wherever it gets its data from @ In, inputs, dict, stuff from RAVEN, particularly including the keys 'meta' and 'raven_vars' @ In, target_var, str, optional, requested outgoing variable name if not None @ In, aliases, dict, optional, alternate variable names for searching in variables + @ In, custom_input, list, optional, additional input nodes from user input @ Out, value, dict, dictionary of resulting evaluation as {vars: vals} @ Out, meta, dict, dictionary of meta (possibly changed during evaluation) """ diff --git a/tests/integration_tests/mechanics/storage_func/heron_input.xml b/tests/integration_tests/mechanics/storage_func/heron_input.xml index f52d74c0..dbff4f3b 100644 --- a/tests/integration_tests/mechanics/storage_func/heron_input.xml +++ b/tests/integration_tests/mechanics/storage_func/heron_input.xml @@ -113,6 +113,14 @@ transfers + + + 42 + unknown + + -2 + -0.5 + diff --git a/tests/integration_tests/mechanics/storage_func/transfers.py b/tests/integration_tests/mechanics/storage_func/transfers.py index 666313e8..f96c2361 100644 --- a/tests/integration_tests/mechanics/storage_func/transfers.py +++ b/tests/integration_tests/mechanics/storage_func/transfers.py @@ -16,8 +16,18 @@ def flex_price(data, meta): """ sine = meta['HERON']['RAVEN_vars']['Signal'] t = meta['HERON']['time_index'] + # check for the existince of the custom functions + for node in meta['HERON']['custom_input']: + if node.tag == 'General': + ans = node.find('TheAnswer').text + qus = node.find('TheQuestion').text + elif node.tag == 'scalar': + scalar = float(node.text) + elif node.tag == 'loc': + loc = float(node.text) + print(f'The answer to the question "{qus}" is "{ans}".') # DispatchManager # scale electricity consumed to flex between -1 and 1 - amount = - 2 * (sine[t] - 0.5) + amount = scalar * (sine[t] + loc) data = {'reference_price': amount} return data, meta