honeybee-energy 1.116.106__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. honeybee_energy/__init__.py +24 -0
  2. honeybee_energy/__main__.py +4 -0
  3. honeybee_energy/_extend_honeybee.py +145 -0
  4. honeybee_energy/altnumber.py +21 -0
  5. honeybee_energy/baseline/__init__.py +2 -0
  6. honeybee_energy/baseline/create.py +608 -0
  7. honeybee_energy/baseline/data/__init__.py +1 -0
  8. honeybee_energy/baseline/data/constructions.csv +64 -0
  9. honeybee_energy/baseline/data/fen_ratios.csv +15 -0
  10. honeybee_energy/baseline/data/lpd_building.csv +21 -0
  11. honeybee_energy/baseline/data/pci_2016.csv +22 -0
  12. honeybee_energy/baseline/data/pci_2019.csv +22 -0
  13. honeybee_energy/baseline/data/pci_2022.csv +22 -0
  14. honeybee_energy/baseline/data/shw.csv +21 -0
  15. honeybee_energy/baseline/pci.py +512 -0
  16. honeybee_energy/baseline/result.py +371 -0
  17. honeybee_energy/boundarycondition.py +128 -0
  18. honeybee_energy/cli/__init__.py +69 -0
  19. honeybee_energy/cli/baseline.py +475 -0
  20. honeybee_energy/cli/edit.py +327 -0
  21. honeybee_energy/cli/lib.py +1154 -0
  22. honeybee_energy/cli/result.py +810 -0
  23. honeybee_energy/cli/setconfig.py +124 -0
  24. honeybee_energy/cli/settings.py +569 -0
  25. honeybee_energy/cli/simulate.py +380 -0
  26. honeybee_energy/cli/translate.py +1714 -0
  27. honeybee_energy/cli/validate.py +224 -0
  28. honeybee_energy/config.json +11 -0
  29. honeybee_energy/config.py +842 -0
  30. honeybee_energy/construction/__init__.py +1 -0
  31. honeybee_energy/construction/_base.py +374 -0
  32. honeybee_energy/construction/air.py +325 -0
  33. honeybee_energy/construction/dictutil.py +89 -0
  34. honeybee_energy/construction/dynamic.py +607 -0
  35. honeybee_energy/construction/opaque.py +460 -0
  36. honeybee_energy/construction/shade.py +319 -0
  37. honeybee_energy/construction/window.py +1096 -0
  38. honeybee_energy/construction/windowshade.py +847 -0
  39. honeybee_energy/constructionset.py +1655 -0
  40. honeybee_energy/dictutil.py +56 -0
  41. honeybee_energy/generator/__init__.py +5 -0
  42. honeybee_energy/generator/loadcenter.py +204 -0
  43. honeybee_energy/generator/pv.py +535 -0
  44. honeybee_energy/hvac/__init__.py +21 -0
  45. honeybee_energy/hvac/_base.py +124 -0
  46. honeybee_energy/hvac/_template.py +270 -0
  47. honeybee_energy/hvac/allair/__init__.py +22 -0
  48. honeybee_energy/hvac/allair/_base.py +349 -0
  49. honeybee_energy/hvac/allair/furnace.py +168 -0
  50. honeybee_energy/hvac/allair/psz.py +131 -0
  51. honeybee_energy/hvac/allair/ptac.py +163 -0
  52. honeybee_energy/hvac/allair/pvav.py +109 -0
  53. honeybee_energy/hvac/allair/vav.py +128 -0
  54. honeybee_energy/hvac/detailed.py +337 -0
  55. honeybee_energy/hvac/doas/__init__.py +28 -0
  56. honeybee_energy/hvac/doas/_base.py +345 -0
  57. honeybee_energy/hvac/doas/fcu.py +127 -0
  58. honeybee_energy/hvac/doas/radiant.py +329 -0
  59. honeybee_energy/hvac/doas/vrf.py +81 -0
  60. honeybee_energy/hvac/doas/wshp.py +91 -0
  61. honeybee_energy/hvac/heatcool/__init__.py +23 -0
  62. honeybee_energy/hvac/heatcool/_base.py +177 -0
  63. honeybee_energy/hvac/heatcool/baseboard.py +61 -0
  64. honeybee_energy/hvac/heatcool/evapcool.py +72 -0
  65. honeybee_energy/hvac/heatcool/fcu.py +92 -0
  66. honeybee_energy/hvac/heatcool/gasunit.py +53 -0
  67. honeybee_energy/hvac/heatcool/radiant.py +269 -0
  68. honeybee_energy/hvac/heatcool/residential.py +77 -0
  69. honeybee_energy/hvac/heatcool/vrf.py +54 -0
  70. honeybee_energy/hvac/heatcool/windowac.py +70 -0
  71. honeybee_energy/hvac/heatcool/wshp.py +62 -0
  72. honeybee_energy/hvac/idealair.py +699 -0
  73. honeybee_energy/internalmass.py +310 -0
  74. honeybee_energy/lib/__init__.py +1 -0
  75. honeybee_energy/lib/_loadconstructions.py +194 -0
  76. honeybee_energy/lib/_loadconstructionsets.py +117 -0
  77. honeybee_energy/lib/_loadmaterials.py +83 -0
  78. honeybee_energy/lib/_loadprogramtypes.py +125 -0
  79. honeybee_energy/lib/_loadschedules.py +87 -0
  80. honeybee_energy/lib/_loadtypelimits.py +64 -0
  81. honeybee_energy/lib/constructions.py +207 -0
  82. honeybee_energy/lib/constructionsets.py +95 -0
  83. honeybee_energy/lib/materials.py +67 -0
  84. honeybee_energy/lib/programtypes.py +125 -0
  85. honeybee_energy/lib/schedules.py +61 -0
  86. honeybee_energy/lib/scheduletypelimits.py +31 -0
  87. honeybee_energy/load/__init__.py +1 -0
  88. honeybee_energy/load/_base.py +190 -0
  89. honeybee_energy/load/daylight.py +397 -0
  90. honeybee_energy/load/dictutil.py +47 -0
  91. honeybee_energy/load/equipment.py +771 -0
  92. honeybee_energy/load/hotwater.py +543 -0
  93. honeybee_energy/load/infiltration.py +460 -0
  94. honeybee_energy/load/lighting.py +480 -0
  95. honeybee_energy/load/people.py +497 -0
  96. honeybee_energy/load/process.py +472 -0
  97. honeybee_energy/load/setpoint.py +816 -0
  98. honeybee_energy/load/ventilation.py +550 -0
  99. honeybee_energy/material/__init__.py +1 -0
  100. honeybee_energy/material/_base.py +166 -0
  101. honeybee_energy/material/dictutil.py +59 -0
  102. honeybee_energy/material/frame.py +367 -0
  103. honeybee_energy/material/gas.py +1087 -0
  104. honeybee_energy/material/glazing.py +854 -0
  105. honeybee_energy/material/opaque.py +1351 -0
  106. honeybee_energy/material/shade.py +1360 -0
  107. honeybee_energy/measure.py +472 -0
  108. honeybee_energy/programtype.py +723 -0
  109. honeybee_energy/properties/__init__.py +1 -0
  110. honeybee_energy/properties/aperture.py +333 -0
  111. honeybee_energy/properties/door.py +342 -0
  112. honeybee_energy/properties/extension.py +244 -0
  113. honeybee_energy/properties/face.py +274 -0
  114. honeybee_energy/properties/model.py +2640 -0
  115. honeybee_energy/properties/room.py +1747 -0
  116. honeybee_energy/properties/shade.py +314 -0
  117. honeybee_energy/properties/shademesh.py +262 -0
  118. honeybee_energy/reader.py +48 -0
  119. honeybee_energy/result/__init__.py +1 -0
  120. honeybee_energy/result/colorobj.py +648 -0
  121. honeybee_energy/result/emissions.py +290 -0
  122. honeybee_energy/result/err.py +101 -0
  123. honeybee_energy/result/eui.py +100 -0
  124. honeybee_energy/result/generation.py +160 -0
  125. honeybee_energy/result/loadbalance.py +890 -0
  126. honeybee_energy/result/match.py +202 -0
  127. honeybee_energy/result/osw.py +90 -0
  128. honeybee_energy/result/rdd.py +59 -0
  129. honeybee_energy/result/zsz.py +190 -0
  130. honeybee_energy/run.py +1577 -0
  131. honeybee_energy/schedule/__init__.py +1 -0
  132. honeybee_energy/schedule/day.py +626 -0
  133. honeybee_energy/schedule/dictutil.py +59 -0
  134. honeybee_energy/schedule/fixedinterval.py +1012 -0
  135. honeybee_energy/schedule/rule.py +619 -0
  136. honeybee_energy/schedule/ruleset.py +1867 -0
  137. honeybee_energy/schedule/typelimit.py +310 -0
  138. honeybee_energy/shw.py +315 -0
  139. honeybee_energy/simulation/__init__.py +1 -0
  140. honeybee_energy/simulation/control.py +214 -0
  141. honeybee_energy/simulation/daylightsaving.py +185 -0
  142. honeybee_energy/simulation/dictutil.py +51 -0
  143. honeybee_energy/simulation/output.py +646 -0
  144. honeybee_energy/simulation/parameter.py +606 -0
  145. honeybee_energy/simulation/runperiod.py +443 -0
  146. honeybee_energy/simulation/shadowcalculation.py +295 -0
  147. honeybee_energy/simulation/sizing.py +546 -0
  148. honeybee_energy/ventcool/__init__.py +5 -0
  149. honeybee_energy/ventcool/_crack_data.py +91 -0
  150. honeybee_energy/ventcool/afn.py +289 -0
  151. honeybee_energy/ventcool/control.py +269 -0
  152. honeybee_energy/ventcool/crack.py +126 -0
  153. honeybee_energy/ventcool/fan.py +493 -0
  154. honeybee_energy/ventcool/opening.py +365 -0
  155. honeybee_energy/ventcool/simulation.py +314 -0
  156. honeybee_energy/writer.py +1078 -0
  157. honeybee_energy-1.116.106.dist-info/METADATA +113 -0
  158. honeybee_energy-1.116.106.dist-info/RECORD +162 -0
  159. honeybee_energy-1.116.106.dist-info/WHEEL +5 -0
  160. honeybee_energy-1.116.106.dist-info/entry_points.txt +2 -0
  161. honeybee_energy-1.116.106.dist-info/licenses/LICENSE +661 -0
  162. honeybee_energy-1.116.106.dist-info/top_level.txt +1 -0
@@ -0,0 +1,619 @@
1
+ # coding=utf-8
2
+ """Object storing rules for how a given ScheduleDay gets applied over a year."""
3
+ from __future__ import division
4
+
5
+ from .day import ScheduleDay
6
+ from ..reader import parse_idf_string
7
+
8
+ from honeybee._lockable import lockable
9
+
10
+ from ladybug.dt import Date
11
+
12
+
13
+ @lockable
14
+ class ScheduleRule(object):
15
+ """Schedule rule including a ScheduleDay and when it should be applied.
16
+
17
+ Note that a ScheduleRule cannot be assigned to Rooms, Shades, etc. The
18
+ ScheduleRule must be added to a ScheduleRuleset and then the ScheduleRuleset
19
+ can be applied to such objects.
20
+
21
+ Args:
22
+ schedule_day: A ScheduleDay object associated with this rule.
23
+ apply_sunday: Boolean noting whether to apply schedule_day on Sundays.
24
+ apply_monday: Boolean noting whether to apply schedule_day on Mondays.
25
+ apply_tuesday: Boolean noting whether to apply schedule_day on Tuesdays.
26
+ apply_wednesday: Boolean noting whether to apply schedule_day on Wednesdays.
27
+ apply_thursday: Boolean noting whether to apply schedule_day on Thursdays.
28
+ apply_friday: Boolean noting whether to apply schedule_day on Fridays.
29
+ apply_saturday: Boolean noting whether to apply schedule_day on Saturdays.
30
+ start_date: A ladybug Date object for the start of the period over which
31
+ the schedule_day will be applied. If None, Jan 1 will be used.
32
+ end_date: A ladybug Date object for the end of the period over which
33
+ the schedule_day will be applied. If None, Dec 31 will be used.
34
+
35
+ Properties:
36
+ * schedule_day
37
+ * apply_sunday
38
+ * apply_monday
39
+ * apply_tuesday
40
+ * apply_wednesday
41
+ * apply_thursday
42
+ * apply_friday
43
+ * apply_saturday
44
+ * start_date
45
+ * end_date
46
+ * apply_weekday
47
+ * apply_weekend
48
+ * apply_all
49
+ * days_applied
50
+ * week_apply_tuple
51
+ * is_reversed
52
+ """
53
+ __slots__ = ('_schedule_day', '_apply_sunday', '_apply_monday', '_apply_tuesday',
54
+ '_apply_wednesday', '_apply_thursday', '_apply_friday',
55
+ '_apply_saturday', '_start_date', '_end_date', '_start_doy',
56
+ '_end_doy', '_locked')
57
+
58
+ _year_start = Date(1, 1)
59
+ _year_end = Date(12, 31)
60
+
61
+ def __init__(self, schedule_day, apply_sunday=False, apply_monday=False,
62
+ apply_tuesday=False, apply_wednesday=False, apply_thursday=False,
63
+ apply_friday=False, apply_saturday=False, start_date=None, end_date=None):
64
+ """Initialize Schedule Rule."""
65
+ self._locked = False # unlocked by default
66
+ self.schedule_day = schedule_day
67
+ self.apply_sunday = apply_sunday
68
+ self.apply_monday = apply_monday
69
+ self.apply_tuesday = apply_tuesday
70
+ self.apply_wednesday = apply_wednesday
71
+ self.apply_thursday = apply_thursday
72
+ self.apply_friday = apply_friday
73
+ self.apply_saturday = apply_saturday
74
+
75
+ # process the start date and end date
76
+ if start_date is not None:
77
+ self._check_date(start_date, 'start_date')
78
+ self._start_date = start_date
79
+ else:
80
+ self._start_date = self._year_start
81
+ self._start_doy = self._doy_non_leap_year(self._start_date)
82
+ self.end_date = end_date
83
+
84
+ @property
85
+ def schedule_day(self):
86
+ """Get or set the ScheduleDay object associated with this rule.."""
87
+ return self._schedule_day
88
+
89
+ @schedule_day.setter
90
+ def schedule_day(self, value):
91
+ assert isinstance(value, ScheduleDay), \
92
+ 'Expected ScheduleDay for ScheduleRule. Got {}.'.format(type(value))
93
+ self._schedule_day = value
94
+
95
+ @property
96
+ def apply_sunday(self):
97
+ """Get or set a boolean noting whether to apply schedule_day on Sundays."""
98
+ return self._apply_sunday
99
+
100
+ @apply_sunday.setter
101
+ def apply_sunday(self, value):
102
+ self._apply_sunday = bool(value)
103
+
104
+ @property
105
+ def apply_monday(self):
106
+ """Get or set a boolean noting whether to apply schedule_day on Mondays."""
107
+ return self._apply_monday
108
+
109
+ @apply_monday.setter
110
+ def apply_monday(self, value):
111
+ self._apply_monday = bool(value)
112
+
113
+ @property
114
+ def apply_tuesday(self):
115
+ """Get or set a boolean noting whether to apply schedule_day on Tuesdays."""
116
+ return self._apply_tuesday
117
+
118
+ @apply_tuesday.setter
119
+ def apply_tuesday(self, value):
120
+ self._apply_tuesday = bool(value)
121
+
122
+ @property
123
+ def apply_wednesday(self):
124
+ """Get or set a boolean noting whether to apply schedule_day on Wednesdays."""
125
+ return self._apply_wednesday
126
+
127
+ @apply_wednesday.setter
128
+ def apply_wednesday(self, value):
129
+ self._apply_wednesday = bool(value)
130
+
131
+ @property
132
+ def apply_thursday(self):
133
+ """Get or set a boolean noting whether to apply schedule_day on Thursdays."""
134
+ return self._apply_thursday
135
+
136
+ @apply_thursday.setter
137
+ def apply_thursday(self, value):
138
+ self._apply_thursday = bool(value)
139
+
140
+ @property
141
+ def apply_friday(self):
142
+ """Get or set a boolean noting whether to apply schedule_day on Fridays."""
143
+ return self._apply_friday
144
+
145
+ @apply_friday.setter
146
+ def apply_friday(self, value):
147
+ self._apply_friday = bool(value)
148
+
149
+ @property
150
+ def apply_saturday(self):
151
+ """Get or set a boolean noting whether to apply schedule_day on Saturdays."""
152
+ return self._apply_saturday
153
+
154
+ @apply_saturday.setter
155
+ def apply_saturday(self, value):
156
+ self._apply_saturday = bool(value)
157
+
158
+ @property
159
+ def apply_weekday(self):
160
+ """Get or set a boolean noting whether to apply schedule_day on week days."""
161
+ return self._apply_monday and self._apply_tuesday and self._apply_wednesday and \
162
+ self._apply_thursday and self._apply_friday
163
+
164
+ @apply_weekday.setter
165
+ def apply_weekday(self, value):
166
+ self._apply_monday = self._apply_tuesday = self._apply_wednesday = \
167
+ self._apply_thursday = self._apply_friday = bool(value)
168
+
169
+ @property
170
+ def apply_weekend(self):
171
+ """Get or set a boolean noting whether to apply schedule_day on weekends."""
172
+ return self._apply_sunday and self._apply_saturday
173
+
174
+ @apply_weekend.setter
175
+ def apply_weekend(self, value):
176
+ self._apply_sunday = self._apply_saturday = bool(value)
177
+
178
+ @property
179
+ def apply_all(self):
180
+ """Get or set a boolean noting whether to apply schedule_day on all days."""
181
+ return self._apply_sunday and self._apply_monday and self._apply_tuesday and \
182
+ self._apply_wednesday and self._apply_thursday and self._apply_friday and \
183
+ self._apply_saturday
184
+
185
+ @apply_all.setter
186
+ def apply_all(self, value):
187
+ self._apply_sunday = self._apply_monday = self._apply_tuesday = \
188
+ self._apply_wednesday = self._apply_thursday = self._apply_friday = \
189
+ self._apply_saturday = bool(value)
190
+
191
+ @property
192
+ def start_date(self):
193
+ """Get or set a ladybug Date object for the start of the period."""
194
+ return self._start_date
195
+
196
+ @start_date.setter
197
+ def start_date(self, value):
198
+ if value is not None:
199
+ self._check_date(value, 'start_date')
200
+ self._start_date = value
201
+ else:
202
+ self._start_date = self._year_start
203
+ self._start_doy = self._doy_non_leap_year(self._start_date)
204
+
205
+ @property
206
+ def end_date(self):
207
+ """Get or set a ladybug Date object for the end of the period."""
208
+ return self._end_date
209
+
210
+ @end_date.setter
211
+ def end_date(self, value):
212
+ if value is not None:
213
+ self._check_date(value, 'end_date')
214
+ self._end_date = value
215
+ else:
216
+ self._end_date = self._year_end
217
+ self._end_doy = self._doy_non_leap_year(self._end_date)
218
+
219
+ @property
220
+ def days_applied(self):
221
+ """Get a list of text values for the days applied."""
222
+ day_names = ('sunday', 'monday', 'tuesday', 'wednesday', 'thursday',
223
+ 'friday', 'saturday')
224
+ days = [name for name, apply in zip(day_names, self.week_apply_tuple) if apply]
225
+ return days
226
+
227
+ @property
228
+ def week_apply_tuple(self):
229
+ """Get a tuple of 7 booleans for each of the days of the week."""
230
+ return (self._apply_sunday, self._apply_monday, self._apply_tuesday,
231
+ self._apply_wednesday, self._apply_thursday, self._apply_friday,
232
+ self._apply_saturday)
233
+
234
+ @property
235
+ def is_reversed(self):
236
+ """A property to note whether the start date is after the end date.
237
+
238
+ This indicates that the rule applies through the end of the year into
239
+ the start of the year.
240
+ """
241
+ return self._start_date > self._end_date
242
+
243
+ def apply_day_by_name(self, day_name):
244
+ """Set the rule to apply to the day of the week by its name.
245
+
246
+ Args:
247
+ day_name: A text string for the day on which this rule should be applied.
248
+ The following options are acceptable:
249
+ 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday',
250
+ 'saturday', 'weekday', 'weekend', 'all'
251
+ """
252
+ day_name = day_name.lower()
253
+ if day_name == 'sunday':
254
+ self.apply_sunday = True
255
+ elif day_name == 'monday':
256
+ self.apply_monday = True
257
+ elif day_name == 'tuesday':
258
+ self.apply_tuesday = True
259
+ elif day_name == 'wednesday':
260
+ self.apply_wednesday = True
261
+ elif day_name == 'thursday':
262
+ self.apply_thursday = True
263
+ elif day_name == 'friday':
264
+ self.apply_friday = True
265
+ elif day_name == 'saturday':
266
+ self.apply_saturday = True
267
+ elif day_name == 'weekday':
268
+ self.apply_weekday = True
269
+ elif day_name == 'weekend':
270
+ self.apply_weekend = True
271
+ elif day_name == 'all':
272
+ self.apply_all = True
273
+ else:
274
+ raise ValueError('ScheduleRule input "{}" is not an acceptable '
275
+ 'day name.'.format(day_name))
276
+
277
+ def apply_day_by_dow(self, dow):
278
+ """Set the rule to apply to the day of the week by its dow integer.
279
+
280
+ Args:
281
+ week_day_index: An integer from 1-8 for the day of the week. Values
282
+ correspond to the following:
283
+
284
+ 1 - Sunday
285
+ 2 - Monday
286
+ 3 - Tuesday
287
+ 4 - Wednesday
288
+ 5 - Thursday
289
+ 6 - Friday
290
+ 7 - Saturday
291
+ """
292
+ if dow == 1:
293
+ self.apply_sunday = True
294
+ elif dow == 2:
295
+ self.apply_monday = True
296
+ elif dow == 3:
297
+ self.apply_tuesday = True
298
+ elif dow == 4:
299
+ self.apply_wednesday = True
300
+ elif dow == 5:
301
+ self.apply_thursday = True
302
+ elif dow == 6:
303
+ self.apply_friday = True
304
+ elif dow == 7:
305
+ self.apply_saturday = True
306
+ else:
307
+ raise ValueError('ScheduleRule input "{}" is not an acceptable '
308
+ 'dow integer.'.format(dow))
309
+
310
+ def does_rule_apply(self, doy, dow=None):
311
+ """Check if this rule applies to a given day of the year and day of the week.
312
+
313
+ Args:
314
+ doy: An integer between 1 anf 365 for the day of the year to test.
315
+ dow: An integer between 1 anf 7 for the day of the week to test. If None,
316
+ this value will be derived from the doy, assuming the first day of
317
+ the year is a Sunday.
318
+ """
319
+ dow = dow if dow is not None else doy % 7
320
+ return self.does_rule_apply_doy(doy) and self.week_apply_tuple[dow - 1]
321
+
322
+ def does_rule_apply_leap_year(self, doy, dow=None):
323
+ """Check if this rule applies to a given day of a leap year and day of the week.
324
+
325
+ Args:
326
+ doy: An integer between 1 anf 366 for the day of the leap year to test.
327
+ dow: An integer between 1 anf 7 for the day of the week to test. If None,
328
+ this value will be derived from the doy, assuming the first day of
329
+ the year is a Sunday.
330
+ """
331
+ dow = dow if dow is not None else doy % 7
332
+ return self.does_rule_apply_doy_leap_year(doy) and self.week_apply_tuple[dow - 1]
333
+
334
+ def does_rule_apply_doy(self, doy):
335
+ """Check if this rule applies to a given day of the year.
336
+
337
+ Args:
338
+ doy: An integer between 1 anf 365 for the day of the year to test.
339
+ """
340
+ if self.is_reversed:
341
+ return doy <= self._end_doy or self._start_doy <= doy
342
+ else:
343
+ return self._start_doy <= doy <= self._end_doy
344
+
345
+ def does_rule_apply_doy_leap_year(self, doy):
346
+ """Check if this rule applies to a given day of a leap year.
347
+
348
+ Args:
349
+ doy: An integer between 1 anf 366 for the day of the leap year to test.
350
+ """
351
+ st_doy = self._start_doy if self._start_date.month <= 2 else self._start_doy + 1
352
+ end_doy = self._end_doy if self._end_date.month <= 2 else self._end_doy + 1
353
+ if self.is_reversed:
354
+ return doy <= end_doy or st_doy <= doy
355
+ else:
356
+ return st_doy <= doy <= end_doy
357
+
358
+ @classmethod
359
+ def from_days_applied(cls, schedule_day, applicable_days=None,
360
+ start_date=None, end_date=None):
361
+ """Initialize a ScheduleRule using a list of days when the rule is applied.
362
+
363
+ Args:
364
+ schedule_day: A ScheduleDay object associated with this rule.
365
+ applicable_days: A list of text strings for the days when theScheduleRule
366
+ will be applied. For example ['monday', 'weekend'].
367
+ The following options are acceptable:
368
+ 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday',
369
+ 'saturday', 'weekday', 'weekend', 'all'
370
+ start_date: A ladybug Date object for the start of the period over which
371
+ the schedule_day will be applied. If None, Jan 1 will be used.
372
+ end_date: A ladybug Date object for the end of the period over which
373
+ the schedule_day will be applied. If None, Dec 31 will be used.
374
+ """
375
+ rule = cls(schedule_day, start_date=start_date, end_date=end_date)
376
+ if applicable_days is not None:
377
+ for day in applicable_days:
378
+ rule.apply_day_by_name(day)
379
+ return rule
380
+
381
+ @classmethod
382
+ def from_dict(cls, data):
383
+ """Create a ScheduleRule from a dictionary.
384
+
385
+ Args:
386
+ data: ScheduleRule dictionary following the format below.
387
+
388
+ .. code-block:: python
389
+
390
+ {
391
+ "type": 'ScheduleRule'
392
+ "schedule_day": {
393
+ "type": 'ScheduleDay',
394
+ "identifier": 'Office Occupancy',
395
+ "values": [0, 1, 0],
396
+ "times": [(0, 0), (9, 0), (17, 0)],
397
+ "interpolate": False
398
+ },
399
+ "apply_sunday": False,
400
+ "apply_monday": True,
401
+ "apply_tuesday": True,
402
+ "apply_wednesday": True,
403
+ "apply_thursday": True,
404
+ "apply_friday": True,
405
+ "apply_saturday": False,
406
+ "start_date": (1, 1),
407
+ "end_date": (12, 31)
408
+ }
409
+ """
410
+ assert data['type'] == 'ScheduleRule', \
411
+ 'Expected ScheduleRule. Got {}.'.format(data['type'])
412
+
413
+ schedule_day = ScheduleDay.from_dict(data['schedule_day'])
414
+ sun, mon, tues, wed, thurs, fri, sat, start, end = \
415
+ cls._extract_apply_from_dict(data)
416
+
417
+ return cls(schedule_day, sun, mon, tues, wed, thurs, fri, sat, start, end)
418
+
419
+ @classmethod
420
+ def from_dict_abridged(cls, data, schedule_day):
421
+ """Create a ScheduleRule object from an abridged dictionary.
422
+
423
+ Args:
424
+ data: A ScheduleRuleAbridged dictionary in following the format below.
425
+ schedule_day: A honeybee ScheduleDay object that will be assigned to
426
+ this ScheduleRule.
427
+
428
+ .. code-block:: python
429
+
430
+ {
431
+ "type": 'ScheduleRuleAbridged',
432
+ "schedule_day": str,
433
+ "apply_sunday": False,
434
+ "apply_monday": True,
435
+ "apply_tuesday": True,
436
+ "apply_wednesday": True,
437
+ "apply_thursday": True,
438
+ "apply_friday": True,
439
+ "apply_saturday": False,
440
+ "start_date": (1, 1),
441
+ "end_date": (12, 31)
442
+ }
443
+ """
444
+ assert data['type'] == 'ScheduleRuleAbridged', \
445
+ 'Expected ScheduleRuleAbridged dictionary. Got {}.'.format(data['type'])
446
+
447
+ sun, mon, tues, wed, thurs, fri, sat, start, end = \
448
+ cls._extract_apply_from_dict(data)
449
+
450
+ return cls(schedule_day, sun, mon, tues, wed, thurs, fri, sat, start, end)
451
+
452
+ def to_dict(self, abridged=False):
453
+ """ScheduleRule dictionary representation.
454
+
455
+ Args:
456
+ abridged: Boolean to note whether the full dictionary describing the
457
+ object should be returned (False) or just an abridged version (True),
458
+ which only specifies the identifier of the schedule_day. Default: False.
459
+ """
460
+ base = {'type': 'ScheduleRule'} if not abridged \
461
+ else {'type': 'ScheduleRuleAbridged'}
462
+ base['schedule_day'] = self.schedule_day.to_dict() if not abridged \
463
+ else self.schedule_day.identifier
464
+ base['apply_sunday'] = self.apply_sunday
465
+ base['apply_monday'] = self.apply_monday
466
+ base['apply_tuesday'] = self.apply_tuesday
467
+ base['apply_wednesday'] = self.apply_wednesday
468
+ base['apply_thursday'] = self.apply_thursday
469
+ base['apply_friday'] = self.apply_friday
470
+ base['apply_saturday'] = self.apply_saturday
471
+ base['start_date'] = self.start_date.to_array()
472
+ base['end_date'] = self.end_date.to_array()
473
+ return base
474
+
475
+ def duplicate(self):
476
+ """Get a copy of this object."""
477
+ return self.__copy__()
478
+
479
+ def lock(self):
480
+ """The lock() method will also lock the schedule_day."""
481
+ self._locked = True
482
+ self.schedule_day.lock()
483
+
484
+ def unlock(self):
485
+ """The unlock() method will also unlock the schedule_day."""
486
+ self._locked = False
487
+ self.schedule_day.unlock()
488
+
489
+ @staticmethod
490
+ def extract_all_from_schedule_week(week_idf_string, day_schedule_dict,
491
+ start_date=None, end_date=None):
492
+ """Extract all ScheduleRule objects from an IDF string of a Schedule:Week.
493
+
494
+ Args:
495
+ week_idf_string: A text string fully describing an EnergyPlus
496
+ Schedule:Week:Daily or Schedule:Week:Compact.
497
+ day_schedule_dict: A dictionary with the identifiers of ScheduleDay objects
498
+ as keys and the corresponding ScheduleDay objects as values. These objects
499
+ will be used to build the ScheduleRules using the week_idf_string.
500
+ start_date: A ladybug Date object for the start of the period over which
501
+ the ScheduleRules apply. If None, Jan 1 will be used.
502
+ end_date: A ladybug Date object for the end of the period over which
503
+ the ScheduleRules apply. If None, Dec 31 will be used.
504
+
505
+ Returns:
506
+ schedule_rules -- A list of ScheduleRule objects that together describe
507
+ the Schedule:Week.
508
+ """
509
+ schedule_rules = []
510
+ if week_idf_string.startswith('Schedule:Week:Daily,'):
511
+ ep_strs = parse_idf_string(week_idf_string)
512
+ applied_day_ids = []
513
+ for i, day_sch_id in enumerate(ep_strs[1:8]):
514
+ if day_sch_id not in applied_day_ids: # make a new rule
515
+ rule = ScheduleRule(day_schedule_dict[day_sch_id],
516
+ start_date=start_date, end_date=end_date)
517
+ rule.apply_day_by_dow(i + 1)
518
+ schedule_rules.append(rule)
519
+ applied_day_ids.append(day_sch_id)
520
+ else: # edit one of the existing rules to apply it to the new day
521
+ sch_rule_index = applied_day_ids.index(day_sch_id)
522
+ rule = schedule_rules[sch_rule_index]
523
+ rule.apply_day_by_dow(i + 1)
524
+ else:
525
+ ep_strs = parse_idf_string(week_idf_string, 'Schedule:Week:Compact,')
526
+ for i in range(1, len(ep_strs), 2):
527
+ day_type, day_sch_id = ep_strs[i].lower(), ep_strs[i + 1]
528
+ rule = ScheduleRule(day_schedule_dict[day_sch_id])
529
+ if 'alldays' in day_type:
530
+ rule.apply_all = True
531
+ elif 'weekdays' in day_type:
532
+ rule.apply_weekday = True
533
+ elif 'weekends' in day_type:
534
+ rule.apply_weekend = True
535
+ elif 'sunday' in day_type:
536
+ rule.apply_sunday = True
537
+ elif 'monday' in day_type:
538
+ rule.apply_monday = True
539
+ elif 'tuesday' in day_type:
540
+ rule.apply_tuesday = True
541
+ elif 'wednesday' in day_type:
542
+ rule.apply_wednesday = True
543
+ elif 'thursday' in day_type:
544
+ rule.apply_thursday = True
545
+ elif 'friday' in day_type:
546
+ rule.apply_friday = True
547
+ elif 'saturday' in day_type:
548
+ rule.apply_saturday = True
549
+ elif 'allotherdays' in day_type:
550
+ apply_mtx = [rul.week_apply_tuple for rul in schedule_rules]
551
+ for j, dow in enumerate(zip(*apply_mtx)):
552
+ if not any(dow):
553
+ rule.apply_day_by_dow(j + 1)
554
+ if len(rule.days_applied) != 0:
555
+ schedule_rules.append(rule)
556
+ return schedule_rules
557
+
558
+ @staticmethod
559
+ def _extract_apply_from_dict(data):
560
+ """Extract the apply values from a dictionary."""
561
+ apply_sunday = data['apply_sunday'] if 'apply_sunday' in data else False
562
+ apply_monday = data['apply_monday'] if 'apply_monday' in data else False
563
+ apply_tuesday = data['apply_tuesday'] if 'apply_tuesday' in data else False
564
+ apply_wednesday = data['apply_wednesday'] if 'apply_wednesday' in data else False
565
+ apply_thursday = data['apply_thursday'] if 'apply_thursday' in data else False
566
+ apply_friday = data['apply_friday'] if 'apply_friday' in data else False
567
+ apply_saturday = data['apply_saturday'] if 'apply_saturday' in data else False
568
+ start_date = Date.from_array(data['start_date']) if \
569
+ 'start_date' in data else ScheduleRule._year_start
570
+ end_date = Date.from_array(data['end_date']) if \
571
+ 'end_date' in data else ScheduleRule._year_end
572
+
573
+ return apply_sunday, apply_monday, apply_tuesday, apply_wednesday, \
574
+ apply_thursday, apply_friday, apply_saturday, start_date, end_date
575
+
576
+ @staticmethod
577
+ def _check_date(date, date_name='date'):
578
+ assert isinstance(date, Date), 'Expected ladybug Date for ' \
579
+ 'ScheduleRule {}. Got {}.'.format(date_name, type(date))
580
+
581
+ @staticmethod
582
+ def _doy_non_leap_year(date):
583
+ """Get a doy for a non-leap-year even when the input date is for a leap year."""
584
+ if not date.leap_year:
585
+ return date.doy
586
+ else:
587
+ return date.doy if date <= Date(2, 29, True) else date.doy - 1
588
+
589
+ def __key(self):
590
+ """A tuple based on the object properties, useful for hashing."""
591
+ return (hash(self.schedule_day), self.schedule_day, self.apply_sunday,
592
+ self.apply_monday, self.apply_tuesday, self.apply_wednesday,
593
+ self.apply_thursday, self.apply_friday, self.apply_saturday,
594
+ hash(self.start_date), hash(self.end_date))
595
+
596
+ def __hash__(self):
597
+ return hash(self.__key())
598
+
599
+ def __eq__(self, other):
600
+ return isinstance(other, ScheduleRule) and self.__key() == other.__key()
601
+
602
+ def __ne__(self, other):
603
+ return not self.__eq__(other)
604
+
605
+ def __copy__(self):
606
+ return ScheduleRule(
607
+ self.schedule_day.duplicate(), self.apply_sunday,
608
+ self.apply_monday, self.apply_tuesday, self.apply_wednesday,
609
+ self.apply_thursday, self.apply_friday, self.apply_saturday,
610
+ self.start_date, self.end_date)
611
+
612
+ def ToString(self):
613
+ """Overwrite .NET ToString."""
614
+ return self.__repr__()
615
+
616
+ def __repr__(self):
617
+ return 'ScheduleRule: {} [days applied: {}] [date range: {} - {}]'.format(
618
+ self.schedule_day.display_name, ', '.join(self.days_applied),
619
+ self.start_date, self.end_date)