示例#1
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)
示例#2
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()
示例#3
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)
示例#4
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)
示例#5
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()
示例#6
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
示例#7
0
class TestGlpkErrorHandling:
    @pytest.mark.skipif(
        Model().solver.name == "lpsolve" or Model().solver.use_unsafe_api,
        reason="NaN not checked for lpsolve or unsafe GLPK API.",
    )
    def test_nan_constraint_error(self):
        """Test a NaN in a row constraint causes an error"""
        # parse the JSON into a model
        model = load_model("simple1.json")

        nan_param = NanParameter(model)
        inpt = model.nodes["supply1"]
        inpt.max_flow = nan_param

        model.setup()

        with pytest.raises(pywr.solvers.GLPKError):
            model.run()

    @pytest.mark.skipif(
        Model().solver.name == "lpsolve" or Model().solver.use_unsafe_api,
        reason="NaN not checked for lpsolve or unsafe GLPK API.",
    )
    def test_nan_cost_error(self):
        """Test a NaN in a node cost causes an error"""
        # parse the JSON into a model
        model = load_model("simple1.json")

        nan_param = NanParameter(model)
        inpt = model.nodes["supply1"]
        inpt.cost = nan_param

        model.setup()

        with pytest.raises(pywr.solvers.GLPKError):
            model.run()
示例#8
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()
示例#9
0
def simple_dcopf_model():

    m = Model(solver='glpk-dcopf')

    g1 = Generator(m, 'gen1')
    g1.max_flow = 100
    g1.cost = 1.0

    g2 = Generator(m, 'gen2')
    g2.max_flow = 100
    g2.cost = 2.0

    l3 = Load(m, 'load3')
    l3.max_flow = 150
    l3.cost = -10

    b1 = Bus(m, 'bus1')
    b2 = Bus(m, 'bus2')
    b3 = Bus(m, 'bus3')

    l12 = Line(m, 'line12')
    l13 = Line(m, 'line13')
    l23 = Line(m, 'line23')

    g1.connect(b1)
    g2.connect(b2)
    l3.connect(b3)

    b1.connect(l12)
    l12.connect(b2)

    b1.connect(l13)
    l13.connect(b3)

    b2.connect(l23)
    l23.connect(b3)

    return m
示例#10
0
def test_run_empty():
    # empty model should raise an exception if run
    model = Model()
    with pytest.raises(ModelStructureError):
        model.run()
示例#11
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)
示例#12
0
    result = model.step()
    assert_allclose(supply1.flow, 15.0, atol=1e-7)
    assert_allclose(supply2.flow, 15.0, atol=1e-7)
    assert_allclose(demand1.flow, 30.0, atol=1e-7)


def test_run_bottleneck():
    '''Test max flow constraint on intermediate nodes is upheld'''
    model = load_model('bottleneck.json')
    result = model.step()
    d1 = model.nodes['demand1']
    d2 = model.nodes['demand2']
    assert_allclose(d1.flow + d2.flow, 15.0, atol=1e-7)


@pytest.mark.skipif(Model().solver.name == "glpk-edge",
                    reason="Not valid for GLPK Edge based solver.")
def test_run_discharge_upstream():
    '''Test river with inline discharge (upstream)

    In this instance the discharge is upstream of the abstraction, and so can
    be abstracted in the same way as the water from the catchment
    '''
    model = load_model('river_discharge1.json')
    model.step()
    demand = model.nodes['demand1']
    term = model.nodes['term1']
    assert_allclose(demand.flow, 8.0, atol=1e-7)
    assert_allclose(term.flow, 0.0, atol=1e-7)

示例#13
0
    demand1.max_flow = 40.0
    result = model.step()
    assert_allclose(supply1.flow, 15.0, atol=1e-7)
    assert_allclose(supply2.flow, 15.0, atol=1e-7)
    assert_allclose(demand1.flow, 30.0, atol=1e-7)


def test_run_bottleneck():
    '''Test max flow constraint on intermediate nodes is upheld'''
    model = load_model('bottleneck.json')
    result = model.step()
    d1 = model.nodes['demand1']
    d2 = model.nodes['demand2']
    assert_allclose(d1.flow+d2.flow, 15.0, atol=1e-7)

@pytest.mark.skipif(Model().solver.name == "glpk-edge", reason="Not valid for GLPK Edge based solver.")
def test_run_discharge_upstream():
    '''Test river with inline discharge (upstream)

    In this instance the discharge is upstream of the abstraction, and so can
    be abstracted in the same way as the water from the catchment
    '''
    model = load_model('river_discharge1.json')
    model.step()
    demand = model.nodes['demand1']
    term = model.nodes['term1']
    assert_allclose(demand.flow, 8.0, atol=1e-7)
    assert_allclose(term.flow, 0.0, atol=1e-7)

@pytest.mark.skipif(Model().solver.name == "glpk-edge", reason="Not valid for GLPK Edge based solver.")
def test_run_discharge_downstream():
示例#14
0
def pytest_report_header(config):
    headers = []
    solver_name = Model().solver.name
    headers.append('solver: {}'.format(solver_name))
    return '\n'.join(headers)
示例#15
0
def test_select_solver():
    """Test specifying the solver in JSON"""
    solver_names = [solver.name for solver in pywr.solvers.solver_registry]
    for solver_name in solver_names:
        data = '''{"metadata": {"minimum_version": "0.1"}, "nodes": {}, "edges": {}, "timestepper": {"start": "1990-01-01","end": "1999-12-31","timestep": 1}, "solver": {"name": "%s"}}''' % solver_name
        model = load_model(data=data)
        assert (model.solver.name.lower() == solver_name)


def test_solver_unrecognised():
    '''Test specifying an unrecognised solver JSON'''
    solver_name = 'foobar'
    data = '''{"metadata": {"minimum_version": "0.1"}, "nodes": {}, "edges": {}, "timestepper": {"start": "1990-01-01","end": "1999-12-31","timestep": 1}, "solver": {"name": "%s"}}''' % solver_name
    with pytest.raises(KeyError):
        model = load_model(data=data)


@pytest.mark.skipif(Model().solver.name != "glpk",
                    reason="only valid for glpk")
@pytest.mark.parametrize("use_presolve", ["true", "false"])
def test_select_glpk_presolve(use_presolve):
    """Test specifying the solver in JSON"""
    solver_names = ["glpk"]
    for solver_name in solver_names:
        data = '''{"metadata": {"minimum_version": "0.1"}, "nodes": {}, "edges": {}, "timestepper": {"start": "1990-01-01","end": "1999-12-31","timestep": 1}, "solver": {"name": "%s", "use_presolve": %s}}''' % (
            solver_name, use_presolve)
        model = load_model(data=data)
        assert (model.solver.name.lower() == solver_name)
        assert (model.solver._cy_solver.use_presolve == (
            use_presolve == "true"))
示例#16
0
    result = model.step()
    assert_allclose(supply1.flow, 15.0, atol=1e-7)
    assert_allclose(supply2.flow, 15.0, atol=1e-7)
    assert_allclose(demand1.flow, 30.0, atol=1e-7)


def test_run_bottleneck():
    """Test max flow constraint on intermediate nodes is upheld"""
    model = load_model("bottleneck.json")
    result = model.step()
    d1 = model.nodes["demand1"]
    d2 = model.nodes["demand2"]
    assert_allclose(d1.flow + d2.flow, 15.0, atol=1e-7)


@pytest.mark.skipif(Model().solver.name == "glpk-edge",
                    reason="Not valid for GLPK Edge based solver.")
def test_run_discharge_upstream():
    """Test river with inline discharge (upstream)

    In this instance the discharge is upstream of the abstraction, and so can
    be abstracted in the same way as the water from the catchment
    """
    model = load_model("river_discharge1.json")
    model.step()
    demand = model.nodes["demand1"]
    term = model.nodes["term1"]
    assert_allclose(demand.flow, 8.0, atol=1e-7)
    assert_allclose(term.flow, 0.0, atol=1e-7)