Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
if abs(dh) > self.Htol:
if dh < -self.Htol:
return False
elif self._cv.flow < -self.Qtol:
return False
else:
return True
else:
return False
def __str__(self):
s = '{0} head - {1} head > {2} and {3} flow >= {4}'.format(self._start_node.name, self._end_node.name, self.Htol, self._cv.name, -self.Qtol)
return s
class _ClosePowerPumpCondition(ControlCondition):
"""
Prevents reverse flow in pumps.
"""
Htol = 0.0001524
Qtol = 2.83168e-6
Hmax = 1e10
def __init__(self, wn, pump):
"""
Parameters
----------
wn: wntr.network.WaterNetworkModel
pump: wntr.network.Pump
"""
self._pump = pump
self._start_node = wn.get_node(pump.start_node)
tatt = self._threshold_attr
fmt = "{}('{}').{} {} {}('{}').{}"
return fmt.format(typ, obj, att,
rel,
ttyp, tobj, tatt)
def evaluate(self):
cur_value = getattr(self._source_obj, self._source_attr)
thresh_value = getattr(self._threshold_obj, self._threshold_attr)
relation = self._relation.func
state = relation(cur_value, thresh_value)
return bool(state)
@DocInheritor({'requires', 'evaluate', 'backtrack'})
class OrCondition(ControlCondition):
"""Combine two WNTR Conditions with an OR.
Parameters
----------
cond1 : ControlCondition
The first condition
cond2 : ControlCondition
The second condition
"""
def __init__(self, cond1, cond2):
self._condition_1 = cond1
self._condition_2 = cond2
if isinstance(cond1, TankLevelCondition):
if cond1._relation is Comparison.eq:
elif self._relation is Comparison.lt and cur_time < self._threshold:
self._backtrack = 0
return True
elif self._relation is Comparison.le and cur_time <= self._threshold:
self._backtrack = 0
return True
elif self._relation is Comparison.le and prev_time < self._threshold:
self._backtrack = int(cur_time - self._threshold)
return True
else:
self._backtrack = 0
return False
@DocInheritor({'requires', 'evaluate', 'name'})
class ValueCondition(ControlCondition):
"""Compare a network element attribute to a set value.
Parameters
----------
source_obj : object
The object (such as a Junction, Tank, Pipe, etc.) to use in the comparison
source_attr : str
The attribute of the object (such as level, pressure, setting, etc.) to
compare against the threshold
operation : function or str
A two-parameter comparison function (e.g., numpy.greater, numpy.less_equal), or a
string describing the comparison (e.g., '=', 'below', 'is', '>=', etc.)
Words, such as 'below', are only accepted from the EPANET rules conditions list (see ...)
threshold : float
A value to compare the source object attribute against
"""
self._end_node = wn.get_node(self._fcv.end_node)
self._backtrack = 0
def requires(self):
return OrderedSet([self._fcv, self._start_node, self._end_node])
def evaluate(self):
if self._start_node.head - self._end_node.head < -self._Htol:
return True
elif self._fcv.flow < -self._Qtol:
return True
else:
return False
class _ActiveFCVCondition(ControlCondition):
_Qtol = 2.83168e-6
_Htol = 0.0001524
def __init__(self, wn, fcv):
"""
Parameters
----------
wn: wntr.network.WaterNetworkModel
fcv: wntr.network.Valve
"""
self._fcv = fcv
self._start_node = wn.get_node(self._fcv.start_node)
self._end_node = wn.get_node(self._fcv.end_node)
self._backtrack = 0
def requires(self):
def evaluate(self):
return bool(self._condition_1) or bool(self._condition_2)
@property
def backtrack(self):
return np.max([self._condition_1.backtrack, self._condition_2.backtrack])
def requires(self):
req = self._condition_1.requires()
req.update(self._condition_2.requires())
return req
@DocInheritor({'requires', 'evaluate', 'backtrack'})
class AndCondition(ControlCondition):
"""Combine two WNTR Conditions with an AND
Parameters
----------
cond1 : ControlCondition
The first condition
cond2 : ControlCondition
The second condition
"""
def __init__(self, cond1, cond2):
self._condition_1 = cond1
self._condition_2 = cond2
if isinstance(cond1, TankLevelCondition):
if cond1._relation is Comparison.eq:
logger.warning('Using Comparison.eq with {0} will probably not work!'.format(type(cond1)))
elif self._prv._internal_status == LinkStatus.Closed:
if self._start_node.head >= self._prv.setting + self._end_node.elevation + self._Htol and self._end_node.head < self._prv.setting + self._end_node.elevation - self._Htol:
return False
elif self._start_node.head < self._prv.setting + self._end_node.elevation - self._Htol and self._start_node.head > self._end_node.head + self._Htol:
return True
return False
else:
raise RuntimeError('Unexpected PRV _internal_status for valve {0}: {1}.'.format(self._prv,
self._prv._internal_status))
def __str__(self):
s = 'prv {0} needs to be open'.format(self._prv.name)
return s
class _ActivePRVCondition(ControlCondition):
_Qtol = 2.83168e-6
_Htol = 0.0001524
def __init__(self, wn, prv):
"""
Parameters
----------
wn: wntr.network.WaterNetworkModel
prv: wntr.network.Valve
"""
self._prv = prv
self._start_node = wn.get_node(self._prv.start_node)
self._end_node = wn.get_node(self._prv.end_node)
self._backtrack = 0
self._r = 8.0 * self._prv.minor_loss / (9.81 * math.pi**2 * self._prv.diameter**4)
return False
elif self._psv._internal_status == LinkStatus.Closed:
if ((self._end_node.head > setting + self._Htol) and
(self._start_node.head > self._end_node.head + self._Htol)):
return True
return False
else:
raise RuntimeError('Unexpected PSV _internal_status for valve {0}: {1}.'.format(self._psv,
self._psv._internal_status))
def __str__(self):
s = 'psv {0} needs to be open'.format(self._psv.name)
return s
class _ActivePSVCondition(ControlCondition):
_Qtol = 2.83168e-6
_Htol = 0.0001524
def __init__(self, wn, psv):
"""
Parameters
----------
wn: wntr.network.WaterNetworkModel
psv: wntr.network.Valve
"""
self._psv = psv
self._start_node = wn.get_node(self._psv.start_node)
self._end_node = wn.get_node(self._psv.end_node)
self._backtrack = 0
self._r = 8.0 * self._psv.minor_loss / (9.81 * math.pi**2 * self._psv.diameter**4)
if state and not relation(self._last_value, thresh_value):
# if the condition is satisfied and the last value did not satisfy the condition, then backtracking
# is needed.
# The math.floor is not actually needed, but I leave it here for clarity. We want the backtrack value to be
# slightly lower than what the floating point computation would give. This ensures the next time step will
# be slightly later than when the tank level hits the threshold. This ensures the tank level will go
# slightly beyond the threshold. This ensures that relation(self._last_value, thresh_value) will be True
# next time. This prevents us from computing very small backtrack values over and over.
if self._source_obj.demand != 0:
self._backtrack = int(math.floor((cur_value - thresh_value)*math.pi/4.0*self._source_obj.diameter**2/self._source_obj.demand))
self._last_value = cur_value # update the last value
return bool(state)
@DocInheritor({'requires', 'evaluate', 'name'})
class RelativeCondition(ControlCondition):
"""Compare attributes of two different objects (e.g., levels from tanks 1 and 2)
This type of condition does not work with the EpanetSimulator, only the WNTRSimulator.
Parameters
----------
source_obj : object
The object (such as a Junction, Tank, Pipe, etc.) to use in the comparison
source_attr : str
The attribute of the object (such as level, pressure, setting, etc.) to
compare against the threshold
relation : function
A numpy or other comparison method that takes two values and returns a bool
(e.g., numpy.greater, numpy.less_equal)
threshold_obj : object
The object (such as a Junction, Tank, Pipe, etc.) to use in the comparison of attributes
threshold_attr : str
elif self._prv._internal_status == LinkStatus.Open:
if self._prv.flow < -self._Qtol:
return True
return False
elif self._prv._internal_status == LinkStatus.Closed:
return False
else:
raise RuntimeError('Unexpected PRV _internal_status for valve {0}: {1}.'.format(self._prv,
self._prv._internal_status))
def __str__(self):
s = 'prv {0} needs to be closed'.format(self._prv.name)
return s
class _OpenPRVCondition(ControlCondition):
_Qtol = 2.83168e-6
_Htol = 0.0001524
def __init__(self, wn, prv):
"""
Parameters
----------
wn: wntr.network.WaterNetworkModel
prv: wntr.network.Valve
"""
super(_OpenPRVCondition, self).__init__()
self._prv = prv
self._start_node = wn.get_node(self._prv.start_node)
self._end_node = wn.get_node(self._prv.end_node)
self._backtrack = 0
self._r = 8.0 * self._prv.minor_loss / (9.81 * math.pi**2 * self._prv.diameter**4)
def evaluate(self):
"""
If True is returned, the pump needs to be closed
"""
dh = self._end_node.head - self._start_node.head
if dh > self.Hmax + self.Htol:
return True
return False
def __str__(self):
s = '{0} head - {1} head > {2:.4f}'.format(self._end_node.name, self._start_node.name, self.Hmax + self.Htol)
return s
class _OpenPowerPumpCondition(ControlCondition):
Htol = 0.0001524
Qtol = 2.83168e-6
Hmax = 1e10
def __init__(self, wn, pump):
"""
Parameters
----------
wn: wntr.network.WaterNetworkModel
pump: wntr.network.Pump
"""
self._pump = pump
self._start_node = wn.get_node(pump.start_node)
self._end_node = wn.get_node(pump.end_node)
self._backtrack = 0