WaterStrategy
English
English
  • WaterStrategy Documentation
  • Support
  • Getting Started
    • Creating an Account
    • Logging In
    • Tour of WaterStrategy
    • Creating a new Project and Network
    • Sharing Projects and Networks
    • Exporting and Importing Models
    • Dealing with Model Errors
    • Uploading External Data
  • Modeling Basics
    • Water Resource System Modeling?
    • What is Pywr?
    • Pywr Concepts
    • Node Types
      • Water Input
        • Input Node
        • Catchment Node
        • Proportional Input Node
      • Water Transport
        • Link Node
        • River Node
        • Delay Node
        • RiverSplit Node
        • RiverSplitWithGauge Node
        • RiverGauge Node
        • BreakLink Node
        • PiecewiseLink Node
        • MultiSplitLink Node
      • Water Storage
        • Storage Node
        • Reservoir Node
        • VirtualStorage Node
        • RollingVirtualStorage Node
        • AnnualVirtualStorage Node
        • SeasonalVirtualStorage Node
        • AggregatedStorage Node
      • Water Output
        • Output Node
        • Loss Link Node
      • Hydropower
        • Turbine Node
      • Others
        • AggregatedNode
    • Allocation Penalties
    • Scenarios
      • WaterStrategy Scenarios
      • Pywr-Scenarios
        • Parameter and pywr-scenario Integration
    • Parameters
      • Base Parameter Class
        • Parameter
        • IndexParameter
      • Simple Parameters
        • Constant
        • Constant Scenario Parameter
        • Constant Scenario Index Parameter
      • Combining multiple parameters
        • Aggregated Parameter
        • Aggregated Index Parameter
        • Division Parameter
        • Negative Parameter
        • MaxParameter
        • Negative MaxParameter
        • MinParameter
        • Negative MinParameter
        • Offset Parameter
      • Time Series and Profiles
        • Daily Profile
        • Weekly Profile
        • Monthly Profile
        • Uniform Drawdown Profile
        • Scenario Daily Profile
        • Scenario Weekly Profile
        • Scenario Monthly Profile
        • Array Indexed Scenario Monthly Factors
        • RBF Profile
      • DataFrame Parameter
      • HDF5 Parameter
      • Array Based Parameters
        • Array Indexed Parameter
        • Array Indexed Scenario Parameter
        • Indexed Array Parameter
      • Threshold Parameters
        • Abstract Threshold
        • Storage Threshold
        • Node Threshold
        • Parameter Threshold
        • Recorder Threshold
        • Current Year Threshold
        • Current Ordinal Day Threshold
      • Interpolation Parameters
        • Interpolated Parameter
        • Interpolated Quadrature
        • Interpolated Flow
        • Interpolated Volume
      • Control Curve Parameters
        • Base Control Curve
        • Control Curve Interpolated Parameter
        • Control Curve Piecewise Interpolated Parameter
        • Control Curve Index Parameter
      • Hydropower Parameters
      • Others
        • Annual Harmonic Series Parameter
        • Deficit Parameter
        • Scenario Wrapper Parameter
        • Piecewise Integral Parameter
        • Flow Parameter
        • Flow Delay Parameter
        • Discount Factor Parameter
    • Recorders
      • Base Recorder
        • Recorder
        • Node Recorder
        • Storage Recorder
        • Parameter Recorder
        • Index Parameter Recorder
        • Aggregator
      • Numpy Array Recorders
        • Numpy Array Node Recorder
        • Numpy Array Storage Recorder
        • Numpy Array Level Recorder
        • Numpy Array Area Recorder
        • Numpy Array Parameter Recorder
        • Numpy Array Index Parameter Recorder
        • Numpy Array Daily Profile Parameter Recorder
      • Flow Duration Curve Recorders
        • Flow Duration Curve Recorder
        • Storage Duration Curve Recorder
        • Flow Duration Curve Deviation Recorder
        • Seasonal Flow Duration Curve Recorder
      • Deficit Recorders
        • Numpy Array Node Deficit Recorder
        • Numpy Array Node Supplied Ratio Recorder
        • Numpy Array Node Curtailment Ratio Recorder
        • Total Deficit Node Recorder
        • Deficit Frequency Node Recorder
      • Statistical Recorders
        • Aggregated Recorder
        • Mean Flow Node Recorder
        • Total Flow Node Recorder
        • Annual Total Flow Recorder
        • Mean Parameter Recorder
        • Total Parameter Recorder
        • Rolling Mean Flow Node Recorder
        • Minimum Volume Storage Recorder
        • Minimum Threshold Volume Storage Recorder
        • Timestep Count Index Parameter Recorder
        • Annual Count Index Threshold Recorder
        • Rolling Window Parameter Recorder
      • Index Recorders
        • Annual Count Index Parameter Recorder
      • File Recorders
        • CSV Recorder
        • Tables Recorder
      • Hydro-power Recorders
        • Hydropower Recorder
        • Total Hydro Energy Recorder
  • Applied Modeling
    • Reservoir and Storage Nodes
  • Tutorials
    • Creating and running a simple model
      • Creating and Running a Model
        • Setting up a Project and Network
        • Adding Nodes and Links (Edges)
        • Add Data to the Nodes
        • Setting the Time Horizon
        • Running the Model and Visualizing its Outputs
        • Creating a New Scenario
        • Exercise
      • Making Changes to a Model
        • Adding a Reservoir
        • Adding Basic Operating Rules
    • Modelling basin reservoir systems
      • Creating a New Project and Network
      • Adding a Dam (Reservoir)
      • Adding a Demand
      • Adding a Water Treatment Works with Losses
      • Adding a Source Representing Groundwater
      • Additional Exercises
      • Adding reservoir bathymetry, evaporation, and rainfall
        • Background on Evaporation and Precipitation on Reservoirs
        • Adding reservoir bathymetry (Area)
        • Adding reservoir bathymetry (Level)
        • Adding monthly evaporation and rainfall
      • Using allocation penalties and control rules to balance sources
      • Control Curves and Demand Savings
        • Adding reservoir control curves and demand savings (reductions)
    • Using Allocation Penalties to Allocate Water
      • Exercise 1a Two nodes
      • Exercise 1b Two demands
      • Exercise 1c Minimum Flow Properties
      • Exercise 2a Simple system with reservoir draw downs
      • Exercise 2b Simple system with overflow
    • Pywr-scenarios reading external DataFrame and adding Custom Rules
      • Uploading Files
      • Reading CSV DataFrame
      • Running pywr-scenarios
      • Reading h5 DataFrame for pywr-scenarios
      • Create Custom Rule - TranscientDecisionParameter
Powered by GitBook
On this page
  • Register Custom Rule - TranscientDecisionParameter
  • Using TranscientDecisionParameter
  • Results

Was this helpful?

Export as PDF
  1. Tutorials
  2. Pywr-scenarios reading external DataFrame and adding Custom Rules

Create Custom Rule - TranscientDecisionParameter

PreviousReading h5 DataFrame for pywr-scenarios

Last updated 7 months ago

Was this helpful?

Register Custom Rule - TranscientDecisionParameter

class TransientDecisionParameter(Parameter):
    """ Return one of two values depending on the current time-step

    This `Parameter` can be used to model a discrete decision event
     that happens at a given date. Prior to this date the `before`
     value is returned, and post this date the `after` value is returned.

    Parameters
    ----------
    decision_date : string or pandas.Timestamp
        The trigger date for the decision.
    before_parameter : Parameter
        The value to use before the decision date.
    after_parameter : Parameter
        The value to use after the decision date.
    earliest_date : string or pandas.Timestamp or None
        Earliest date that the variable can be set to. Defaults to `model.timestepper.start`
    latest_date : string or pandas.Timestamp or None
        Latest date that the variable can be set to. Defaults to `model.timestepper.end`
    decision_freq : pandas frequency string (default 'AS')
        The resolution of feasible dates. For example 'AS' would create feasible dates every
        year between `earliest_date` and `latest_date`. The `pandas` functions are used
        internally for delta date calculations.

    """

    def __init__(self, model, decision_date, before_parameter, after_parameter, earliest_date=None, latest_date=None, decision_freq='AS', **kwargs):
        super(TransientDecisionParameter, self).__init__(model, **kwargs)
        self._decision_date = None
        self.decision_date = decision_date

        if not isinstance(before_parameter, Parameter):
            raise ValueError('The `before` value should be a Parameter instance.')
        before_parameter.parents.add(self)
        self.before_parameter = before_parameter

        if not isinstance(after_parameter, Parameter):
            raise ValueError('The `after` value should be a Parameter instance.')
        after_parameter.parents.add(self)
        self.after_parameter = after_parameter

        # These parameters are mostly used if this class is used as variable.
        self._earliest_date = None
        self.earliest_date = earliest_date

        self._latest_date = None
        self.latest_date = latest_date

        self.decision_freq = decision_freq
        self._feasible_dates = None
        self.integer_size = 1  # This parameter has a single integer variable

    def decision_date():
        def fget(self):
            return self._decision_date

        def fset(self, value):
            if isinstance(value, pd.Timestamp):
                self._decision_date = value
            else:
                self._decision_date = pd.to_datetime(value)

        return locals()

    decision_date = property(**decision_date())

    def earliest_date():
        def fget(self):
            if self._earliest_date is not None:
                return self._earliest_date
            else:
                return self.model.timestepper.start

        def fset(self, value):
            if isinstance(value, pd.Timestamp):
                self._earliest_date = value
            else:
                self._earliest_date = pd.to_datetime(value)

        return locals()

    earliest_date = property(**earliest_date())

    def latest_date():
        def fget(self):
            if self._latest_date is not None:
                return self._latest_date
            else:
                return self.model.timestepper.end

        def fset(self, value):
            if isinstance(value, pd.Timestamp):
                self._latest_date = value
            else:
                self._latest_date = pd.to_datetime(value)

        return locals()

    latest_date = property(**latest_date())

    def setup(self):
        super(TransientDecisionParameter, self).setup()

        # Now setup the feasible dates for when this object is used as a variable.
        self._feasible_dates = pd.date_range(self.earliest_date, self.latest_date,
                                                 freq=self.decision_freq)

    def value(self, ts, scenario_index):

        if ts is None:
            v = self.before_parameter.get_value(scenario_index)
        elif ts.datetime >= self.decision_date:
            v = self.after_parameter.get_value(scenario_index)
        else:
            v = self.before_parameter.get_value(scenario_index)
        return v

    def get_integer_lower_bounds(self):
        return np.array([0, ], dtype=np.int)

    def get_integer_upper_bounds(self):
        return np.array([len(self._feasible_dates) - 1, ], dtype=np.int)

    def set_integer_variables(self, values):
        # Update the decision date with the corresponding feasible date
        self.decision_date = self._feasible_dates[values[0]]

    def get_integer_variables(self):
        return np.array([self._feasible_dates.get_loc(self.decision_date), ], dtype=np.int)

    def dump(self):

        data = {
            'earliest_date': self.earliest_date.isoformat(),
            'latest_date': self.latest_date.isoformat(),
            'decision_date': self.decision_date.isoformat(),
            'decision_frequency': self.decision_freq
        }

        return data

    @classmethod
    def load(cls, model, data):

        before_parameter = load_parameter(model, data.pop('before_parameter'))
        after_parameter = load_parameter(model, data.pop('after_parameter'))

        return cls(model, before_parameter=before_parameter, after_parameter=after_parameter, **data)

TransientDecisionParameter.register()

Now when running this network in WaterStrategy, a TranscientDecisionParameter will be registered.

Make sure after saving your Custom Rule, it is displayed on the left side, in this case under Parameter section

Using TranscientDecisionParameter

For this case, we will double the max volume of New Reservoir storage node starting on 2045-01-01

Go to New Reservoir storage node and Edit Max Volume

Select in Options tab PYWR_PARAMETER

Paste the following code and click Save

{
  	"type": "TransientDecisionParameter",
	"after_parameter": "__New reservoir__:max_volume after",
	"before_parameter": "__New reservoir__:max_volume before",
	"decision_date": "2045-01-01",
	"latest_date": "2045-01-01"
}

TranscientDecisionParameter includes attributes before_parameter and after_parameter which we will have to create as following:

A small text box will open, when we can write the name of our new PWR_PARAMETER, in this case __New reservoir__:max_volume before. Click Enter.

WaterStrategy will open the parameter window, paste the following code and Save

__New reservoir__:max_volume before:

{
	"type": "ConstantParameter",
	"value": 120000
}

Repeat to create the max volume after parameter

__New reservoir__:max_volume after:

{
	"type": "ConstantParameter",
	"value": 240000
}

As last step, TranscientDecisionParameter needs Initial Volume Proportion for the storage node as the parameter inherit initial values from the node, in this case we will setup to 0.99

Results

As we can see in the following picture, we are combining pywr-scenarios using Climate Change and increasing the volume of our selected reservoir from 120.000 Ml to 240.000 Ml in 1st january 2045.

Paste the following code and then click on the save button

simulated volume (New Reservoir)