def test_storage_max_volume_param(): """Test a that an max_volume with a Parameter results in the correct current_pc """ model = Model(start=pandas.to_datetime('2016-01-01'), end=pandas.to_datetime('2016-01-01')) storage = Storage(model, 'storage', inputs=1, outputs=0) otpt = Output(model, 'output', max_flow=99999, cost=-99999) storage.connect(otpt) p = ConstantParameter(model, 20.0) storage.max_volume = p storage.initial_volume = 10.0 storage.initial_volume_pc = 0.5 model.setup() np.testing.assert_allclose(storage.current_pc, 0.5) model.run() p.set_double_variables(np.asarray([ 40.0, ])) model.reset() # This is a demonstration of the issue describe in #470 # https://github.com/pywr/pywr/issues/470 # The initial storage is defined in both absolute and relative terms # but these are now not consistent with one another and the updated max_volume np.testing.assert_allclose(storage.volume, 10.0) np.testing.assert_allclose(storage.current_pc, 0.5)
def optimisation_model(simple_storage_model): model = simple_storage_model # Modify the model to have two variables. inpt = model.nodes["Input"] inpt.max_flow = ConstantParameter( model, inpt.max_flow, lower_bounds=0.0, upper_bounds=10.0, name="Input flow", is_variable=True, ) otpt = model.nodes["Output"] otpt.max_flow = ConstantParameter( model, otpt.max_flow, lower_bounds=0.0, upper_bounds=10.0, name="Output flow", is_variable=True, ) # And two objectives. TotalFlowNodeRecorder(model, inpt, name="Total inflow", is_objective="maximise") TotalFlowNodeRecorder(model, otpt, name="Total outflow", is_objective="maximise") return model
def test_storage_max_volume_param_raises(solver): """Test a that an max_volume with a Parameter that has children. Only some aggregated style parameters should work here. """ model = Model(solver=solver, start=pandas.to_datetime('2016-01-01'), end=pandas.to_datetime('2016-01-01')) storage = Storage(model, 'storage', num_inputs=1, num_outputs=0) otpt = Output(model, 'output', max_flow=99999, cost=-99999) storage.connect(otpt) p = AggregatedParameter( model, [ConstantParameter(model, 20.0), ConstantParameter(model, 20.0)], agg_func='sum') storage.max_volume = p storage.initial_volume = 10.0 model.setup() np.testing.assert_allclose(storage.current_pc, 0.25)
def test_storage_max_volume_param_raises(solver): """Test a that an max_volume with a Parameter that has children is an error """ model = Model(solver=solver, start=pandas.to_datetime('2016-01-01'), end=pandas.to_datetime('2016-01-01')) storage = Storage(model, 'storage', num_inputs=1, num_outputs=0) otpt = Output(model, 'output', max_flow=99999, cost=-99999) storage.connect(otpt) p = AggregatedParameter( model, [ConstantParameter(model, 20.0), ConstantParameter(model, 20.0)], agg_func='sum') p1 = AggregatedParameter(model, [p, ConstantParameter(model, 1.5)], agg_func="product") storage.max_volume = p1 storage.initial_volume = 10.0 with pytest.raises(RuntimeError): model.run()
def test_storage_max_volume_param(solver): """Test a that an max_volume with a Parameter results in the correct current_pc """ model = Model(solver=solver, start=pandas.to_datetime('2016-01-01'), end=pandas.to_datetime('2016-01-01')) storage = Storage(model, 'storage', num_inputs=1, num_outputs=0) otpt = Output(model, 'output', max_flow=99999, cost=-99999) storage.connect(otpt) p = ConstantParameter(model, 20.0) storage.max_volume = p storage.initial_volume = 10.0 model.setup() np.testing.assert_allclose(storage.current_pc, 0.5) model.run() p.update(np.asarray([ 40.0, ])) model.reset() np.testing.assert_allclose(storage.current_pc, 0.25)
def test_storage_initial_volume_pc(solver): """Test that setting initial volume as a percentage works as expected. """ model = Model(solver=solver, start=pandas.to_datetime('2016-01-01'), end=pandas.to_datetime('2016-01-01')) storage = Storage(model, 'storage', num_inputs=1, num_outputs=0) otpt = Output(model, 'output', max_flow=99999, cost=-99999) storage.connect(otpt) p = ConstantParameter(model, 20.0) storage.max_volume = p storage.initial_volume_pc = 0.5 model.setup() np.testing.assert_allclose(storage.current_pc, 0.5) np.testing.assert_allclose(storage.volume, 10.0) model.run() p.update(np.asarray([ 40.0, ])) model.reset() np.testing.assert_allclose(storage.current_pc, 0.5) np.testing.assert_allclose(storage.volume, 20.0)
def __init__(self, model, name, *args, **kwargs): demand = kwargs.pop('demand', ConstantParameter(model, 0)) supply = kwargs.pop('supply', ConstantParameter(model, 0)) headroom = kwargs.pop('headroom', ConstantParameter(model, 0)) super().__init__(model, name, *args, **kwargs) self.supply_node = Input(model, name=f'{name}-supply', parent=self) self.demand_node = Output(model, name=f'{name}-demand', parent=self) self.supply_node.max_flow = MaxParameter(model, supply) demand_headroom = AggregatedParameter(model, parameters=[demand, headroom], agg_func='sum') self.demand_node.max_flow = MaxParameter(model, demand_headroom) self.demand_node.cost = -100 self.supply_node.connect(self) self.connect(self.demand_node) # Track deficits deficit_param = DeficitParameter(model, self.demand_node, name=f'{name}-deficit_param') NumpyArrayParameterRecorder(model, deficit_param, name=f'__{name}-demand__:deficit', temporal_agg_func='sum')
def test_control_curve_interpolated(model): m = model m.timestepper.delta = 200 s = m.nodes['Storage'] o = m.nodes['Output'] s.connect(o) cc = ConstantParameter(model, 0.8) values = [20.0, 5.0, 0.0] s.cost = p = ControlCurveInterpolatedParameter(model, s, cc, values) @assert_rec(model, p) def expected_func(timestep, scenario_index): v = s.initial_volume c = cc.value(timestep, scenario_index) if c == 1.0 and v == 100.0: expected = values[1] elif c == 0.0 and v == 0.0: expected = values[1] else: expected = np.interp(v / 100.0, [0.0, c, 1.0], values[::-1]) return expected for control_curve in (0.0, 0.8, 1.0): cc.update(np.array([ control_curve, ])) for initial_volume in (0.0, 10.0, 50.0, 80.0, 90.0, 100.0): s.initial_volume = initial_volume model.run()
def __init__(self, *args, **kwargs): """ Keywords: control_curve - A Parameter object that can return the control curve position, as a percentage of fill, for the given timestep. """ control_curve = pop_kwarg_parameter(kwargs, 'control_curve', None) above_curve_cost = kwargs.pop('above_curve_cost', None) cost = kwargs.pop('cost', 0.0) if above_curve_cost is not None: if control_curve is None: # Make a default control curve at 100% capacity control_curve = ConstantParameter(1.0) elif not isinstance(control_curve, Parameter): # Assume parameter is some kind of constant and coerce to ConstantParameter control_curve = ConstantParameter(control_curve) if not isinstance(cost, Parameter): # In the case where an above_curve_cost is given and cost is not a Parameter # a default cost Parameter is created. kwargs['cost'] = ControlCurveParameter( self, control_curve, [above_curve_cost, cost]) else: raise ValueError( 'If an above_curve_cost is given cost must not be a Parameter.' ) else: # reinstate the given cost parameter to pass to the parent constructors kwargs['cost'] = cost super(Reservoir, self).__init__(*args, **kwargs)
def __init__(self, model, name, **kwargs): # Create the keyword arguments for the HP recorder hp_recorder_kwarg_names = ('efficiency', 'density', 'flow_unit_conversion', 'energy_unit_conversion') hp_kwargs = {} for kwd in hp_recorder_kwarg_names: try: hp_kwargs[kwd] = kwargs.pop(kwd) except KeyError: pass self.storage_node = storage_node = kwargs.pop('storage_node', None) # See if there is a level parameter on the storage node if storage_node is not None: level_parameter = storage_node.level if not isinstance(level_parameter, Parameter): level_parameter = ConstantParameter(model, value=level_parameter) else: level_parameter = None turbine_elevation = kwargs.pop('turbine_elevation', 0) generation_capacity = kwargs.pop('generation_capacity', 0) min_operating_elevation = kwargs.pop('min_operating_elevation', 0) min_head = min_operating_elevation - turbine_elevation super().__init__(model, name, **kwargs) if isinstance(generation_capacity, (float, int)): generation_capacity = ConstantParameter(model, generation_capacity) hp_target_flow = HydropowerTargetParameter( model, generation_capacity, water_elevation_parameter=level_parameter, min_head=min_head, min_flow=ConstantParameter(model, 0), turbine_elevation=turbine_elevation, **{k: v for k, v in hp_kwargs.items()}) self.max_flow = hp_target_flow hp_recorder = HydropowerRecorder( model, self, water_elevation_parameter=level_parameter, turbine_elevation=turbine_elevation, **hp_kwargs) self.hydropower_recorder = hp_recorder
def test_with_parameters(self, model): """ Test with `parameters` keyword argument. """ m = model s = m.nodes['Storage'] # Two different control curves cc = [ConstantParameter(model, 0.8), ConstantParameter(model, 0.6)] # Three different parameters to return params = [ ConstantParameter(model, 1.0), ConstantParameter(model, 0.7), ConstantParameter(model, 0.4) ] s.cost = ControlCurveParameter(model, s, cc, parameters=params) self._assert_results(m, s)
def test_two_control_curves(self, simple_storage_model): """Test `ControlCurvePiecewiseInterpolatedParameter` with two control curves. """ model = simple_storage_model storage_node = model.nodes["Storage"] input_node = model.nodes["Input"] output_node = model.nodes["Output"] control_curves = [ ConstantParameter(model, 0.75), ConstantParameter(model, 0.25), ] parameter = ControlCurvePiecewiseInterpolatedParameter(model, storage_node, control_curves, [(500, 200), (100, 50), (0, -100)], name="CCPIP") assert parameter.minimum == 0.0 assert parameter.maximum == 1.0 input_node.max_flow = 1.0 input_node.cost = 0 output_node.max_flow = 0.0 storage_node.initial_volume = 0.0 storage_node.max_volume = 100.0 storage_node.cost = -10 model.timestepper.start = "1920-01-01" model.timestepper.delta = 1 model.timestepper.end = model.timestepper.start + model.timestepper.offset * 100 @assert_rec(model, parameter) def expected_func(timestep, scenario_index): volume = timestep.index current_position = volume / storage_node.max_volume if current_position >= 0.75: factor = (volume - 75) / 25 value = 200 + factor * (500 - 200) elif current_position >= 0.25: factor = (volume - 25) / 50 value = 50 + factor * (100 - 50) else: factor = volume / 25 value = -100 + factor * 100 return value model.run()
def test_parameters(self, simple_linear_model, tmpdir): """ Test the TablesRecorder """ from pywr.parameters import ConstantParameter model = simple_linear_model otpt = model.nodes['Output'] inpt = model.nodes['Input'] p = ConstantParameter(model, 10.0, name='max_flow') inpt.max_flow = p # ensure TablesRecorder can handle parameters with a / in the name p_slash = ConstantParameter(model, 0.0, name='name with a / in it') inpt.min_flow = p_slash agg_node = AggregatedNode(model, 'Sum', [otpt, inpt]) inpt.max_flow = 10.0 otpt.cost = -2.0 h5file = tmpdir.join('output.h5') import tables with tables.open_file(str(h5file), 'w') as h5f: with pytest.warns(ParameterNameWarning): rec = TablesRecorder(model, h5f, parameters=[p, p_slash]) # check parameters have been added to the component tree # this is particularly important for parameters which update their # values in `after`, e.g. DeficitParameter (see #465) assert(not model.find_orphaned_parameters()) assert(p in rec.children) assert(p_slash in rec.children) with pytest.warns(tables.NaturalNameWarning): model.run() for node_name in model.nodes.keys(): ca = h5f.get_node('/', node_name) assert ca.shape == (365, 1) if node_name == 'Sum': np.testing.assert_allclose(ca, 20.0) elif "name with a" in node_name: assert(node_name == "name with a _ in it") np.testing.assert_allclose(ca, 0.0) else: np.testing.assert_allclose(ca, 10.0)
def test_init(self, simple_storage_model): """ Test initialisation raises error with too many keywords """ stg = simple_storage_model.nodes['Storage'] param = ConstantParameter(simple_storage_model, 2.0) with pytest.raises(ValueError): # Passing both "parameter" and "storage_node" is invalid Polynomial1DParameter(simple_storage_model, [0.5, np.pi], parameter=param, storage_node=stg)
def test_with_nonstorage(self, model): """Test usage on non-`Storage` node.""" # Now test if the parameter is used on a non storage node m = model s = m.nodes["Storage"] l = Link(m, "Link") # Connect the link node to the network to create a valid model o = m.nodes["Output"] s.connect(l) l.connect(o) cc = ConstantParameter(model, 0.8) l.cost = ControlCurveParameter(model, s, cc, [10.0, 0.0]) @assert_rec(m, l.cost) def expected_func(timestep, scenario_index): v = s.initial_volume if v >= 80.0: expected = 10.0 else: expected = 0.0 return expected for initial_volume in (90, 70): s.initial_volume = initial_volume m.run()
def test_parameters(self, simple_linear_model, tmpdir): """ Test the TablesRecorder """ from pywr.parameters import ConstantParameter model = simple_linear_model otpt = model.nodes['Output'] inpt = model.nodes['Input'] p = ConstantParameter(10.0, name='max_flow') inpt.max_flow = p agg_node = AggregatedNode(model, 'Sum', [otpt, inpt]) inpt.max_flow = 10.0 otpt.cost = -2.0 h5file = tmpdir.join('output.h5') import tables with tables.open_file(str(h5file), 'w') as h5f: rec = TablesRecorder(model, h5f, parameters=[p, ]) model.run() for node_name in model.nodes.keys(): ca = h5f.get_node('/', node_name) assert ca.shape == (365, 1) if node_name == 'Sum': np.testing.assert_allclose(ca, 20.0) else: np.testing.assert_allclose(ca, 10.0)
def test_run(self, simple_storage_model): model = simple_storage_model storage_node = model.nodes["Storage"] input_node = model.nodes["Input"] output_node = model.nodes["Output"] control_curve = ConstantParameter(model, 0.5) parameter = PiecewiseLinearControlCurve(model, storage_node, control_curve, values=[(50, 100), (200, 500)], name="PLCC") assert parameter.minimum == 0.0 assert parameter.maximum == 1.0 input_node.max_flow = 1.0 input_node.cost = 0 output_node.max_flow = 0.0 storage_node.initial_volume = 0.0 storage_node.max_volume = 100.0 storage_node.cost = -10 model.timestepper.start = "1920-01-01" model.timestepper.delta = 1 model.timestepper.end = model.timestepper.start + model.timestepper.delta*100 @assert_rec(model, parameter) def expected_func(timestep, scenario_index): volume = timestep.index control_curve = 0.5 current_position = volume / storage_node.max_volume if current_position > control_curve: factor = (volume - 50) / 50 value = 200 + factor * (500 - 200) else: factor = volume / 50 value = 50 + factor * (100 - 50) return value model.run()
def test_nodes_with_str(self, simple_linear_model, tmpdir): """ Test the TablesRecorder """ from pywr.parameters import ConstantParameter model = simple_linear_model otpt = model.nodes['Output'] inpt = model.nodes['Input'] agg_node = AggregatedNode(model, 'Sum', [otpt, inpt]) p = ConstantParameter(model, 10.0, name='max_flow') inpt.max_flow = p otpt.cost = -2.0 h5file = tmpdir.join('output.h5') import tables with tables.open_file(str(h5file), 'w') as h5f: nodes = ['Output', 'Input', 'Sum'] where = "/agroup" rec = TablesRecorder(model, h5f, nodes=nodes, parameters=[p, ], where=where) model.run() for node_name in ['Output', 'Input', 'Sum', 'max_flow']: ca = h5f.get_node("/agroup/" + node_name) assert ca.shape == (365, 1) if node_name == 'Sum': np.testing.assert_allclose(ca, 20.0) else: np.testing.assert_allclose(ca, 10.0)
def test_annual_count_index_parameter_recorder(simple_storage_model): """ Test AnnualCountIndexParameterRecord The test sets uses a simple reservoir model with different inputs that trigger a control curve failure after different numbers of years. """ from pywr.parameters import ConstantScenarioParameter, ConstantParameter from pywr.parameters.control_curves import ControlCurveIndexParameter model = simple_storage_model scenario = Scenario(model, 'A', size=2) # Simulate 5 years model.timestepper.start = '2015-01-01' model.timestepper.end = '2019-12-31' # Control curve parameter param = ControlCurveIndexParameter(model, model.nodes['Storage'], ConstantParameter(model, 0.25)) # Storage model has a capacity of 20, but starts at 10 Ml # Demand is roughly 2 Ml/d per year # First ensemble balances the demand # Second ensemble should fail during 3rd year demand = 2.0 / 365 model.nodes['Input'].max_flow = ConstantScenarioParameter(model, scenario, [demand, 0]) model.nodes['Output'].max_flow = demand # Create the recorder with a threshold of 1 rec = AnnualCountIndexParameterRecorder(model, param, 1) model.run() # We expect no failures in the first ensemble, but 3 out of 5 in the second assert_allclose(rec.values(), [0, 3])
def test_control_curve(solver): """ Use a simple model of a Reservoir to test that a control curve behaves as expected. The control curve should alter the cost of the Reservoir when it is above or below a particular threshold. (flow = 8.0) (max_flow = 10.0) Catchment -> River -> DemandCentre | ^ (max_flow = 2.0) v | (max_flow = 2.0) Reservoir """ in_flow = 8 model = pywr.core.Model(solver=solver) catchment = river.Catchment(model, name="Catchment", flow=in_flow) lnk = river.River(model, name="River") catchment.connect(lnk) demand = pywr.core.Output(model, name="Demand", cost=-10.0, max_flow=10) lnk.connect(demand) from pywr.parameters import ConstantParameter control_curve = ConstantParameter(0.8) reservoir = river.Reservoir(model, name="Reservoir", max_volume=10, cost=-20, above_curve_cost=0.0, control_curve=control_curve, initial_volume=10) reservoir.inputs[0].max_flow = 2.0 reservoir.outputs[0].max_flow = 2.0 lnk.connect(reservoir) reservoir.connect(demand) model.step() # Reservoir is currently above control curve. 2 should be taken from the # reservoir assert (reservoir.volume == 8) assert (demand.flow == 10) # Reservoir is still at (therefore above) control curve. So 2 is still taken model.step() assert (reservoir.volume == 6) assert (demand.flow == 10) # Reservoir now below curve. Better to retain volume and divert some of the # inflow model.step() assert (reservoir.volume == 8) assert (demand.flow == 6) # Set the above_curve_cost function to keep filling from pywr.parameters.control_curves import ControlCurveParameter # We know what we're doing with the control_curve Parameter so unset its parent before overriding # the cost parameter. reservoir.cost = ControlCurveParameter(reservoir, control_curve, [-20.0, -20.0]) model.step() assert (reservoir.volume == 10) assert (demand.flow == 6)
def test_basic_use(self, simple_linear_model): """ Test the basic use of `ConstantParameter` using the Python API """ model = simple_linear_model # Add two scenarios scA = Scenario(model, 'Scenario A', size=2) scB = Scenario(model, 'Scenario B', size=5) p = ConstantParameter(model, np.pi, name='pi', comment='Mmmmm Pi!') assert not p.is_variable assert p.double_size == 1 assert p.integer_size == 0 model.setup() ts = model.timestepper.current # Now ensure the appropriate value is returned for all scenarios for i, (a, b) in enumerate(itertools.product(range(scA.size), range(scB.size))): si = ScenarioIndex(i, np.array([a, b], dtype=np.int32)) np.testing.assert_allclose(p.value(ts, si), np.pi)
def test_json(self, simple_storage_model): """Test loading from JSON data.""" model = simple_storage_model control_curve1 = ConstantParameter(model, 0.5, name="cc1") control_curve2 = ConstantParameter(model, 0.25, name="cc2") parameter_data = { "type": "controlcurvepiecewiseinterpolated", "storage_node": "Storage", "control_curves": ["cc1", "cc2"], "minimum": 0.2, "maximum": 0.7, "values": [[200, 100], [10, 5], [0, -10]] } parameter = load_parameter(model, parameter_data) assert parameter.minimum == 0.2 assert parameter.maximum == 0.7 np.testing.assert_allclose(parameter.values, [[200, 100], [10, 5], [0, -10]]) assert parameter.control_curves == [control_curve1, control_curve2] assert parameter.storage_node is model.nodes["Storage"]
def test_storage_max_volume_nested_param(): """Test that a max_volume can be used with a Parameter with children. """ model = Model( start=pandas.to_datetime('2016-01-01'), end=pandas.to_datetime('2016-01-01') ) storage = Storage(model, 'storage', num_inputs=1, num_outputs=0) otpt = Output(model, 'output', max_flow=99999, cost=-99999) storage.connect(otpt) p = AggregatedParameter(model, [ConstantParameter(model, 20.0), ConstantParameter(model, 20.0)], agg_func='sum') storage.max_volume = p storage.initial_volume = 10.0 model.setup() np.testing.assert_allclose(storage.current_pc, 0.25)
def test_1st_order_with_parameter(self, simple_linear_model): """ Test 1st order with a `Parameter` """ model = simple_linear_model x = 2.0 p1 = Polynomial1DParameter(model, [0.5, np.pi], parameter=ConstantParameter(model, x)) @assert_rec(model, p1) def expected_func(timestep, scenario_index): return 0.5 + np.pi * x model.run()
def test_control_curve_interpolated(model, use_parameters): m = model m.timestepper.delta = 200 s = m.nodes['Storage'] o = m.nodes['Output'] s.connect(o) cc = ConstantParameter(model, 0.8) values = [20.0, 5.0, 0.0] if use_parameters: # Create the parameter using parameters for the values parameters = [ConstantParameter(model, v) for v in values] s.cost = p = ControlCurveInterpolatedParameter(model, s, cc, parameters=parameters) else: # Create the parameter using a list of values s.cost = p = ControlCurveInterpolatedParameter(model, s, cc, values) @assert_rec(model, p) def expected_func(timestep, scenario_index): v = s.initial_volume c = cc.value(timestep, scenario_index) if c == 1.0 and v == 100.0: expected = values[1] elif c == 0.0 and v == 0.0: expected = values[1] else: expected = np.interp(v / 100.0, [0.0, c, 1.0], values[::-1]) return expected for control_curve in (0.0, 0.8, 1.0): cc.set_double_variables(np.array([ control_curve, ])) for initial_volume in (0.0, 10.0, 50.0, 80.0, 90.0, 100.0): s.initial_volume = initial_volume model.run()
def test_2nd_order_with_parameter(self, simple_linear_model): """ Test 2nd order with a `Parameter` """ model = simple_linear_model x = 2.0 px = ConstantParameter(model, x) p1 = Polynomial1DParameter(model, [0.5, np.pi, 3.0], parameter=px) @assert_rec(model, p1) def expected_func(timestep, scenario_index): return 0.5 + np.pi*x + 3.0*x**2 model.run()
def test_control_curve_interpolated(model): m = model m.scenarios.setup() si = ScenarioIndex(0, np.array([0], dtype=np.int32)) s = Storage(m, 'Storage', max_volume=100.0) cc = ConstantParameter(0.8) values = [20.0, 5.0, 0.0] s.cost = ControlCurveInterpolatedParameter(s, cc, values) s.setup(m) for v in (0.0, 10.0, 50.0, 80.0, 90.0, 100.0): s.initial_volume = v s.reset() assert_allclose(s.get_cost(m.timestepper.current, si), np.interp(v/100.0, [0.0, 0.8, 1.0], values[::-1])) # special case when control curve is 100% cc.update(np.array([1.0,])) s.initial_volume == 100.0 s.reset() assert_allclose(s.get_cost(m.timestepper.current, si), values[1]) # special case when control curve is 0% cc.update(np.array([0.0,])) s.initial_volume == 0.0 s.reset() assert_allclose(s.get_cost(m.timestepper.current, si), values[0])
def _make_weather_nodes(self, model, weather, cost): if not isinstance(self.area, Parameter): raise ValueError( 'Weather nodes can only be created if an area Parameter is given.' ) rainfall = weather['rainfall'].astype(np.float64) rainfall_param = MonthlyProfileParameter(model, rainfall) evaporation = weather['evaporation'].astype(np.float64) evaporation_param = MonthlyProfileParameter(model, evaporation) # Assume rainfall/evap is mm/day # Need to convert: # Mm2 -> m2 # mm/day -> m/day # m3/day -> Mm3/day # TODO allow this to be configured const = ConstantParameter(model, 1e6 * 1e-3 * 1e-6) # Create the flow parameters multiplying area by rate of rainfall/evap rainfall_flow_param = AggregatedParameter( model, [rainfall_param, const, self.area], agg_func='product') evaporation_flow_param = AggregatedParameter( model, [evaporation_param, const, self.area], agg_func='product') # Create the nodes to provide the flows rainfall_node = Input(model, '{}.rainfall'.format(self.name), parent=self) rainfall_node.max_flow = rainfall_flow_param rainfall_node.cost = cost evporation_node = Output(model, '{}.evaporation'.format(self.name), parent=self) evporation_node.max_flow = evaporation_flow_param evporation_node.cost = cost rainfall_node.connect(self) self.connect(evporation_node) self.rainfall_node = rainfall_node self.evaporation_node = evporation_node # Finally record these flows self.rainfall_recorder = NumpyArrayNodeRecorder( model, rainfall_node, name=f'__{rainfall_node.name}__:rainfall') self.evaporation_recorder = NumpyArrayNodeRecorder( model, evporation_node, name=f'__{evporation_node.name}__:evaporation')
def test_orphaned_components(simple_linear_model): model = simple_linear_model model.nodes["Input"].max_flow = ConstantParameter(model, 10.0) result = model.find_orphaned_parameters() assert (not result) # assert that warning not raised by check with pytest.warns(None) as record: model.check() for w in record: if isinstance(w, OrphanedParameterWarning): pytest.fail("OrphanedParameterWarning raised unexpectedly!") # add some orphans orphan1 = ConstantParameter(model, 5.0) orphan2 = ConstantParameter(model, 10.0) orphans = {orphan1, orphan2} result = model.find_orphaned_parameters() assert (orphans == result) with pytest.warns(OrphanedParameterWarning): model.check()
def test_1st(self, simple_storage_model): """ Test 1st order """ model = simple_storage_model stg = model.nodes['Storage'] x = 2.0 y = stg.initial_volume coefs = [[0.5, np.pi], [2.5, 0.3]] p1 = Polynomial2DStorageParameter(model, coefs, stg, ConstantParameter(model, x)) @assert_rec(model, p1) def expected_func(timestep, scenario_index): return 0.5 + np.pi*x + 2.5*y+ 0.3*x*y model.setup() model.step()