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,723 @@
1
+ # coding=utf-8
2
+ """Complete definition of a zone program, including schedules and loads."""
3
+ from __future__ import division
4
+ import random
5
+
6
+ from .load.people import People
7
+ from .load.lighting import Lighting
8
+ from .load.equipment import ElectricEquipment, GasEquipment
9
+ from .load.hotwater import ServiceHotWater
10
+ from .load.infiltration import Infiltration
11
+ from .load.ventilation import Ventilation
12
+ from .load.setpoint import Setpoint
13
+
14
+ from honeybee._lockable import lockable
15
+ from honeybee.typing import valid_ep_string, tuple_with_length, clean_and_id_ep_string
16
+
17
+
18
+ @lockable
19
+ class ProgramType(object):
20
+ """Program Type object possessing all schedules and loads defining a program.
21
+
22
+ Args:
23
+ identifier: Text string for a unique ProgramType ID. Must be < 100 characters
24
+ and not contain any EnergyPlus special characters. This will be used to
25
+ identify the object across a model and in the exported IDF.
26
+ people: A People object to describe the occupancy of the program. If None,
27
+ no occupancy will be assumed for the program. (Default: None).
28
+ lighting: A Lighting object to describe the lighting usage of the program.
29
+ If None, no lighting will be assumed for the program. (Default: None).
30
+ electric_equipment: An ElectricEquipment object to describe the usage
31
+ of electric equipment within the program. If None, no electric equipment
32
+ will be assumed for the program. (Default: None).
33
+ gas_equipment: A GasEquipment object to describe the usage of gas equipment
34
+ within the program. If None, no gas equipment will be assumed for
35
+ the program. (Default: None).
36
+ service_hot_water: A ServiceHotWater object to describe the usage of hot
37
+ water within the program. If None, no hot water will be assumed for
38
+ the program. (Default: None).
39
+ infiltration: An Infiltration object to describe the outdoor air leakage of
40
+ the program. If None, no infiltration will be assumed for the program.
41
+ (Default: None).
42
+ ventilation: A Ventilation object to describe the minimum outdoor air
43
+ requirement of the program. If None, no ventilation requirement will
44
+ be assumed for the program. Default: None
45
+ setpoint: A Setpoint object to describe the temperature and humidity
46
+ setpoints of the program. If None, the ProgramType cannot be assigned
47
+ to a Room that is conditioned. (Default: None).
48
+
49
+ Properties:
50
+ * identifier
51
+ * display_name
52
+ * people
53
+ * lighting
54
+ * electric_equipment
55
+ * gas_equipment
56
+ * service_hot_water
57
+ * infiltration
58
+ * ventilation
59
+ * setpoint
60
+ * schedules
61
+ * schedules_unique
62
+ * user_data
63
+ """
64
+ __slots__ = ('_identifier', '_display_name', '_people', '_lighting',
65
+ '_electric_equipment', '_gas_equipment', '_service_hot_water',
66
+ '_infiltration', '_ventilation', '_setpoint', '_locked', '_user_data')
67
+
68
+ def __init__(self, identifier, people=None, lighting=None, electric_equipment=None,
69
+ gas_equipment=None, service_hot_water=None,
70
+ infiltration=None, ventilation=None, setpoint=None):
71
+ """Initialize ProgramType"""
72
+ self._locked = False # unlocked by default
73
+ self.identifier = identifier
74
+ self._display_name = None
75
+ self.people = people
76
+ self.lighting = lighting
77
+ self.electric_equipment = electric_equipment
78
+ self.gas_equipment = gas_equipment
79
+ self.service_hot_water = service_hot_water
80
+ self.infiltration = infiltration
81
+ self.ventilation = ventilation
82
+ self.setpoint = setpoint
83
+ self._user_data = None
84
+
85
+ @property
86
+ def identifier(self):
87
+ """Get or set the text string for a unique program type identifier."""
88
+ return self._identifier
89
+
90
+ @identifier.setter
91
+ def identifier(self, identifier):
92
+ self._identifier = valid_ep_string(identifier, 'program type identifier')
93
+
94
+ @property
95
+ def display_name(self):
96
+ """Get or set a string for the object name without any character restrictions.
97
+
98
+ If not set, this will be equal to the identifier.
99
+ """
100
+ if self._display_name is None:
101
+ return self._identifier
102
+ return self._display_name
103
+
104
+ @display_name.setter
105
+ def display_name(self, value):
106
+ if value is not None:
107
+ try:
108
+ value = str(value)
109
+ except UnicodeEncodeError: # Python 2 machine lacking the character set
110
+ pass # keep it as unicode
111
+ self._display_name = value
112
+
113
+ @property
114
+ def people(self):
115
+ """Get or set a People object to describe the occupancy of the program."""
116
+ return self._people
117
+
118
+ @people.setter
119
+ def people(self, value):
120
+ if value is not None:
121
+ assert isinstance(value, People), 'Expected People object for ' \
122
+ 'ProgramType.people. Got {}.'.format(type(value))
123
+ self._people = value
124
+
125
+ @property
126
+ def lighting(self):
127
+ """Get or set a Lighting object to describe the lighting usage of the program."""
128
+ return self._lighting
129
+
130
+ @lighting.setter
131
+ def lighting(self, value):
132
+ if value is not None:
133
+ assert isinstance(value, Lighting), 'Expected Lighting object for ' \
134
+ 'ProgramType.lighting. Got {}.'.format(type(value))
135
+ self._lighting = value
136
+
137
+ @property
138
+ def electric_equipment(self):
139
+ """Get or set an ElectricEquipment object to describe the usage of equipment."""
140
+ return self._electric_equipment
141
+
142
+ @electric_equipment.setter
143
+ def electric_equipment(self, value):
144
+ if value is not None:
145
+ assert isinstance(value, ElectricEquipment), 'Expected ElectricEquipment ' \
146
+ 'object for ProgramType.electric_equipment. Got {}.'.format(type(value))
147
+ self._electric_equipment = value
148
+
149
+ @property
150
+ def gas_equipment(self):
151
+ """Get or set a GasEquipment object to describe the usage of equipment."""
152
+ return self._gas_equipment
153
+
154
+ @gas_equipment.setter
155
+ def gas_equipment(self, value):
156
+ if value is not None:
157
+ assert isinstance(value, GasEquipment), 'Expected GasEquipment ' \
158
+ 'object for ProgramType.gas_equipment. Got {}.'.format(type(value))
159
+ self._gas_equipment = value
160
+
161
+ @property
162
+ def service_hot_water(self):
163
+ """Get or set a ServiceHotWater object to describe the usage of hot water."""
164
+ return self._service_hot_water
165
+
166
+ @service_hot_water.setter
167
+ def service_hot_water(self, value):
168
+ if value is not None:
169
+ assert isinstance(value, ServiceHotWater), 'Expected ServiceHotWater ' \
170
+ 'object for ProgramType.service_hot_water. Got {}.'.format(type(value))
171
+ self._service_hot_water = value
172
+
173
+ @property
174
+ def infiltration(self):
175
+ """Get or set an Infiltration object to describe the outdoor air leakage."""
176
+ return self._infiltration
177
+
178
+ @infiltration.setter
179
+ def infiltration(self, value):
180
+ if value is not None:
181
+ assert isinstance(value, Infiltration), 'Expected Infiltration ' \
182
+ 'object for ProgramType.infiltration. Got {}.'.format(type(value))
183
+ self._infiltration = value
184
+
185
+ @property
186
+ def ventilation(self):
187
+ """Get or set a Ventilation object to describe the minimum outdoor air flow."""
188
+ return self._ventilation
189
+
190
+ @ventilation.setter
191
+ def ventilation(self, value):
192
+ if value is not None:
193
+ assert isinstance(value, Ventilation), 'Expected Ventilation ' \
194
+ 'object for ProgramType.ventilation. Got {}.'.format(type(value))
195
+ self._ventilation = value
196
+
197
+ @property
198
+ def setpoint(self):
199
+ """Get or set a Setpoint object to describe the temperature setpoints."""
200
+ return self._setpoint
201
+
202
+ @setpoint.setter
203
+ def setpoint(self, value):
204
+ if value is not None:
205
+ assert isinstance(value, Setpoint), 'Expected Setpoint ' \
206
+ 'object for ProgramType.setpoint. Got {}.'.format(type(value))
207
+ self._setpoint = value
208
+
209
+ @property
210
+ def schedules(self):
211
+ """List of all schedules contained within the ProgramType."""
212
+ sched = []
213
+ if self.people is not None:
214
+ sched.append(self.people.occupancy_schedule)
215
+ sched.append(self.people.activity_schedule)
216
+ if self.lighting is not None:
217
+ sched.append(self.lighting.schedule)
218
+ if self.electric_equipment is not None:
219
+ sched.append(self.electric_equipment.schedule)
220
+ if self.gas_equipment is not None:
221
+ sched.append(self.gas_equipment.schedule)
222
+ if self.service_hot_water is not None:
223
+ sched.append(self.service_hot_water.schedule)
224
+ if self.infiltration is not None:
225
+ sched.append(self.infiltration.schedule)
226
+ if self.ventilation is not None and self.ventilation.schedule is not None:
227
+ sched.append(self.ventilation.schedule)
228
+ if self.setpoint is not None:
229
+ sched.append(self.setpoint.heating_schedule)
230
+ sched.append(self.setpoint.cooling_schedule)
231
+ if self.setpoint.humidifying_schedule is not None:
232
+ sched.append(self.setpoint.humidifying_schedule)
233
+ sched.append(self.setpoint.dehumidifying_schedule)
234
+ return sched
235
+
236
+ @property
237
+ def schedules_unique(self):
238
+ """List of all unique schedules contained within the ProgramType."""
239
+ return list(set(self.schedules))
240
+
241
+ @property
242
+ def user_data(self):
243
+ """Get or set an optional dictionary for additional meta data for this object.
244
+
245
+ This will be None until it has been set. All keys and values of this
246
+ dictionary should be of a standard Python type to ensure correct
247
+ serialization of the object to/from JSON (eg. str, float, int, list, dict)
248
+ """
249
+ return self._user_data
250
+
251
+ @user_data.setter
252
+ def user_data(self, value):
253
+ if value is not None:
254
+ assert isinstance(value, dict), 'Expected dictionary for honeybee_energy' \
255
+ 'object user_data. Got {}.'.format(type(value))
256
+ self._user_data = value
257
+
258
+ @classmethod
259
+ def from_dict(cls, data):
260
+ """Create a ProgramType from a dictionary.
261
+
262
+ Note that the dictionary must be a non-abridged version for this
263
+ classmethod to work.
264
+
265
+ Args:
266
+ data: Dictionary describing the ProgramType with the format below.
267
+
268
+ .. code-block:: python
269
+
270
+ {
271
+ "type": 'ProgramType',
272
+ "identifier": str, # ProgramType identifier
273
+ "display_name": str, # ProgramType display name
274
+ 'people': {}, # A People dictionary
275
+ 'lighting': {}, # A Lighting dictionary
276
+ 'electric_equipment': {}, # A ElectricEquipment dictionary
277
+ 'gas_equipment': {}, # A GasEquipment dictionary
278
+ 'service_hot_water': {}, # A ServiceHotWater dictionary
279
+ 'infiltration': {}, # A Infliltration dictionary
280
+ 'ventilation': {}, # A Ventilation dictionary
281
+ 'setpoint': {} # A Setpoint dictionary
282
+ }
283
+
284
+ """
285
+ assert data['type'] == 'ProgramType', \
286
+ 'Expected ProgramType. Got {}.'.format(data['type'])
287
+
288
+ # build each of the load objects
289
+ people = People.from_dict(data['people']) if 'people' in data and \
290
+ data['people'] is not None else None
291
+ lighting = Lighting.from_dict(data['lighting']) if 'lighting' in data and \
292
+ data['lighting'] is not None else None
293
+ electric_equipment = ElectricEquipment.from_dict(data['electric_equipment']) \
294
+ if 'electric_equipment' in data and \
295
+ data['electric_equipment'] is not None else None
296
+ gas_equipment = GasEquipment.from_dict(data['gas_equipment']) \
297
+ if 'gas_equipment' in data and \
298
+ data['gas_equipment'] is not None else None
299
+ shw = ServiceHotWater.from_dict(data['service_hot_water']) \
300
+ if 'service_hot_water' in data and \
301
+ data['service_hot_water'] is not None else None
302
+ infiltration = Infiltration.from_dict(data['infiltration']) if 'infiltration' \
303
+ in data and data['infiltration'] is not None else None
304
+ ventilation = Ventilation.from_dict(data['ventilation']) if 'ventilation' \
305
+ in data and data['ventilation'] is not None else None
306
+ setpoint = Setpoint.from_dict(data['setpoint']) if 'setpoint' in data and \
307
+ data['setpoint'] is not None else None
308
+
309
+ new_obj = cls(data['identifier'], people, lighting, electric_equipment,
310
+ gas_equipment, shw, infiltration, ventilation, setpoint)
311
+ if 'display_name' in data and data['display_name'] is not None:
312
+ new_obj.display_name = data['display_name']
313
+ if 'user_data' in data and data['user_data'] is not None:
314
+ new_obj.user_data = data['user_data']
315
+ return new_obj
316
+
317
+ @classmethod
318
+ def from_dict_abridged(cls, data, schedule_dict):
319
+ """Create a ProgramType object from an abridged dictionary.
320
+
321
+ Args:
322
+ data: A ProgramTypeAbridged dictionary.
323
+ schedule_dict: A dictionary with schedule identifiers as keys and
324
+ honeybee schedule objects as values (either ScheduleRuleset or
325
+ ScheduleFixedInterval). These will be used to assign the schedules
326
+ to the ProgramType object.
327
+
328
+ .. code-block:: python
329
+
330
+ {
331
+ "type": 'ProgramTypeAbridged',
332
+ "identifier": str, # ProgramType identifier
333
+ "display_name": str, # ProgramType display name
334
+ 'people': {}, # A PeopleAbridged dictionary
335
+ 'lighting': {}, # A LightingAbridged dictionary
336
+ 'electric_equipment': {}, # A ElectricEquipmentAbridged dictionary
337
+ 'gas_equipment': {}, # A GasEquipmentAbridged dictionary
338
+ 'service_hot_water': {}, # A ServiceHotWaterAbridged dictionary
339
+ 'infiltration': {}, # A InfiltrationAbridged dictionary
340
+ 'ventilation': {}, # A VentilationAbridged dictionary
341
+ 'setpoint': {} # A SetpointAbridged dictionary
342
+ }
343
+ """
344
+ assert data['type'] == 'ProgramTypeAbridged', \
345
+ 'Expected ProgramTypeAbridged dictionary. Got {}.'.format(data['type'])
346
+
347
+ # build each of the load objects
348
+ try:
349
+ people, lighting, electric_equipment, gas_equipment, shw, infiltration, \
350
+ ventilation, setpoint = cls._get_loads_from_abridged(data, schedule_dict)
351
+ except KeyError as e:
352
+ raise ValueError(
353
+ 'The following schedule is missing from the model: {}'.format(e)
354
+ )
355
+ new_obj = cls(data['identifier'], people, lighting, electric_equipment,
356
+ gas_equipment, shw, infiltration, ventilation, setpoint)
357
+ if 'display_name' in data and data['display_name'] is not None:
358
+ new_obj.display_name = data['display_name']
359
+ if 'user_data' in data and data['user_data'] is not None:
360
+ new_obj.user_data = data['user_data']
361
+ return new_obj
362
+
363
+ def to_dict(self, abridged=False):
364
+ """Get ProgramType as a dictionary.
365
+
366
+ Args:
367
+ abridged: Boolean noting whether detailed schedule objects should be
368
+ written into the ProgramType (False) or just an abridged version (True)
369
+ that references the schedules by identifier. Default: False.
370
+ """
371
+ base = {'type': 'ProgramType'} if not \
372
+ abridged else {'type': 'ProgramTypeAbridged'}
373
+ base['identifier'] = self.identifier
374
+ if self.people is not None:
375
+ base['people'] = self.people.to_dict(abridged)
376
+ if self.lighting is not None:
377
+ base['lighting'] = self.lighting.to_dict(abridged)
378
+ if self.electric_equipment is not None:
379
+ base['electric_equipment'] = self.electric_equipment.to_dict(abridged)
380
+ if self.gas_equipment is not None:
381
+ base['gas_equipment'] = self.gas_equipment.to_dict(abridged)
382
+ if self.service_hot_water is not None:
383
+ base['service_hot_water'] = self.service_hot_water.to_dict(abridged)
384
+ if self.infiltration is not None:
385
+ base['infiltration'] = self.infiltration.to_dict(abridged)
386
+ if self.ventilation is not None:
387
+ base['ventilation'] = self.ventilation.to_dict(abridged)
388
+ if self.setpoint is not None:
389
+ base['setpoint'] = self.setpoint.to_dict(abridged)
390
+
391
+ if self._display_name is not None:
392
+ base['display_name'] = self.display_name
393
+ if self._user_data is not None:
394
+ base['user_data'] = self.user_data
395
+ return base
396
+
397
+ def diversify(self, program_count, occupancy_stdev=20, lighting_stdev=20,
398
+ electric_equip_stdev=20, gas_equip_stdev=20, hot_water_stdev=20,
399
+ infiltration_stdev=20, schedule_offset=1, timestep=1):
400
+ """Get an array of diversified ProgramTypes derived from this "average" one.
401
+
402
+ This method is useful when attempting to account for the fact that not
403
+ all rooms within a building will be used by occupants according to a
404
+ strict regimen. Some rooms will be used more than expected and others less.
405
+
406
+ This method uses a random number generator and gaussian distribution to
407
+ generate loads that vary about the mean program. Note that the randomly
408
+ generated values can be set to something predictable by using the native
409
+ Python random.seed() method before running this method.
410
+
411
+ In addition to diversifying load values, approximately 2/3 of the schedules
412
+ in the output programs will be offset from the mean by the input
413
+ schedule_offset (1/3 ahead and another 1/3 behind).
414
+
415
+ Args:
416
+ program_count: An positive integer for the number of diversified programs
417
+ to generate from this mean program.
418
+ occupancy_stdev: A number between 0 and 100 for the percent of the
419
+ occupancy people_per_area representing one standard deviation
420
+ of diversification from the mean. (Default 20 percent).
421
+ lighting_stdev: A number between 0 and 100 for the percent of the
422
+ lighting watts_per_area representing one standard deviation
423
+ of diversification from the mean. (Default 20 percent).
424
+ electric_equip_stdev: A number between 0 and 100 for the percent of the
425
+ electric equipment watts_per_area representing one standard deviation
426
+ of diversification from the mean. (Default 20 percent).
427
+ gas_equip_stdev: A number between 0 and 100 for the percent of the
428
+ gas equipment watts_per_area representing one standard deviation
429
+ of diversification from the mean. (Default 20 percent).
430
+ hot_water_stdev: A number between 0 and 100 for the percent of the
431
+ service hot water flow_per_area representing one standard deviation
432
+ of diversification from the mean. (Default 20 percent).
433
+ infiltration_stdev: A number between 0 and 100 for the percent of the
434
+ infiltration flow_per_exterior_area representing one standard deviation
435
+ of diversification from the mean. (Default 20 percent).
436
+ schedule_offset: A positive integer for the number of timesteps at which all
437
+ schedules of the resulting programs will be shifted - roughly 1/3 of
438
+ the programs ahead and another 1/3 behind. (Default: 1).
439
+ timestep: An integer for the number of timesteps per hour at which the
440
+ shifting is occurring. This must be a value between 1 and 60, which
441
+ is evenly divisible by 60. 1 indicates that each step is an hour
442
+ while 60 indicates that each step is a minute. (Default: 1).
443
+ """
444
+ # duplicate the input programs so that they can be diversified
445
+ div_programs = [self.duplicate() for i in range(program_count)]
446
+ for program in div_programs:
447
+ program.identifier = clean_and_id_ep_string(self.identifier)
448
+ sch_int = [random.randint(0, 2) for i in range(program_count)]
449
+
450
+ # go through each load and generate diversified versions for the div_programs
451
+ if self.people is not None and occupancy_stdev != 0:
452
+ div_people = self.people.diversify(
453
+ program_count, occupancy_stdev, schedule_offset, timestep, sch_int)
454
+ for i, ppl in enumerate(div_people):
455
+ div_programs[i].people = ppl
456
+ if self.lighting is not None and lighting_stdev != 0:
457
+ div_lighting = self.lighting.diversify(
458
+ program_count, lighting_stdev, schedule_offset, timestep, sch_int)
459
+ for i, light in enumerate(div_lighting):
460
+ div_programs[i].lighting = light
461
+ if self.electric_equipment is not None and electric_equip_stdev != 0:
462
+ div_e_equipment = self.electric_equipment.diversify(
463
+ program_count, electric_equip_stdev, schedule_offset, timestep, sch_int)
464
+ for i, e_equip in enumerate(div_e_equipment):
465
+ div_programs[i].electric_equipment = e_equip
466
+ if self.gas_equipment is not None and gas_equip_stdev != 0:
467
+ div_g_equipment = self.gas_equipment.diversify(
468
+ program_count, gas_equip_stdev, schedule_offset, timestep, sch_int)
469
+ for i, g_equip in enumerate(div_g_equipment):
470
+ div_programs[i].gas_equipment = g_equip
471
+ if self.service_hot_water is not None and hot_water_stdev != 0:
472
+ div_hot_water = self.service_hot_water.diversify(
473
+ program_count, hot_water_stdev, schedule_offset, timestep, sch_int)
474
+ for i, shw in enumerate(div_hot_water):
475
+ div_programs[i].service_hot_water = shw
476
+ if self.infiltration is not None and infiltration_stdev != 0:
477
+ div_infiltration = self.infiltration.diversify(
478
+ program_count, infiltration_stdev, schedule_offset, timestep, sch_int)
479
+ for i, inf in enumerate(div_infiltration):
480
+ div_programs[i].infiltration = inf
481
+ if self.setpoint is not None and schedule_offset != 0:
482
+ div_setpoint = self.setpoint.diversify(
483
+ program_count, schedule_offset, timestep, sch_int)
484
+ for i, setpt in enumerate(div_setpoint):
485
+ div_programs[i].setpoint = setpt
486
+ return div_programs
487
+
488
+ @staticmethod
489
+ def average(identifier, program_types, weights=None, timestep_resolution=1):
490
+ """Get a ProgramType object that's a weighted average between other objects.
491
+
492
+ Args:
493
+ identifier: A unique ID text string for the new averaged ProgramType.
494
+ Must be < 100 characters and not contain any EnergyPlus special
495
+ characters. This will be used to identify the object across a model
496
+ and in the exported IDF.
497
+ program_types: A list of ProgramType objects that will be averaged
498
+ together to make a new ProgramType.
499
+ weights: An optional list of fractional numbers with the same length
500
+ as the input program_types that sum to 1. These will be used to weight
501
+ each of the ProgramType objects in the resulting average. If None, the
502
+ individual objects will be weighted equally. (Default: None).
503
+ timestep_resolution: An optional integer for the timestep resolution
504
+ at which the schedules will be averaged. Any schedule details
505
+ smaller than this timestep will be lost in the averaging process.
506
+ (Default: 1).
507
+ """
508
+ # check the weights input
509
+ if weights is None:
510
+ weights = [1 / len(program_types)] * len(program_types) if \
511
+ len(program_types) > 0 else []
512
+ else:
513
+ weights = tuple_with_length(weights, len(program_types), float,
514
+ 'average ProgramType weights')
515
+ assert abs(sum(weights) - 1.0) <= 1e-3, 'Average ProgramType weights ' \
516
+ 'must be equal to 1. Got {}.'.format(sum(weights))
517
+
518
+ # gather all of the load objects across all of the programs
519
+ people_mtx = [[pr.people, w] for pr, w in zip(program_types, weights)
520
+ if pr.people is not None]
521
+ lighting_mtx = [[pr.lighting, w] for pr, w in zip(program_types, weights)
522
+ if pr.lighting is not None]
523
+ e_equip_mtx = [[p.electric_equipment, w] for p, w in zip(program_types, weights)
524
+ if p.electric_equipment is not None]
525
+ g_equip_mtx = [[pr.gas_equipment, w] for pr, w in zip(program_types, weights)
526
+ if pr.gas_equipment is not None]
527
+ shw_mtx = [[pr.service_hot_water, w] for pr, w in zip(program_types, weights)
528
+ if pr.service_hot_water is not None]
529
+ inf_mtx = [[pr.infiltration, w] for pr, w in zip(program_types, weights)
530
+ if pr.infiltration is not None]
531
+ vent_mtx = [[pr.ventilation, w] for pr, w in zip(program_types, weights)
532
+ if pr.ventilation is not None]
533
+ setp_mtx = [[pr.setpoint, w] for pr, w in zip(program_types, weights)
534
+ if pr.setpoint is not None]
535
+
536
+ # compute the average loads
537
+ people = None
538
+ if len(people_mtx) != 0:
539
+ t_people_mtx = tuple(zip(*people_mtx))
540
+ people = People.average('{}_People'.format(identifier), t_people_mtx[0],
541
+ t_people_mtx[1], timestep_resolution)
542
+ lighting = None
543
+ if len(lighting_mtx) != 0:
544
+ t_lighting_mtx = tuple(zip(*lighting_mtx))
545
+ lighting = Lighting.average(
546
+ '{}_Lighting'.format(identifier), t_lighting_mtx[0], t_lighting_mtx[1],
547
+ timestep_resolution)
548
+ electric_equipment = None
549
+ if len(e_equip_mtx) != 0:
550
+ t_e_equip_mtx = tuple(zip(*e_equip_mtx))
551
+ electric_equipment = ElectricEquipment.average(
552
+ '{}_Electric Equipment'.format(identifier), t_e_equip_mtx[0],
553
+ t_e_equip_mtx[1], timestep_resolution)
554
+ gas_equipment = None
555
+ if len(g_equip_mtx) != 0:
556
+ t_g_equip_mtx = tuple(zip(*g_equip_mtx))
557
+ gas_equipment = GasEquipment.average(
558
+ '{}_Gas Equipment'.format(identifier), t_g_equip_mtx[0],
559
+ t_g_equip_mtx[1], timestep_resolution)
560
+ shw = None
561
+ if len(shw_mtx) != 0:
562
+ t_shw_mtx = tuple(zip(*shw_mtx))
563
+ shw = ServiceHotWater.average(
564
+ '{}_Service Hot Water'.format(identifier), t_shw_mtx[0],
565
+ t_shw_mtx[1], timestep_resolution)
566
+ infiltration = None
567
+ if len(inf_mtx) != 0:
568
+ t_inf_mtx = tuple(zip(*inf_mtx))
569
+ infiltration = Infiltration.average(
570
+ '{}_Infiltration'.format(identifier), t_inf_mtx[0],
571
+ t_inf_mtx[1], timestep_resolution)
572
+ ventilation = None
573
+ if len(vent_mtx) != 0:
574
+ t_vent_mtx = tuple(zip(*vent_mtx))
575
+ ventilation = Ventilation.average(
576
+ '{}_Ventilation'.format(identifier), t_vent_mtx[0],
577
+ t_vent_mtx[1], timestep_resolution)
578
+ setpoint = None
579
+ if len(setp_mtx) != 0:
580
+ t_setp_mtx = tuple(zip(*setp_mtx))
581
+ setpoint = Setpoint.average('{}_Setpoint'.format(identifier), t_setp_mtx[0],
582
+ t_setp_mtx[1], timestep_resolution)
583
+
584
+ # return the averaged object
585
+ return ProgramType(
586
+ identifier, people, lighting, electric_equipment, gas_equipment, shw,
587
+ infiltration, ventilation, setpoint)
588
+
589
+ def duplicate(self):
590
+ """Get a copy of this object."""
591
+ return self.__copy__()
592
+
593
+ def lock(self):
594
+ """The lock() method to will also lock the loads."""
595
+ self._locked = True
596
+ if self.people is not None:
597
+ self.people.lock()
598
+ if self.lighting is not None:
599
+ self.lighting.lock()
600
+ if self.electric_equipment is not None:
601
+ self.electric_equipment.lock()
602
+ if self.gas_equipment is not None:
603
+ self.gas_equipment.lock()
604
+ if self.service_hot_water is not None:
605
+ self.service_hot_water.lock()
606
+ if self.infiltration is not None:
607
+ self.infiltration.lock()
608
+ if self.ventilation is not None:
609
+ self.ventilation.lock()
610
+ if self.setpoint is not None:
611
+ self.setpoint.lock()
612
+
613
+ def unlock(self):
614
+ """The unlock() method will also unlock the loads."""
615
+ self._locked = False
616
+ if self.people is not None:
617
+ self.people.unlock()
618
+ if self.lighting is not None:
619
+ self.lighting.unlock()
620
+ if self.electric_equipment is not None:
621
+ self.electric_equipment.unlock()
622
+ if self.gas_equipment is not None:
623
+ self.gas_equipment.unlock()
624
+ if self.service_hot_water is not None:
625
+ self.service_hot_water.unlock()
626
+ if self.infiltration is not None:
627
+ self.infiltration.unlock()
628
+ if self.ventilation is not None:
629
+ self.ventilation.unlock()
630
+ if self.setpoint is not None:
631
+ self.setpoint.unlock()
632
+
633
+ def ToString(self):
634
+ """Overwrite .NET ToString."""
635
+ return self.__repr__()
636
+
637
+ @staticmethod
638
+ def _get_loads_from_abridged(data, schedule_dict):
639
+ """Get re-built load objects from abridged dictionaries."""
640
+ people = None
641
+ lighting = None
642
+ electric_equipment = None
643
+ gas_equipment = None
644
+ shw = None
645
+ infiltration = None
646
+ ventilation = None
647
+ setpoint = None
648
+ if 'people' in data and data['people'] is not None:
649
+ people = People.from_dict_abridged(data['people'], schedule_dict)
650
+ if 'lighting' in data and data['lighting'] is not None:
651
+ lighting = Lighting.from_dict_abridged(data['lighting'], schedule_dict)
652
+ if 'electric_equipment' in data and data['electric_equipment'] is not None:
653
+ electric_equipment = ElectricEquipment.from_dict_abridged(
654
+ data['electric_equipment'], schedule_dict)
655
+ if 'gas_equipment' in data and data['gas_equipment'] is not None:
656
+ gas_equipment = GasEquipment.from_dict_abridged(
657
+ data['gas_equipment'], schedule_dict)
658
+ if 'service_hot_water' in data and data['service_hot_water'] is not None:
659
+ shw = ServiceHotWater.from_dict_abridged(
660
+ data['service_hot_water'], schedule_dict)
661
+ if 'infiltration' in data and data['infiltration'] is not None:
662
+ infiltration = Infiltration.from_dict_abridged(
663
+ data['infiltration'], schedule_dict)
664
+ if 'ventilation' in data and data['ventilation'] is not None:
665
+ ventilation = Ventilation.from_dict_abridged(
666
+ data['ventilation'], schedule_dict)
667
+ if 'setpoint' in data and data['setpoint'] is not None:
668
+ setpoint = Setpoint.from_dict_abridged(data['setpoint'], schedule_dict)
669
+ return people, lighting, electric_equipment, gas_equipment, shw, \
670
+ infiltration, ventilation, setpoint
671
+
672
+ @staticmethod
673
+ def _instance_in_array(object_instance, object_array):
674
+ """Check if a specific object instance is already in an array.
675
+
676
+ This can be much faster than `if object_instance in object_array`
677
+ when you expect to be testing a lot of the same instance of an object for
678
+ inclusion in an array since the builtin method uses an == operator to
679
+ test inclusion.
680
+ """
681
+ for val in object_array:
682
+ if val is object_instance:
683
+ return True
684
+ return False
685
+
686
+ def __copy__(self):
687
+ people = self.people.duplicate() if self.people is not None else None
688
+ lighting = self.lighting.duplicate() if self.lighting is not None else None
689
+ electric_equipment = self.electric_equipment.duplicate() if \
690
+ self.electric_equipment is not None else None
691
+ gas_equipment = self.gas_equipment.duplicate() if \
692
+ self.gas_equipment is not None else None
693
+ shw = self.service_hot_water.duplicate() if \
694
+ self.service_hot_water is not None else None
695
+ infiltration = self.infiltration.duplicate() if \
696
+ self.infiltration is not None else None
697
+ ventilation = self.ventilation.duplicate() if \
698
+ self.ventilation is not None else None
699
+ setpoint = self.setpoint.duplicate() if self.setpoint is not None else None
700
+ new_obj = ProgramType(self.identifier, people, lighting, electric_equipment,
701
+ gas_equipment, shw, infiltration, ventilation, setpoint)
702
+ new_obj._display_name = self._display_name
703
+ new_obj._user_data = None if self._user_data is None else self._user_data.copy()
704
+ return new_obj
705
+
706
+ def __key(self):
707
+ """A tuple based on the object properties, useful for hashing."""
708
+ return (self.identifier, hash(self.people), hash(self.lighting),
709
+ hash(self.electric_equipment), hash(self.gas_equipment),
710
+ hash(self.service_hot_water), hash(self.infiltration),
711
+ hash(self.ventilation), hash(self.setpoint))
712
+
713
+ def __hash__(self):
714
+ return hash(self.__key())
715
+
716
+ def __eq__(self, other):
717
+ return isinstance(other, ProgramType) and self.__key() == other.__key()
718
+
719
+ def __ne__(self, other):
720
+ return not self.__eq__(other)
721
+
722
+ def __repr__(self):
723
+ return 'Program Type: {}'.format(self.display_name)