Beispiel #1
0
    def test_with_nonstorage_load(self, model):
        """ Test load from dict with 'storage_node' key. """
        m = model
        m.scenarios.setup()
        s = Storage(m, 'Storage', max_volume=100.0)
        l = Link(m, 'Link')

        data = {
            "type": "controlcurve",
            "control_curve": 0.8,
            "values": [10.0, 0.0],
            "storage_node": "Storage"
        }

        l.cost = p = load_parameter(model, data)
        assert isinstance(p, ControlCurveParameter)

        s.setup(m)  # Init memory view on storage (bypasses usual `Model.setup`)
        si = ScenarioIndex(0, np.array([0], dtype=np.int32))
        print(s.volume)
        assert_allclose(l.get_cost(m.timestepper.current, si), 0.0)
        # When storage volume changes, the cost of the link changes.
        s.initial_volume = 90.0
        m.reset()
        assert_allclose(l.get_cost(m.timestepper.current, si), 10.0)
Beispiel #2
0
    def test_with_nonstorage_load(self, model):
        """Test load from dict with 'storage_node' key."""
        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)

        data = {
            "type": "controlcurve",
            "control_curve": 0.8,
            "values": [10.0, 0.0],
            "storage_node": "Storage",
        }

        l.cost = p = load_parameter(model, data)
        assert isinstance(p, ControlCurveParameter)

        @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()
Beispiel #3
0
    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()
Beispiel #4
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=1.0)
    C = Output(model, name="C", max_flow=5.0, cost=-2.0)

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

    return model
Beispiel #5
0
def simple_linear_model(request, solver):
    """
    Make a simple model with a single Input and Output.

    Input -> Link -> Output

    """
    model = Model(solver=solver)
    inpt = Input(model, name="Input")
    lnk = Link(model, name="Link", cost=1.0)
    inpt.connect(lnk)
    otpt = Output(model, name="Output")
    lnk.connect(otpt)

    return model
Beispiel #6
0
    def test_with_nonstorage_load(self, model):
        """ Test load from dict with 'storage_node' key. """
        m = model
        s = m.nodes['Storage']
        l = Link(m, 'Link')

        data = {
            "type": "controlcurve",
            "control_curve": 0.8,
            "values": [10.0, 0.0],
            "storage_node": "Storage"
        }

        l.cost = p = load_parameter(model, data)
        assert isinstance(p, ControlCurveParameter)

        @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()
Beispiel #7
0
def test_daily_profile_control_curve(simple_linear_model):
    """ Test `DailyProfileControlCurveParameter` """
    model = simple_linear_model
    s = Storage(model, 'Storage', max_volume=100.0)
    l = Link(model, 'Link2')

    data = {
        'type': 'dailyprofilecontrolcurve',
        'control_curves': [0.8, 0.6],
        'values': [[1.0] * 366, [0.7] * np.arange(366), [0.3] * 366],
        'storage_node': 'Storage'
    }

    l.max_flow = p = load_parameter(model, data)
    model.setup()

    @assert_rec(model, p)
    def expected_func(timestep, scenario_index):
        v = s.initial_volume
        doy = timestep.dayofyear
        if v >= 80.0:
            expected = 1.0
        elif v >= 60:
            expected = 0.7 * (doy - 1)
        else:
            expected = 0.3

        return expected

    for initial_volume in (90, 70, 30):
        s.initial_volume = initial_volume
        model.run()
Beispiel #8
0
def test_scaled_profile_nested_load(model):
    """ Test `ScaledProfileParameter` loading with `AggregatedParameter` """

    s = Storage(model, 'Storage', max_volume=100.0)
    l = Link(model, 'Link')
    data = {
        'type': 'scaledprofile',
        'scale': 50.0,
        'profile': {
            'type':
            'aggregated',
            'agg_func':
            'product',
            'parameters': [{
                'type': 'monthlyprofile',
                'values': [0.5] * 12
            }, {
                'type':
                'monthlyprofilecontrolcurve',
                'control_curves': [0.8, 0.6],
                'values': [[1.0] * 12, [0.7] * np.arange(12), [0.3] * 12],
                'storage_node':
                'Storage'
            }]
        }
    }

    l.max_flow = p = load_parameter(model, data)

    p.setup(model)

    # Test correct aggregation is performed
    model.scenarios.setup()
    s.setup(
        model)  # Init memory view on storage (bypasses usual `Model.setup`)

    s.initial_volume = 90.0
    model.reset()  # Set initial volume on storage
    si = ScenarioIndex(0, np.array([0], dtype=np.int32))
    for mth in range(1, 13):
        ts = Timestep(datetime.datetime(2016, mth, 1), 366, 1.0)
        np.testing.assert_allclose(p.value(ts, si), 50.0 * 0.5 * 1.0)

    s.initial_volume = 70.0
    model.reset()  # Set initial volume on storage
    si = ScenarioIndex(0, np.array([0], dtype=np.int32))
    for mth in range(1, 13):
        ts = Timestep(datetime.datetime(2016, mth, 1), 366, 1.0)
        np.testing.assert_allclose(p.value(ts, si),
                                   50.0 * 0.5 * 0.7 * (mth - 1))

    s.initial_volume = 30.0
    model.reset()  # Set initial volume on storage
    si = ScenarioIndex(0, np.array([0], dtype=np.int32))
    for mth in range(1, 13):
        ts = Timestep(datetime.datetime(2016, mth, 1), 366, 1.0)
        np.testing.assert_allclose(p.value(ts, si), 50.0 * 0.5 * 0.3)
Beispiel #9
0
    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
        m.scenarios.setup()
        s = Storage(m, 'Storage', max_volume=100.0)

        l = Link(m, 'Link')
        cc = ConstantParameter(0.8)
        l.cost = ControlCurveParameter(s, cc, [10.0, 0.0])

        s.setup(m)  # Init memory view on storage (bypasses usual `Model.setup`)
        print(s.volume)
        si = ScenarioIndex(0, np.array([0], dtype=np.int32))
        assert_allclose(l.get_cost(m.timestepper.current, si), 0.0)
        # When storage volume changes, the cost of the link changes.
        s.initial_volume = 90.0
        m.reset()
        print(s.volume)
        assert_allclose(l.get_cost(m.timestepper.current, si), 10.0)
Beispiel #10
0
    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')
        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()
Beispiel #11
0
    def test_no_scale_no_profile(self, simple_linear_model):
        """ No scale or profile specified """
        model = simple_linear_model
        s = Storage(model, 'Storage', max_volume=100.0)
        l = Link(model, 'Link2')

        data = {
            'type': 'monthlyprofilecontrolcurve',
            'control_curves': [0.8, 0.6],
            'values': [[1.0] * 12, [0.7] * np.arange(12), [0.3] * 12],
            'storage_node': 'Storage'
        }

        l.max_flow = p = load_parameter(model, data)
        self._assert_results(model, s, p)
Beispiel #12
0
    def test_scale_no_profile(self, simple_linear_model):
        """ Test `MonthlyProfileControlCurveParameter` """
        model = simple_linear_model
        s = Storage(model, 'Storage', max_volume=100.0)
        l = Link(model, 'Link2')

        data = {
            'type': 'monthlyprofilecontrolcurve',
            'control_curves': [0.8, 0.6],
            'values': [[1.0] * 12, [0.7] * np.arange(12), [0.3] * 12],
            'storage_node': 'Storage',
            'scale': 1.5
        }

        l.max_flow = p = load_parameter(model, data)
        model.setup()
        self._assert_results(model, s, p, scale=1.5)
Beispiel #13
0
    def test_no_scale_profile(self, model):
        """ No scale, but profile array specified """

        s = Storage(model, 'Storage', max_volume=100.0)
        l = Link(model, 'Link')

        data = {
            'type': 'monthlyprofilecontrolcurve',
            'control_curves': [0.8, 0.6],
            'values': [[1.0] * 12, [0.7] * np.arange(12), [0.3] * 12],
            'storage_node': 'Storage',
            'profile': [1.5]*12
        }

        l.max_flow = p = load_parameter(model, data)
        p.setup(model)
        model.scenarios.setup()
        self._assert_results(model, s, p, scale=1.5)
Beispiel #14
0
def test_daily_profile_control_curve(model):
    """ Test `DailyProfileControlCurveParameter` """

    s = Storage(model, 'Storage', max_volume=100.0)
    l = Link(model, 'Link')

    data = {
        'type': 'dailyprofilecontrolcurve',
        'control_curves': [0.8, 0.6],
        'values': [[1.0]*366, [0.7]*np.arange(366), [0.3]*366],
        'storage_node': 'Storage'
    }

    l.max_flow = p = load_parameter(model, data)
    p.setup(model)

    # Test correct aggregation is performed
    model.scenarios.setup()
    s.setup(model)  # Init memory view on storage (bypasses usual `Model.setup`)

    s.initial_volume = 90.0
    model.reset()  # Set initial volume on storage
    si = ScenarioIndex(0, np.array([0], dtype=np.int32))
    for mth in range(1, 13):
        ts = Timestep(datetime.datetime(2016, mth, 1), 366, 1.0)
        np.testing.assert_allclose(p.value(ts, si), 1.0)

    s.initial_volume = 70.0
    model.reset()  # Set initial volume on storage
    si = ScenarioIndex(0, np.array([0], dtype=np.int32))
    for mth in range(1, 13):
        ts = Timestep(datetime.datetime(2016, mth, 1), 366, 1.0)
        doy = ts.datetime.dayofyear
        np.testing.assert_allclose(p.value(ts, si), 0.7*(doy - 1))

    s.initial_volume = 30.0
    model.reset()  # Set initial volume on storage
    si = ScenarioIndex(0, np.array([0], dtype=np.int32))
    for mth in range(1, 13):
        ts = Timestep(datetime.datetime(2016, mth, 1), 366, 1.0)
        np.testing.assert_allclose(p.value(ts, si), 0.3)
Beispiel #15
0
        'id': link_id,
        'node_1_id': node_1_id,
        'node_2_id': node_2_id,
        'from_slot': node_lookup_id[node_1_id]['connect_out'] - 1,
        'to_slot': node_lookup_id[node_2_id]['connect_in'] - 1
    }
    link_lookup_id[link_id] = {
        'name': link['name'],
        'type': link['types'][0]['name'],
        'node_1_id': node_1_id,
        'node_2_id': node_2_id,
        'from_slot': node_lookup_id[node_1_id]['connect_out'] - 1,
        'to_slot': node_lookup_id[node_2_id]['connect_in'] - 1,
        'attributes': link['attributes']
    }
    pywr_links[link_id] = Link(model, name=name)

#  remove unconnected (rogue) nodes from analysis
connected_nodes = []
for link_id, trait in link_lookup_id.items():
    connected_nodes.append(trait['node_1_id'])
    connected_nodes.append(trait['node_2_id'])
rogue_nodes = []
for node in node_lookup_id:
    if node not in connected_nodes:
        rogue_nodes.append(node)
for node in rogue_nodes:
    del node_lookup_id[node]

# create pywr nodes dictionary with format ["name" = pywr type + 'name']
# separate non_storage dicts for greater flexibility with recording model results
Beispiel #16
0
def create_model(harmonic=True):
    # import flow timeseries for catchments
    flow = pd.read_csv(os.path.join('data', 'thames_stochastic_flow.gz'))

    flow['Date'] = flow['Date'].apply(pd.to_datetime)
    flow.set_index('Date', inplace=True)
    # resample input to weekly average
    flow = flow.resample('7D', how='mean')

    model = InspyredOptimisationModel(
        solver='glpk',
        start=flow.index[0],
        end=flow.index[365*10],  # roughly 10 years
        timestep=datetime.timedelta(7),  # weekly time-step
    )

    flow_parameter = ArrayIndexedParameter(model, flow['flow'].values)

    catchment1 = Input(model, 'catchment1', min_flow=flow_parameter, max_flow=flow_parameter)
    catchment2 = Input(model, 'catchment2', min_flow=flow_parameter, max_flow=flow_parameter)

    reservoir1 = Storage(model, 'reservoir1', min_volume=3000, max_volume=20000, initial_volume=16000)
    reservoir2 = Storage(model, 'reservoir2', min_volume=3000, max_volume=20000, initial_volume=16000)

    if harmonic:
        control_curve = AnnualHarmonicSeriesParameter(model, 0.5, [0.5], [0.0], mean_upper_bounds=1.0, amplitude_upper_bounds=1.0)
    else:
        control_curve = MonthlyProfileParameter(model, np.array([0.0]*12), lower_bounds=0.0, upper_bounds=1.0)

    control_curve.is_variable = True
    controller = ControlCurveParameter(model, reservoir1, control_curve, [0.0, 10.0])
    transfer = Link(model, 'transfer', max_flow=controller, cost=-500)

    demand1 = Output(model, 'demand1', max_flow=45.0, cost=-101)
    demand2 = Output(model, 'demand2', max_flow=20.0, cost=-100)

    river1 = Link(model, 'river1')
    river2 = Link(model, 'river2')

    # compensation flows from reservoirs
    compensation1 = Link(model, 'compensation1', max_flow=5.0, cost=-9999)
    compensation2 = Link(model, 'compensation2', max_flow=5.0, cost=-9998)

    terminator = Output(model, 'terminator', cost=1.0)

    catchment1.connect(reservoir1)
    catchment2.connect(reservoir2)
    reservoir1.connect(demand1)
    reservoir2.connect(demand2)
    reservoir2.connect(transfer)
    transfer.connect(reservoir1)
    reservoir1.connect(river1)
    reservoir2.connect(river2)
    river1.connect(terminator)
    river2.connect(terminator)

    reservoir1.connect(compensation1)
    reservoir2.connect(compensation2)
    compensation1.connect(terminator)
    compensation2.connect(terminator)

    r1 = TotalDeficitNodeRecorder(model, demand1)
    r2 = TotalDeficitNodeRecorder(model, demand2)
    r3 = AggregatedRecorder(model, [r1, r2], agg_func="mean")
    r3.is_objective = 'minimise'
    r4 = TotalFlowNodeRecorder(model, transfer)
    r4.is_objective = 'minimise'

    return model