Exemple #1
0
def test_dynamic_factors_load(model):

    model.timestepper.end = Timestamp("2016-01-03")

    A = Input(model, "A", max_flow=10.0)
    B = Input(model, "B", max_flow=10.0)
    Z = Output(model, "Z", cost=-10, max_flow=10.0)

    A.connect(Z)
    B.connect(Z)

    DailyProfileParameter(model,
                          np.append(np.array([3, 4]), np.ones(364)),
                          name="factor1")

    data = {"name": "agg", "factors": [1, "factor1"], "nodes": ["A", "B"]}

    AggregatedNode.load(data, model)

    model.step()

    assert_allclose(A.flow, 2.5)
    assert_allclose(B.flow, 7.5)

    model.step()

    assert_allclose(A.flow, 2)
    assert_allclose(B.flow, 8)
Exemple #2
0
def test_aggregated_node_two_factors_time_varying(model):
    """Nodes constrained by a time-varying ratio between flows (2 nodes)"""
    model.timestepper.end = Timestamp("2016-01-03")

    A = Input(model, "A")
    B = Input(model, "B", max_flow=40.0)
    Z = Output(model, "Z", max_flow=100, cost=-10)

    agg = AggregatedNode(model, "agg", [A, B])
    agg.factors = [0.5, 0.5]
    assert_allclose(agg.factors, [0.5, 0.5])

    A.connect(Z)
    B.connect(Z)

    model.setup()
    model.step()

    assert_allclose(agg.flow, 80.0)
    assert_allclose(A.flow, 40.0)
    assert_allclose(B.flow, 40.0)

    agg.factors = [1.0, 2.0]

    model.step()

    assert_allclose(agg.flow, 60.0)
    assert_allclose(A.flow, 20.0)
    assert_allclose(B.flow, 40.0)
Exemple #3
0
def test_dynamic_factors(model):

    model.timestepper.end = Timestamp("2016-01-03")

    A = Input(model, "A", max_flow=10.0)
    B = Input(model, "B", max_flow=10.0)
    C = Input(model, "C", max_flow=10.0)
    Z = Output(model, "Z", cost=-10)

    agg = AggregatedNode(model, "agg", [A, B, C])
    agg.max_flow = 10.0
    factor1 = DailyProfileParameter(
        model, np.append(np.array([0.8, 0.3]), np.ones(364)))
    factor2 = DailyProfileParameter(
        model, np.append(np.array([0.1, 0.3]), np.ones(364)))
    factor3 = DailyProfileParameter(
        model, np.append(np.array([0.1, 0.4]), np.ones(364)))

    agg.factors = [factor1, factor2, factor3]

    A.connect(Z)
    B.connect(Z)
    C.connect(Z)

    model.step()

    assert_allclose(A.flow, 8)
    assert_allclose(B.flow, 1)
    assert_allclose(C.flow, 1)

    model.step()

    assert_allclose(A.flow, 3)
    assert_allclose(B.flow, 3)
    assert_allclose(C.flow, 4)
Exemple #4
0
    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)
Exemple #5
0
    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)
Exemple #6
0
def test_aggregated_node_min_flow_parameter(model):
    """Nodes constrained by the min_flow of their AggregatedNode"""
    A = Input(model, "A", max_flow=20.0, cost=1)
    B = Input(model, "B", max_flow=20.0, cost=100)
    Z = Output(model, "Z", max_flow=100, cost=0)

    A.connect(Z)
    B.connect(Z)

    agg = AggregatedNode(model, "agg", [A, B])
    agg.min_flow = ConstantParameter(model, 15.0)

    model.run()

    assert_allclose(agg.flow, 15.0)
    assert_allclose(A.flow, 15.0)
    assert_allclose(B.flow, 0.0)
Exemple #7
0
def test_aggregated_node_max_flow(model):
    """Nodes constrained by the max_flow of their AggregatedNode"""
    A = Input(model, "A", max_flow=20.0, cost=1)
    B = Input(model, "B", max_flow=20.0, cost=2)
    Z = Output(model, "Z", max_flow=100, cost=-10)

    A.connect(Z)
    B.connect(Z)

    agg = AggregatedNode(model, "agg", [A, B])
    agg.max_flow = 30.0

    model.run()

    assert_allclose(agg.flow, 30.0)
    assert_allclose(A.flow, 20.0)
    assert_allclose(B.flow, 10.0)
Exemple #8
0
def test_aggregated_node_two_factors(model):
    """Nodes constrained by a fixed ratio between flows (2 nodes)"""
    A = Input(model, "A")
    B = Input(model, "B", max_flow=40.0)
    Z = Output(model, "Z", max_flow=100, cost=-10)

    agg = AggregatedNode(model, "agg", [A, B])
    agg.factors = [0.5, 0.5]
    assert_allclose(agg.factors, [0.5, 0.5])

    A.connect(Z)
    B.connect(Z)

    model.run()

    assert_allclose(agg.flow, 80.0)
    assert_allclose(A.flow, 40.0)
    assert_allclose(B.flow, 40.0)
Exemple #9
0
def test_aggregated_node_max_flow_with_weights(model, flow_weights, expected_agg_flow, expected_A_flow, expected_B_flow):
    """Nodes constrained by the weighted max_flow of their AggregatedNode"""
    A = Input(model, "A", max_flow=20.0, cost=1)
    B = Input(model, "B", max_flow=20.0, cost=8)
    Z = Output(model, "Z", max_flow=100, cost=-10)

    A.connect(Z)
    B.connect(Z)

    agg = AggregatedNode(model, "agg", [A, B])
    agg.flow_weights = flow_weights
    agg.max_flow = 30.0

    model.run()

    assert_allclose(agg.flow, expected_agg_flow)
    assert_allclose(A.flow, expected_A_flow)
    assert_allclose(B.flow, expected_B_flow)
Exemple #10
0
def test_aggregated_node_max_flow_same_route(model):
    """Unusual case where the aggregated nodes are in the same route"""
    A = Input(model, "A", max_flow=20.0, cost=1)
    B = Input(model, "B", max_flow=20.0, cost=2)
    C = Input(model, "C", max_flow=50.0, cost=0)
    Z = Output(model, "Z", max_flow=100, cost=-10)

    A.connect(B)
    B.connect(Z)
    C.connect(Z)

    agg = AggregatedNode(model, "agg", [A, B])
    agg.max_flow = 30.0

    model.run()

    assert_allclose(agg.flow, 30.0)
    assert_allclose(A.flow + B.flow, 30.0)
def test_piecewise_constraint(model, flow):
    """Test using an aggregated node constraint in combination with a
    piecewise link in order to create a minimum flow constraint of the form
    y = mx + c, where y is the MRF, x is the upstream flow and m and c are
    constants.

    Flows are tested at 100, 200 and 300 to ensure the aggregated ratio works
    when there is too much to route entirely through to node 'D'.

    ::

                 / -->-- X0 -->-- \
        A -->-- Xo -->-- X1 -->-- Xi -->-- C
                 \\ -->-- X2 -->-- /
                         |
                         Bo -->-- Bi --> D
    """
    A = Input(model, "A", min_flow=flow, max_flow=flow)
    X = PiecewiseLink(model,
                      name="X",
                      nsteps=3,
                      costs=[-500.0, 0, 0],
                      max_flows=[40.0, None, None])
    C = Output(model, "C")

    A.connect(X)
    X.connect(C)

    # create a new input inside the piecewise link which only has access
    # to flow travelling via the last sublink (X2)
    Bo = Output(model, "Bo", domain=X.sub_domain)
    Bi = Input(model, "Bi")
    D = Output(model, "D", max_flow=50, cost=-100)
    Bo.connect(Bi)
    Bi.connect(D)
    X.sublinks[-1].connect(Bo)

    agg = AggregatedNode(model, "agg", X.sublinks[1:])
    agg.factors = [3.0, 1.0]

    model.step()
    assert_allclose(D.flow, min((flow - 40) * 0.25, 50.0))
Exemple #12
0
def test_aggregated_node_two_factors(model):
    """Nodes constrained by a fixed ratio between flows (2 nodes)"""
    A = Input(model, "A")
    B = Input(model, "B", max_flow=40.0)
    Z = Output(model, "Z", max_flow=100, cost=-10)

    agg = AggregatedNode(model, "agg", [A, B])
    agg.factors = [0.5, 0.5]

    for f in agg.factors:
        assert isinstance(f, ConstantParameter)
        assert_allclose(f.get_double_variables(), 0.5)

    A.connect(Z)
    B.connect(Z)

    model.run()
    assert_allclose(agg.flow, 80.0)
    assert_allclose(A.flow, 40.0)
    assert_allclose(B.flow, 40.0)
Exemple #13
0
def test_aggregated_node_three_factors(model):
    """Nodes constrained by a fixed ratio between flows (3 nodes)"""
    A = Input(model, "A")
    B = Input(model, "B", max_flow=10.0)
    C = Input(model, "C")
    Z = Output(model, "Z", max_flow=100, cost=-10)

    agg = AggregatedNode(model, "agg", [A, B, C])
    agg.factors = [0.5, 1.0, 2.0]
    assert_allclose(agg.factors, [0.5, 1.0, 2.0])

    A.connect(Z)
    B.connect(Z)
    C.connect(Z)

    model.run()

    assert_allclose(agg.flow, 35.0)
    assert_allclose(A.flow, 5.0)
    assert_allclose(B.flow, 10.0)
    assert_allclose(C.flow, 20.0)
Exemple #14
0
    def test_routes(self, simple_linear_model, tmpdir):
        """
        Test the TablesRecorder

        """
        model = simple_linear_model
        otpt = model.nodes['Output']
        inpt = model.nodes['Input']
        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, routes_flows='flows')

            model.run()

            flows = h5f.get_node('/flows')
            assert flows.shape == (365, 1, 1)
            np.testing.assert_allclose(flows.read(), np.ones((365, 1, 1))*10)

            routes = h5f.get_node('/routes')
            assert routes.shape[0] == 1
            row = routes[0]
            row['start'] = "Input"
            row['end'] = "Output"

            from datetime import date, timedelta
            d = date(2015, 1, 1)
            time = h5f.get_node('/time')
            for i in range(len(model.timestepper)):
                row = time[i]
                assert row['year'] == d.year
                assert row['month'] == d.month
                assert row['day'] == d.day

                d += timedelta(1)

            scenarios = h5f.get_node('/scenarios')
            for s in model.scenarios.scenarios:
                row = scenarios[i]
                assert row['name'] == s.name
                assert row['size'] == s.size

            model.reset()
            model.run()

            time = h5f.get_node('/time')
            assert len(time) == len(model.timestepper)
Exemple #15
0
    def test_nodes(self, simple_linear_model, tmpdir):
        """
        Test the TablesRecorder

        """
        model = simple_linear_model
        otpt = model.nodes['Output']
        inpt = model.nodes['Input']
        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)

            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)

            from datetime import date, timedelta
            d = date(2015, 1, 1)
            time = h5f.get_node('/time')
            for i in range(len(model.timestepper)):
                row = time[i]
                assert row['year'] == d.year
                assert row['month'] == d.month
                assert row['day'] == d.day

                d += timedelta(1)

            scenarios = h5f.get_node('/scenarios')
            for i, s in enumerate(model.scenarios.scenarios):
                row = scenarios[i]
                assert row['name'] == s.name.encode('utf-8')
                assert row['size'] == s.size

            model.reset()
            model.run()

            time = h5f.get_node('/time')
            assert len(time) == len(model.timestepper)
Exemple #16
0
    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)
Exemple #17
0
def test_aggregated_node_three_factors(model):
    """Nodes constrained by a fixed ratio between flows (3 nodes)"""
    A = Input(model, "A")
    B = Input(model, "B", max_flow=10.0)
    C = Input(model, "C")
    Z = Output(model, "Z", max_flow=100, cost=-10)

    agg = AggregatedNode(model, "agg", [A, B, C])
    agg.factors = [0.5, 1.0, 2.0]

    for f, v in zip(agg.factors, [0.5, 1.0, 2.0]):
        assert isinstance(f, ConstantParameter)
        assert_allclose(f.get_double_variables(), v)

    A.connect(Z)
    B.connect(Z)
    C.connect(Z)

    model.run()

    assert_allclose(agg.flow, 35.0)
    assert_allclose(A.flow, 5.0)
    assert_allclose(B.flow, 10.0)
    assert_allclose(C.flow, 20.0)
Exemple #18
0
def three_storage_model(request):
    """
    Make a simple model with three input, storage and output nodes. Also adds
    an `AggregatedStorage` and `AggregatedNode`.

        Input 0 -> Storage 0 -> Output 0
        Input 1 -> Storage 1 -> Output 1
        Input 2 -> Storage 2 -> Output 2


    """

    model = pywr.core.Model(
        start=pandas.to_datetime('2016-01-01'),
        end=pandas.to_datetime('2016-01-05'),
        timestep=datetime.timedelta(1),
    )

    all_res = []
    all_otpt = []

    for num in range(3):
        inpt = Input(model,
                     name="Input {}".format(num),
                     max_flow=5.0 * num,
                     cost=-1)
        res = Storage(model,
                      name="Storage {}".format(num),
                      num_outputs=1,
                      num_inputs=1,
                      max_volume=20,
                      initial_volume=10 + num)
        otpt = Output(model,
                      name="Output {}".format(num),
                      max_flow=8 + num,
                      cost=-999)

        inpt.connect(res)
        res.connect(otpt)

        all_res.append(res)
        all_otpt.append(otpt)

    AggregatedStorage(model, name='Total Storage', storage_nodes=all_res)
    AggregatedNode(model, name='Total Output', nodes=all_otpt)
    return model
Exemple #19
0
    def test_create_directory(self, simple_linear_model, tmpdir):
        """ Test TablesRecorder to create a new directory """

        model = simple_linear_model
        otpt = model.nodes['Output']
        inpt = model.nodes['Input']
        agg_node = AggregatedNode(model, 'Sum', [otpt, inpt])

        inpt.max_flow = 10.0
        otpt.cost = -2.0
        # Make a path with a new directory
        folder = tmpdir.join('outputs')
        h5file = folder.join('output.h5')
        assert(not folder.exists())
        rec = TablesRecorder(model, str(h5file), create_directories=True)
        model.run()
        assert(folder.exists())
        assert(h5file.exists())