Note: Before proceeding, clone the previous WaterStrategy scenario so you can compare the modifications applied during this step with the original configuration. This will allow you to assess the impact of changes made.
classTransientDecisionParameter(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_dateifnotisinstance(before_parameter, Parameter):raiseValueError('The `before` value should be a Parameter instance.') before_parameter.parents.add(self) self.before_parameter = before_parameterifnotisinstance(after_parameter, Parameter):raiseValueError('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 variabledefdecision_date():deffget(self):return self._decision_datedeffset(self,value):ifisinstance(value, pd.Timestamp): self._decision_date = valueelse: self._decision_date = pd.to_datetime(value)returnlocals() decision_date =property(**decision_date())defearliest_date():deffget(self):if self._earliest_date isnotNone:return self._earliest_dateelse:return self.model.timestepper.startdeffset(self,value):ifisinstance(value, pd.Timestamp): self._earliest_date = valueelse: self._earliest_date = pd.to_datetime(value)returnlocals() earliest_date =property(**earliest_date())deflatest_date():deffget(self):if self._latest_date isnotNone:return self._latest_dateelse:return self.model.timestepper.enddeffset(self,value):ifisinstance(value, pd.Timestamp): self._latest_date = valueelse: self._latest_date = pd.to_datetime(value)returnlocals() latest_date =property(**latest_date())defsetup(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)defvalue(self,ts,scenario_index):if ts isNone: 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 vdefget_integer_lower_bounds(self):return np.array([0, ], dtype=np.int)defget_integer_upper_bounds(self):return np.array([len(self._feasible_dates) -1, ], dtype=np.int)defset_integer_variables(self,values):# Update the decision date with the corresponding feasible date self.decision_date = self._feasible_dates[values[0]]defget_integer_variables(self):return np.array([self._feasible_dates.get_loc(self.decision_date), ], dtype=np.int)defdump(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@classmethoddefload(cls,model,data): before_parameter =load_parameter(model, data.pop('before_parameter')) after_parameter =load_parameter(model, data.pop('after_parameter'))returncls(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 TranscientDecisionParamete
In this case, we will assume that the Maguga Dam was initially constructed with a maximum storage volume of 250 million cubic meters (Mm³). A modification completed on January 1, 1980, allowed the reservoir to increase its maximum volume to 332 million cubic meters (Mm³). This historical change in capacity will be accounted for in the model, reflecting the expansion of the dam's storage capabilities over time.