Skip to content

Commit

Permalink
Merge 95a2747 into 7c5a6a0
Browse files Browse the repository at this point in the history
  • Loading branch information
kbonney committed Nov 20, 2023
2 parents 7c5a6a0 + 95a2747 commit 02ccf1d
Show file tree
Hide file tree
Showing 8 changed files with 813 additions and 269 deletions.
42 changes: 42 additions & 0 deletions wntr/network/controls.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,25 @@ def __init__(self):
def _reset(self):
pass

def _shift(self, value):
"""
Shift any SimTimeConditions within larger condition rules by value seconds (backward).
I.e., if a control is scheduled at simulation time 7200 and you shift by 3600, the new
control threshold with be sim time 3600.
Parameters
----------
value : float
seconds to subtract from threshold
Returns
-------
bool
is this still a valid control?
"""
return True

@abc.abstractmethod
def requires(self):
"""
Expand Down Expand Up @@ -585,6 +604,13 @@ def _compare(self, other):
return False
return True

def _shift(self, value):
self._threshold -= value
if self._threshold >= 0:
return True
self._threshold = 0
return False

@property
def name(self):
if not self._repeat:
Expand Down Expand Up @@ -996,6 +1022,11 @@ def _reset(self):
self._condition_1._reset()
self._condition_2._reset()

def _shift(self, value):
success1 = self._condition_1._shift(value)
success2 = self._condition_2._shift(value)
return success1 or success2

def _compare(self, other):
"""
Parameters
Expand Down Expand Up @@ -1062,6 +1093,11 @@ def _reset(self):
self._condition_1._reset()
self._condition_2._reset()

def _shift(self, value):
success1 = self._condition_1._shift(value)
success2 = self._condition_2._shift(value)
return success1 or success2

def _compare(self, other):
"""
Parameters
Expand Down Expand Up @@ -2012,6 +2048,9 @@ def epanet_control_type(self):
control_type: _ControlType
"""
return self._control_type

def _shift(self, step):
return self._condition._shift(step)

def requires(self):
req = self._condition.requires()
Expand Down Expand Up @@ -2177,6 +2216,9 @@ def __init__(self, condition, then_action: BaseControlAction, priority=ControlPr
else:
self._control_type = _ControlType.postsolve

def _shift(self, step):
return self._condition._shift(step)

@classmethod
def _time_control(cls, wnm, run_at_time, time_flag, daily_flag, control_action, name=None):
"""
Expand Down
132 changes: 132 additions & 0 deletions wntr/network/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -1552,7 +1552,139 @@ def reset_initial_values(self):
for name, control in self.controls():
control._reset()

def set_initial_conditions(self, results, ts=None, remove_controls=True, warn=False):
"""
Set the initial conditions of the network based on prior simulation results.
Parameters
----------
results : SimulationResults
Results from a prior simulation
ts : int, optional
The time value (in seconds) from the results to use to select initial conditions,
by default None (which will use the final values)
remove_controls : bool, optional
If a rule or control has a SimTimeCondition that now occurs prior to simulation start, remove
the control, by default True.
warn : bool
Send a warning to the logger that the rule has been deleted, by default False.
When False, information is sent to the logger at the `info` level.
Returns
-------
list
Control names that have been, when `remove_controls is True`,
or need to be, when `remove_controls is False`,
removed from the water network model
Raises
------
NameError
If both `ts` and `idx` are passed in
IndexError
If `ts` is passed, but no such time exists in the results
ValueError
If the time selected is not a multiple of the pattern timestep
"""
if ts is None:
end_time = results.node['demand'].index[-1]
else:
ts = int(ts)
if ts in results.node['demand'].index:
end_time = ts
else:
raise IndexError('There is no time "{}" in the results'.format(ts))

# if end_time / self.options.time.pattern_timestep != end_time // self.options.time.pattern_timestep:
# raise ValueError('You must give a time step that is a multiple of the pattern_timestep ({})'.format(self.options.time.pattern_timestep))

self.sim_time = 0.0
self._prev_sim_time = None

for name, node in self.nodes(Junction):
node._head = None
node._demand = None
node._pressure = None
try: node.initial_quality = float(results.node['quality'].loc[end_time, name])
except KeyError: pass
node._leak_demand = None
node._leak_status = False
node._is_isolated = False

for name, node in self.nodes(Tank):
node._head = None
node._demand = None
node._pressure = None
node.init_level = float(results.node['head'].loc[end_time, name] - node.elevation)
try: node.initial_quality = float(results.node['quality'].loc[end_time, name])
except KeyError: pass
node._prev_head = node.head
node._leak_demand = None
node._leak_status = False
node._is_isolated = False

for name, node in self.nodes(Reservoir):
node._head = None
node._demand = None
node._pressure = None
try: node.initial_quality = float(results.node['quality'].loc[end_time, name])
except KeyError: pass
node._leak_demand = None
node._is_isolated = False

for name, link in self.links(Pipe):
link.initial_status = results.link['status'].loc[end_time, name]
try: link.initial_setting = results.link['setting'].loc[end_time, name]
except KeyError: link.initial_setting = link.setting
link._user_status = link.initial_status
link._internal_status = LinkStatus.Active
link._is_isolated = False
link._flow = None
link._prev_setting = None

for name, link in self.links(Pump):
link.initial_status = results.link['status'].loc[end_time, name]
try: link.initial_setting = results.link['setting'].loc[end_time, name]
except KeyError: link.initial_setting = link.setting
link._user_status = link.initial_status
link._setting = link.initial_setting
link._internal_status = LinkStatus.Active
link._is_isolated = False
link._flow = None
if isinstance(link, PowerPump):
link.power = link._base_power
link._prev_setting = None

for name, link in self.links(Valve):
link.initial_status = results.link['status'].loc[end_time, name]
try: link.initial_setting = results.link['setting'].loc[end_time, name]
except KeyError: link.initial_setting = link.setting
# print(name, link.initial_status, link.initial_setting)
link._user_status = link.initial_status
link._setting = link.initial_setting
link._internal_status = LinkStatus.Active
link._is_isolated = False
link._flow = None
link._prev_setting = None

to_delete = []
for name, control in self.controls():
control._reset()
still_good = control._shift(end_time)
if not still_good:
to_delete.append(name)

for name in to_delete:
msg = 'Rule {} {} removed from the network'.format(name, 'has been' if remove_controls else 'needs to be')
if warn: logger.warning(msg)
else: logger.info(msg)
if remove_controls:
self.remove_control(name)
return to_delete
class PatternRegistry(Registry):
"""A registry for patterns."""

Expand Down

0 comments on commit 02ccf1d

Please sign in to comment.