Prado EFO PVA
rule_compliance.py
Go to the documentation of this file.
1 # -*- coding: utf-8 -*-
2 """
3 Created on Sat May 9 13:10:31 2020
4 
5 @author: cd
6 """
7 
8 import abc
9 from efo.rule import RuleBase
10 from efo.qin import QinSpecified
11 import numpy as np
12 from efo.lookup import LkupTbl, LkupTblAnn, LkupTblElev, LkupTblInterp
13 
14 # TODO: Should compliance rules also return a max or min?
15 
16 class RuleComplianceBase(RuleBase):
17  MIN = int(0)
18  MAX = int(1)
19  CTRL_RLS = int(0)
20  TOT_RLS = int(1)
21 
22  def __init__(self, name, time, *, ruleType=MIN, rlsType=CTRL_RLS):
23  super().__init__(name, time)
24  self.ruleTyperuleType = ruleType
25  self.rlsTyperlsType = rlsType
26  self.qCompCurqCompCur = 0. if ruleType == RuleComplianceBase.MIN else np.inf
27 
28  @abc.abstractmethod
29  def get_qcomp(self, *, rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0):
30  return
31 
32  @classmethod
33  def __subclasshook__(cls, C):
34  if cls is RuleComplianceBase:
35  attrs = set(dir(C))
36  if set(cls.__abstractmethods__) <= attrs:
37  return True
38  return NotImplemented
39 
40  def calc_release(self, rlsProposed, *, rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None):
41  rlsProposed = super().calc_release(
42  rlsProposed, rlsPrev=rlsPrev, rlsUnCtrl=rlsUnCtrl, stor=stor, qIn=qIn)
43  qComp = self.get_qcompget_qcomp(stor=stor, rlsUnCtrl=rlsUnCtrl, rlsPrev=rlsPrev, qIn=qIn)
44  release = min(rlsProposed, qComp) if self.ruleTyperuleType==RuleComplianceBase.MAX else max(rlsProposed, qComp)
45  self.release[self.T.step] = release
46  return release
47 
48 
50  def __init__(self, name, time, minQ, rlsType=RuleComplianceBase.CTRL_RLS):
51  # Call super class constructor
52  # TODO: Error check to make sure that the minQ is a float
53  super().__init__(name, time, ruleType=RuleComplianceBase.MIN)
54  # Class properties
55  self.minQminQ = minQ
56 
57  # TODO: Could this be a property?
58  def get_qcomp(self, *, rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0):
59  self.qCompCurqCompCurqCompCur = self.minQminQ
60  return self.qCompCurqCompCurqCompCur
61 
62 
64  def __init__(self, name, time, maxQ, pctBuffer=0., rlsType=RuleComplianceBase.CTRL_RLS):
65  # Call super class constructor
66  super().__init__(name, time, ruleType=RuleComplianceBase.MAX)
67  # Class properties
68  # TODO: Error check to make sure that the minQ is a float
69  self.pctBufferpctBuffer = pctBuffer
70  self.maxQmaxQ = maxQ - maxQ*pctBuffer
71 
72  def get_qcomp(self, *, rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0):
73  self.qCompCurqCompCurqCompCur = self.maxQmaxQ
74  return self.qCompCurqCompCurqCompCur
75 
76 
77 # TODO: This should subclass something that requires storage to get a qMax for error handling
79  def __init__(self, name, time, hypso, xElev, yQ, rlsType=RuleComplianceBase.CTRL_RLS):
80  # Call super class constructor
81  super().__init__(name, time, ruleType=RuleComplianceBase.MAX)
82  # Build lookup table
83  self.compQTblcompQTbl = LkupTblElev(name+'_table', hypso, xElev, yQ)
84 
85  def get_qcomp(self, *, stor, rlsUnCtrl, rlsPrev=None, qIn=None, tsOffset=0):
86  qCompLkUp = self.compQTblcompQTbl.get_val(stor)
87  if self.rlsTyperlsTyperlsType == RuleMaxLkupTblElev.TOT_RLS:
88  self.qCompCurqCompCurqCompCur = max(0., qCompLkUp - rlsUnCtrl)
89  else:
90  self.qCompCurqCompCurqCompCur = qCompLkUp
91  return self.qCompCurqCompCurqCompCur
92 
93 
95  def __init__(self, name, time, monDayHr, minQsched, rlsType=RuleComplianceBase.CTRL_RLS, *,
96  typ='step', timeUnit=None, hydroCond=None):
97  # Call super class constructor
98  super().__init__(name, time, ruleType=RuleComplianceBase.MIN)
99  # Class properties
100  self.compQschedcompQsched = LkupTblAnn(name+'_sched',time, monDayHr, minQsched,
101  typ=typ, timeUnit=timeUnit)
102  self.hydroCondhydroCond = hydroCond
103 
104  def get_qcomp(self, *, rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0):
105  curDT = self.T.get_datetime_offset(tsOffset)
106  if self.hydroCondhydroCond is None:
107  qCompSched = self.compQschedcompQsched.get_val(curDT)
108  else:
109  hc = self.hydroCondhydroCond.get_hydrologic_cond(tsOffset=tsOffset)
110  qCompSched = self.compQschedcompQsched.get_val(curDT, self.hydroCondhydroCond.curCond)
111  self.qCompCurqCompCurqCompCur = qCompSched
112  return self.qCompCurqCompCurqCompCur
113 
114 
116  def __init__(self, name, time, monDayHr, maxQsched, rlsType=RuleComplianceBase.CTRL_RLS, *,
117  typ='step', timeUnit=None, hydroCond=None):
118  # Call super class constructor
119  super().__init__(name, time, monDayHr, maxQsched, rlsType=rlsType,
120  typ=typ, timeUnit=timeUnit, hydroCond=hydroCond)
121  # Class properties
122  self.ruleTyperuleTyperuleType=RuleComplianceBase.MAX
123  self.compQschedcompQschedcompQsched = LkupTblAnn(name+'_sched',time, monDayHr, maxQsched,
124  typ=typ, timeUnit=timeUnit)
125  self.hydroCondhydroCondhydroCond = hydroCond
126 
127 
129  def __init__(self, name, time, *,
130  ruleMax, jncDiversion, rlsType=RuleComplianceBase.CTRL_RLS):
131  # Call super class constructor
132  super().__init__(name, time, ruleType=RuleComplianceBase.MAX)
133  self.ruleMaxDivruleMaxDiv = ruleMax
134  self.jncDiversionjncDiversion = jncDiversion
135  self.qInSpecifiedqInSpecified = QinSpecified(name+'_qInSpecified',time)
136  self.qInSpecifiedqInSpecified.set_qin(tsOffset=0, qSpecified=0.)
137  self.jncDiversionjncDiversion.append_qin(self.qInSpecifiedqInSpecified)
138 
139  def get_qcomp(self, *, rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0):
140  qMaxDiv = self.ruleMaxDivruleMaxDiv.get_qcomp(rlsPrev=rlsPrev, rlsUnCtrl=rlsUnCtrl, stor=stor, qIn=qIn, tsOffset=tsOffset)
141  qDemand = -self.jncDiversionjncDiversion.calc_delta(ruleType=self.ruleTyperuleType, tsOffset=tsOffset)
142  self.qCompCurqCompCurqCompCur = min(qMaxDiv, qDemand)
143  return self.qCompCurqCompCurqCompCur
144 
145  def calc_release(self, rlsProposed, *, rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None):
146  rlsProposed = super().calc_release(
147  rlsProposed, rlsPrev=rlsPrev, rlsUnCtrl=rlsUnCtrl, stor=stor, qIn=qIn)
148  qDiv = min(self.get_qcompget_qcompget_qcomp(rlsPrev=rlsPrev, rlsUnCtrl=rlsUnCtrl, stor=stor, qIn=qIn), rlsProposed)
149  self.qInSpecifiedqInSpecified.set_qin(tsOffset=0, qSpecified=qDiv)
150  return qDiv
151 
152 
154  def __init__(self, name, time, *,
155  ruleMax, jncDiversion=None):
156  # Call super class constructor
157  super().__init__(name, time, ruleType=RuleComplianceBase.MAX)
158  self.ruleMaxruleMax = ruleMax
159  self.jncDiversionjncDiversion = jncDiversion
160 
161  def get_qcomp(self, *, rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0):
162  # super().get_qcomp(rlsPrev=rlsPrev, rlsUnCtrl=rlsUnCtrl, stor=stor, qIn=qIn, tsOffset=tsOffset)
163  self.qCompCurqCompCurqCompCur = self.ruleMaxruleMax.get_qcomp(tsOffset=tsOffset)
164  return self.qCompCurqCompCurqCompCur
165 
166  def calc_release(self, rlsProposed, *, rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None):
167  rlsProposed = super().calc_release(
168  rlsProposed, rlsPrev=rlsPrev, rlsUnCtrl=rlsUnCtrl, stor=stor, qIn=qIn)
169  # TODO: Since the downstream rule is a min rule this a temporary fix to max it a max rule
170  # TODO: Also it seems that qComp it being called many times
171  qDiv = self.ruleMaxruleMax.calc_release(rlsProposed,
172  rlsUnCtrl=rlsUnCtrl, stor=stor, qIn=qIn)
173  self.jncDiversionjncDiversion.set_qout(qOutSpecified=qDiv)
174  return qDiv
175 
176 
178  def __init__(self, name):
179  self.namename = name
180  # Set class properties
181  self._curCond_curCond = np.nan
182 
183  @property
184  def curCond(self):
185  return self._curCond_curCond
186 
187  @curCond.setter
188  def curCond(self, curHydroCond):
189  self._curCond_curCond = curHydroCond
190 
191 
193  def __init__(self, name, time, xQinMax, yRls, *, typ='step'):
194  # Call super class constructor
195  super().__init__(name, time, ruleType=RuleComplianceBase.MAX)
196  if typ=='interp':
197  self.qInMaxTblqInMaxTbl = LkupTblInterp(name+'_QinMax', xQinMax, yRls)
198  else:
199  self.qInMaxTblqInMaxTbl = LkupTbl(name+'_QinMax', xQinMax, yRls)
200 
201  def get_qcomp(self, *, qIn, rlsPrev=None, rlsUnCtrl=None, stor=None, tsOffset=0):
202  self.qCompCurqCompCurqCompCur = self.qInMaxTblqInMaxTbl.get_val(qIn)
203  return self.qCompCurqCompCurqCompCur
204 
205 
206 # TODO: This should be an abstract class in it's own module with it's subclasses
208  def __init__(self, name, time, rlsSched, rampSched, ruleType, timeUnit='h', nHrs=1):
209  # Call super class constructor
210  super().__init__(name, time, ruleType=ruleType, rlsType=RuleComplianceBase.CTRL_RLS)
211  if timeUnit != time.timeUnit or nHrs != time.nHrs:
212  if timeUnit == 'h': rampSched = rampSched*(time.nHrs/nHrs)
213  # Create lookup table
214  self.rampTblrampTbl = LkupTbl(name+'_RampSched',rlsSched, rampSched)
215 
216  # TODO: This should be moved to the RuleIncreaseRateChng subclass
217  def get_qcomp(self, *, rlsPrev, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0):
218  self.qCompCurqCompCurqCompCur = rlsPrev + self.rampTblrampTbl.get_val(rlsPrev)
219  return self.qCompCurqCompCurqCompCur
220 
221 
223  def __init__(self, name, time, rlsSched, drocSched, timeUnit='h', nHrs=1):
224  # Call super class constructor
225  super().__init__(name, time, rlsSched, drocSched, ruleType=RuleComplianceBase.MIN)
226  # self.ruleType = RuleComplianceBase.MIN
227 
228  def get_qcomp(self, *, rlsPrev, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0):
229  self.qCompCurqCompCurqCompCurqCompCur = rlsPrev - self.rampTblrampTbl.get_val(rlsPrev)
230  return self.qCompCurqCompCurqCompCurqCompCur
231 
232 
234  def __init__(self, name, time, rlsSched, irocSched, timeUnit='h', nHrs=1):
235  # Call super class constructor
236  super().__init__(name, time, rlsSched, irocSched, ruleType=RuleComplianceBase.MAX)
237 
238 
239 
240 
241 
242 
def get_qcomp(self, *rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0)
def calc_release(self, rlsProposed, *rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None)
def __init__(self, name, time, *ruleType=MIN, rlsType=CTRL_RLS)
def get_qcomp(self, *rlsPrev, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0)
def __init__(self, name, time, rlsSched, drocSched, timeUnit='h', nHrs=1)
def calc_release(self, rlsProposed, *rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None)
def __init__(self, name, time, *ruleMax, jncDiversion=None)
def get_qcomp(self, *rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0)
def calc_release(self, rlsProposed, *rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None)
def get_qcomp(self, *rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0)
def __init__(self, name, time, *ruleMax, jncDiversion, rlsType=RuleComplianceBase.CTRL_RLS)
def __init__(self, name, time, rlsSched, irocSched, timeUnit='h', nHrs=1)
def __init__(self, name, time, monDayHr, maxQsched, rlsType=RuleComplianceBase.CTRL_RLS, *typ='step', timeUnit=None, hydroCond=None)
def get_qcomp(self, *stor, rlsUnCtrl, rlsPrev=None, qIn=None, tsOffset=0)
def __init__(self, name, time, hypso, xElev, yQ, rlsType=RuleComplianceBase.CTRL_RLS)
def __init__(self, name, time, xQinMax, yRls, *typ='step')
def get_qcomp(self, *qIn, rlsPrev=None, rlsUnCtrl=None, stor=None, tsOffset=0)
def get_qcomp(self, *rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0)
def __init__(self, name, time, maxQ, pctBuffer=0., rlsType=RuleComplianceBase.CTRL_RLS)
def __init__(self, name, time, monDayHr, minQsched, rlsType=RuleComplianceBase.CTRL_RLS, *typ='step', timeUnit=None, hydroCond=None)
def get_qcomp(self, *rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0)
def __init__(self, name, time, minQ, rlsType=RuleComplianceBase.CTRL_RLS)
def get_qcomp(self, *rlsPrev=None, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0)
def get_qcomp(self, *rlsPrev, rlsUnCtrl=None, stor=None, qIn=None, tsOffset=0)
def __init__(self, name, time, rlsSched, rampSched, ruleType, timeUnit='h', nHrs=1)