Пример #1
0
def test_transfer(pywr_solver, size):
    """Test a simple transfer model. """

    model = Model()

    Scenario(model, name='test', size=size)

    supply1 = Input(model, name='supply-1', max_flow=5.0)
    wtw1 = Link(model, name='wtw-1')
    demand1 = Output(model, name='demand-1', max_flow=10.0, cost=-10.0)

    supply1.connect(wtw1)
    wtw1.connect(demand1)

    supply2 = Input(model, name='supply-2', max_flow=15.0)
    wtw2 = Link(model, name='wtw-2')
    demand2 = Output(model, name='demand-2', max_flow=10.0, cost=-10.0)

    supply2.connect(wtw2)
    wtw2.connect(demand2)

    transfer21 = Link(model, name='transfer-12', max_flow=2.0, cost=1.0)
    wtw2.connect(transfer21)
    transfer21.connect(wtw1)

    model.setup()
    model.step()

    assert_allclose(supply1.flow, [5.0] * size)
    assert_allclose(demand1.flow, [7.0] * size)
    assert_allclose(supply2.flow, [12.0] * size)
    assert_allclose(demand2.flow, [10.0] * size)
    assert_allclose(transfer21.flow, [2.0] * size)
Пример #2
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')
Пример #3
0
def test_delay_param_load():
    """Test that the `.load` method of `FlowDelayParameter` works correctly"""

    model = Model()
    model.timestepper.start = "2015/01/01"
    model.timestepper.end = "2015/01/31"
    catchment = Catchment(model, name="input", flow=1)
    output = Output(model, name="output")
    catchment.connect(output)

    data = {"name": "delay", "node": "input", "days": 2}

    param = FlowDelayParameter.load(model, data)

    assert param.days == 2

    data = {"name": "delay2", "node": "input", "timesteps": 2}

    param2 = FlowDelayParameter.load(model, data)

    assert param2.timesteps == 2

    expected = np.concatenate([np.zeros(2), np.ones(29)]).reshape(31, 1)

    AssertionRecorder(model, param, name="rec1", expected_data=expected)
    AssertionRecorder(model, param2, name="rec2", expected_data=expected)

    model.setup()
    model.run()
Пример #4
0
def test_virtual_storage_duplicate_route():
    """ Test the VirtualStorage node """

    model = pywr.core.Model()

    inpt = Input(model, "Input", max_flow=20)
    lnk = Link(model, "Link")
    inpt.connect(lnk)
    otpt = Output(model, "Output", max_flow=10, cost=-10.0)
    lnk.connect(otpt)

    vs = pywr.core.VirtualStorage(model,
                                  "Licence", [lnk, otpt],
                                  factors=[0.5, 1.0],
                                  initial_volume=10.0,
                                  max_volume=10.0)

    model.setup()

    assert_allclose(vs.volume, [10], atol=1e-7)

    model.step()

    assert_allclose(otpt.flow, [10 / 1.5], atol=1e-7)
    assert_allclose(vs.volume, [0], atol=1e-7)

    model.step()

    assert_allclose(otpt.flow, [0], atol=1e-7)
    assert_allclose(vs.volume, [0], atol=1e-7)
Пример #5
0
    def test_initial_volume(self):
        """Test RollingVirtualStorage node behaviour when initial volume is less than max volume"""

        model = pywr.core.Model(timestep="1D")

        inpt = Input(model, "Input", max_flow=0.0)
        lnk = Link(model, "Link")
        inpt.connect(lnk)
        otpt = Output(model, "Output", max_flow=10, cost=-10.0)
        lnk.connect(otpt)

        vs = pywr.core.RollingVirtualStorage(model,
                                             "Licence", [lnk],
                                             timesteps=3,
                                             initial_volume=70.0,
                                             max_volume=100.0)

        model.setup()

        assert_allclose(vs.volume, [70.0], atol=1e-7)

        model.step()

        assert_allclose(otpt.flow, [0.0], atol=1e-7)
        assert_allclose(vs.volume, [85.0], atol=1e-7)

        model.step()

        assert_allclose(otpt.flow, [0.0], atol=1e-7)
        assert_allclose(vs.volume, [100.0], atol=1e-7)

        model.step()

        assert_allclose(otpt.flow, [0.0], atol=1e-7)
        assert_allclose(vs.volume, [100.0], atol=1e-7)
Пример #6
0
def test_virtual_storage(solver):
    """ Test the VirtualStorage node """

    model = pywr.core.Model(solver=solver)

    inpt = Input(model, "Input", max_flow=20)
    lnk = Link(model, "Link")
    inpt.connect(lnk)
    otpt = Output(model, "Output", max_flow=10, cost=-10.0)
    lnk.connect(otpt)

    vs = pywr.core.VirtualStorage(model, "Licence", [lnk], initial_volume=10.0, max_volume=10.0)

    model.setup()

    assert_allclose(vs.volume, [10], atol=1e-7)

    model.step()

    assert_allclose(otpt.flow, [10], atol=1e-7)
    assert_allclose(vs.volume, [0], atol=1e-7)

    model.step()

    assert_allclose(otpt.flow, [0], atol=1e-7)
    assert_allclose(vs.volume, [0], atol=1e-7)
Пример #7
0
def test_transfer2(pywr_solver, size):
    """Test a simple transfer model. """

    model = Model()

    Scenario(model, name='test', size=size)

    demands = [9.47, 7.65, 9.04, 9.56, 9.44]
    supply = [4.74, 6.59, 12.04, 8.81, 11.75]

    for i, (s, d) in enumerate(zip(supply, demands)):
        s = Input(model, name=f'supply-{i}', max_flow=s)
        lnk = Link(model, name=f'wtw-{i}')
        d = Output(model, name=f'demand-{i}', max_flow=d, cost=-10.0)

        s.connect(lnk)
        lnk.connect(d)

    transfer04 = Link(model, name='transfer-04', max_flow=15.36, cost=1.0)

    model.nodes['wtw-0'].connect(transfer04)
    transfer04.connect(model.nodes['wtw-4'])

    model.setup()
    model.step()

    expected_supply = [4.74, 6.59, 9.04, 8.81, 9.44]

    for i, expected in enumerate(expected_supply):
        assert_allclose(model.nodes[f'supply-{i}'].flow, [expected] * size)

    assert_allclose(transfer04.flow, [0.0] * size, atol=1e-8)
Пример #8
0
def test_delay_node(key, delay, initial_flow):
    """Test that the `DelayNode` and the `FlowDelayParameter` internal to it correctly delay node for a range of inputs and
    across scenarios"""
    model = Model()

    model.timestepper.start = "2015/01/01"
    model.timestepper.end = "2015/01/31"

    scen = Scenario(model, name="scenario", size=2)
    flow_vals = np.arange(1, 63).reshape((31, 2), order="F")
    flow = ArrayIndexedScenarioParameter(model, scen, flow_vals)

    catchment = Catchment(model, name="input", flow=flow)
    kwargs = {key: delay}
    if initial_flow:
        kwargs["initial_flow"] = initial_flow
    delaynode = DelayNode(model, name="delaynode", **kwargs)
    output = Output(model, name="output")

    catchment.connect(delaynode)
    delaynode.connect(output)

    rec = NumpyArrayNodeRecorder(model, output)

    model.run()
    if initial_flow:
        expected = np.concatenate(
            [np.full((delay, 2), initial_flow), flow_vals[:-delay, :]])
    else:
        expected = np.concatenate(
            [np.zeros((delay, 2)), flow_vals[:-delay, :]])

    assert_array_almost_equal(rec.data, expected)
Пример #9
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')
Пример #10
0
def test_empty_storage_min_flow():

    model = Model()
    storage = Storage(model, "storage", initial_volume=100, max_volume=100, num_inputs=1, num_outputs=0)
    otpt = Output(model, "output", min_flow=75)
    storage.connect(otpt)
    model.check()
    model.step()
    with pytest.raises(RuntimeError):
        model.step()
Пример #11
0
    def _make_evaporation_node(self, model, evaporation, cost):

        if not isinstance(self.area, Parameter):
            log.warning(
                'Evaporation nodes can only be created if an area Parameter is given.'
            )
            return

        if evaporation is None:
            try:
                evaporation_param = load_parameter(
                    model, f'__{self.name}__:evaporation')
            except KeyError:
                log.warning(
                    f"Please speficy an evaporation or a weather on node {self.name}"
                )
                return
        elif isinstance(evaporation, pd.DataFrame) or isinstance(
                evaporation, pd.Series):
            evaporation = evaporation.astype(np.float64)
            evaporation_param = MonthlyProfileParameter(model, evaporation)
        else:
            evaporation_param = evaporation

        evaporation_flow_param = AggregatedParameter(
            model, [evaporation_param, self.const, self.area],
            agg_func='product')

        evporation_node = Output(model,
                                 '{}.evaporation'.format(self.name),
                                 parent=self)
        evporation_node.max_flow = evaporation_flow_param
        evporation_node.cost = cost

        self.connect(evporation_node)
        self.evaporation_node = evporation_node

        self.evaporation_recorder = NumpyArrayNodeRecorder(
            model,
            evporation_node,
            name=f'__{evporation_node.name}__:evaporation')
Пример #12
0
def create_model():
    # create a model
    model = Model(start="2016-01-01", end="2019-12-31", timestep=7)

    # create three nodes (an input, a link, and an output)
    A = Input(model, name="A", max_flow=10.0)
    B = Link(model, name="B", cost=10.0)
    C = Output(model, name="C", max_flow=5.0, cost=-20.0)

    # connect the nodes together
    A.connect(B)
    B.connect(C)

    return model
Пример #13
0
    def test_run(self, from_json):
        """Test RollingVirtualStorage node behaviour."""

        if from_json:
            model = load_model('rolling_virtual_storage.json')

            vs = model.nodes['Licence']
            otpt = model.nodes['Output']
        else:
            model = pywr.core.Model()

            inpt = Input(model, "Input", max_flow=20)
            lnk = Link(model, "Link")
            inpt.connect(lnk)
            otpt = Output(model, "Output", max_flow=15, cost=-10.0)
            lnk.connect(otpt)

            vs = pywr.core.RollingVirtualStorage(model,
                                                 "Licence", [lnk],
                                                 days=3,
                                                 initial_volume=30.0,
                                                 max_volume=30.0)

        model.setup()

        assert_allclose(vs.volume, [30], atol=1e-7)

        model.step()

        assert_allclose(otpt.flow, [15], atol=1e-7)
        assert_allclose(vs.volume, [15], atol=1e-7)

        model.step()

        assert_allclose(otpt.flow, [15], atol=1e-7)
        assert_allclose(vs.volume, [0], atol=1e-7)

        model.step()

        assert_allclose(otpt.flow, [0], atol=1e-7)
        # End of third day the flow from the first day is return to the licence
        assert_allclose(vs.volume, [15], atol=1e-7)

        model.step()

        assert_allclose(otpt.flow, [15], atol=1e-7)
        assert_allclose(vs.volume, [15], atol=1e-7)
Пример #14
0
def test_delay_failure(key, delay):
    """Test the FlowDelayParameter returns a ValueError when the input value of the `days` attribute is not
    divisible exactly by the model timestep delta and when the `timesteps` attribute is less than 1
    """

    model = Model()
    model.timestepper.start = "2015/01/01"
    model.timestepper.end = "2015/01/31"
    model.timestepper.delta = 3

    catchment = Catchment(model, name="input", flow=1)
    output = Output(model, name="output")
    catchment.connect(output)

    FlowDelayParameter(model, catchment, **{key: delay})

    with pytest.raises(ValueError):
        model.setup()
Пример #15
0
    def test_run_weekly(self):
        """Test RollingVirtualStorage node behaviour with a weekly timestep."""

        model = pywr.core.Model(timestep='7D')

        inpt = Input(model, "Input", max_flow=20)
        lnk = Link(model, "Link")
        inpt.connect(lnk)
        otpt = Output(model, "Output", max_flow=10, cost=-10.0)
        lnk.connect(otpt)

        vs = pywr.core.RollingVirtualStorage(model,
                                             "Licence", [lnk],
                                             timesteps=3,
                                             initial_volume=100.0,
                                             max_volume=100.0)

        model.setup()

        assert_allclose(vs.volume, [100.0], atol=1e-7)

        model.step()

        assert_allclose(otpt.flow, [10.0], atol=1e-7)
        assert_allclose(vs.volume, [30.0], atol=1e-7)

        model.step()

        assert_allclose(otpt.flow, [30.0 / 7], atol=1e-7)
        assert_allclose(vs.volume, [0], atol=1e-7)

        model.step()

        assert_allclose(otpt.flow, [0], atol=1e-7)
        # End of third day the flow from the first day is return to the licence
        assert_allclose(vs.volume, [70.0], atol=1e-7)

        model.step()

        assert_allclose(otpt.flow, [10.0], atol=1e-7)
        assert_allclose(vs.volume, [30.0], atol=1e-7)
Пример #16
0
    def test_max_vol_param_zero_initial_vol(self):
        """Test RollingVirtualStorage node behaviour when initial volume is zero"""

        model = pywr.core.Model(timestep="1D")

        inpt = Input(model, "Input", max_flow=0.0)
        lnk = Link(model, "Link")
        inpt.connect(lnk)
        otpt = Output(model, "Output", max_flow=10, cost=-10.0)
        lnk.connect(otpt)

        mx_vol = ConstantParameter(model, 100)
        pywr.core.RollingVirtualStorage(
            model,
            "Licence",
            [lnk],
            timesteps=3,
            initial_volume=0.0,
            initial_volume_pc=0.0,
            max_volume=mx_vol,
        )

        with pytest.raises(ValueError):
            model.setup()
Пример #17
0
def test_reservoir_circle():
    """
    Issue #140. A model with a circular route, from a reservoir Input back
    around to it's own Output.

                 Demand
                    ^
                    |
                Reservoir <- Pumping
                    |           ^
                    v           |
              Compensation      |
                    |           |
                    v           |
    Catchment -> River 1 -> River 2 ----> MRFA -> Waste
                                    |              ^
                                    |---> MRFB ----|
    """
    model = Model()

    catchment = Input(model, "catchment", max_flow=500, min_flow=500)

    reservoir = Storage(model,
                        "reservoir",
                        max_volume=10000,
                        initial_volume=5000)

    demand = Output(model, "demand", max_flow=50, cost=-100)
    pumping_station = Link(model, "pumping station", max_flow=100, cost=-10)
    river1 = Link(model, "river1")
    river2 = Link(model, "river2")
    compensation = Link(model, "compensation", cost=600)
    mrfA = Link(model, "mrfA", cost=-500, max_flow=50)
    mrfB = Link(model, "mrfB")
    waste = Output(model, "waste")

    catchment.connect(river1)
    river1.connect(river2)
    river2.connect(mrfA)
    river2.connect(mrfB)
    mrfA.connect(waste)
    mrfB.connect(waste)
    river2.connect(pumping_station)
    pumping_station.connect(reservoir)
    reservoir.connect(compensation)
    compensation.connect(river1)
    reservoir.connect(demand)

    model.check()
    model.setup()

    # not limited by mrf, pump capacity is constraint
    model.step()
    assert_allclose(catchment.flow, 500)
    assert_allclose(waste.flow, 400)
    assert_allclose(compensation.flow, 0)
    assert_allclose(pumping_station.flow, 100)
    assert_allclose(demand.flow, 50)

    # limited by mrf
    catchment.min_flow = catchment.max_flow = 100
    model.step()
    assert_allclose(waste.flow, 50)
    assert_allclose(compensation.flow, 0)
    assert_allclose(pumping_station.flow, 50)
    assert_allclose(demand.flow, 50)

    # reservoir can support mrf, but doesn't need to
    compensation.cost = 200
    model.step()
    assert_allclose(waste.flow, 50)
    assert_allclose(compensation.flow, 0)
    assert_allclose(pumping_station.flow, 50)
    assert_allclose(demand.flow, 50)

    # reservoir supporting mrf
    catchment.min_flow = catchment.max_flow = 0
    model.step()
    assert_allclose(waste.flow, 50)
    assert_allclose(compensation.flow, 50)
    assert_allclose(pumping_station.flow, 0)
    assert_allclose(demand.flow, 50)