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,646 @@
1
+ # coding=utf-8
2
+ """Object to hold EnergyPlus simulation outputs."""
3
+ from __future__ import division
4
+
5
+ from honeybee.typing import float_in_range
6
+
7
+ from ..reader import parse_idf_string
8
+ from ..writer import generate_idf_string
9
+
10
+
11
+ class SimulationOutput(object):
12
+ """Object to hold EnergyPlus simulation outputs.
13
+
14
+ Args:
15
+ outputs: A list of EnergyPlus output names as strings, which are requested
16
+ from the simulation. If None, no outputs will be requested.
17
+ Note that this object does not check whether the outputs exist
18
+ within the EnergyPlus IDD or are request-able from a given Model.
19
+ (eg. ['Zone Ideal Loads Supply Air Total Cooling Energy']).
20
+ Default: None.
21
+ reporting_frequency: Text for the frequency at which the outputs
22
+ are reported. Default: 'Hourly'.
23
+ Choose from the following:
24
+
25
+ * Annual
26
+ * Monthly
27
+ * Daily
28
+ * Hourly
29
+ * Timestep
30
+
31
+ include_sqlite: Boolean to note whether a SQLite report should be
32
+ generated from the simulation, which contains all of the outputs and
33
+ summary_reports. Default: True.
34
+ include_html: Boolean to note whether an HTML report should be generated
35
+ from the simulation, which contains all of the summary_reports.
36
+ Default: True.
37
+ summary_reports: An array of EnergyPlus summary report names as strings.
38
+ An empty list or None will result in no summary reports.
39
+ Default: ('AllSummary',). See the Input Output Reference SummaryReports
40
+ section for a full list of all reports that can be requested.
41
+ (https://bigladdersoftware.com/epx/docs/9-1/input-output-reference/\
42
+ output-table-summaryreports.html#outputtablesummaryreports).
43
+ unmet_setpoint_tolerance: A number in degrees Celsius for the difference that
44
+ the zone conditions must be from the thermostat setpoint in order
45
+ for the setpoint to be considered unmet. This will affect how unmet
46
+ hours are reported in the output. ASHRAE 90.1 uses a tolerance of
47
+ 1.11C, which is equivalent to 1.8F. (Default: 1.11C).
48
+
49
+ Properties:
50
+ * outputs
51
+ * reporting_frequency
52
+ * include_sqlite
53
+ * include_html
54
+ * summary_reports
55
+ * unmet_setpoint_tolerance
56
+ """
57
+ __slots__ = ('_outputs', '_reporting_frequency', '_include_sqlite',
58
+ '_include_html', '_summary_reports', '_unmet_setpoint_tolerance')
59
+ REPORTING_FREQUENCIES = ('Annual', 'Monthly', 'Daily', 'Hourly', 'Timestep')
60
+
61
+ def __init__(self, outputs=None, reporting_frequency='Hourly', include_sqlite=True,
62
+ include_html=True, summary_reports=('AllSummary',),
63
+ unmet_setpoint_tolerance=1.11):
64
+ """Initialize SimulationOutput."""
65
+ self.outputs = outputs
66
+ self.reporting_frequency = reporting_frequency
67
+ self.include_sqlite = include_sqlite
68
+ self.include_html = include_html
69
+ self.summary_reports = summary_reports
70
+ self.unmet_setpoint_tolerance = unmet_setpoint_tolerance
71
+
72
+ @property
73
+ def outputs(self):
74
+ """Get or set a tuple of EnergyPlus output names as strings.
75
+
76
+ These outputs will be requested from the simulation and, if None,
77
+ no outputs will be requested.
78
+ """
79
+ return tuple(sorted(self._outputs))
80
+
81
+ @outputs.setter
82
+ def outputs(self, value):
83
+ if value is not None:
84
+ assert not isinstance(value, (str, bytes)), 'Expected list or tuple for ' \
85
+ 'SimulationOutput outputs. Got {}.'.format(type(value))
86
+ vals = []
87
+ for output in value:
88
+ vals.append(str(output))
89
+ value = set(vals)
90
+ else:
91
+ value = set()
92
+ self._outputs = value
93
+
94
+ @property
95
+ def reporting_frequency(self):
96
+ """Get or set text for the frequency at which the outputs are reported.
97
+
98
+ Choose from the following:
99
+
100
+ * Annual
101
+ * Monthly
102
+ * Daily
103
+ * Hourly
104
+ * Timestep
105
+ """
106
+ return self._reporting_frequency
107
+
108
+ @reporting_frequency.setter
109
+ def reporting_frequency(self, value):
110
+ value = value.title()
111
+ assert value in self.REPORTING_FREQUENCIES, 'reporting_frequency {} ' \
112
+ 'is not recognized.\nChoose from the following:\n{}'.format(
113
+ value, self.REPORTING_FREQUENCIES)
114
+ self._reporting_frequency = value
115
+
116
+ @property
117
+ def include_sqlite(self):
118
+ """Get or set a boolean for whether a SQLite report should be generated."""
119
+ return self._include_sqlite
120
+
121
+ @include_sqlite.setter
122
+ def include_sqlite(self, value):
123
+ self._include_sqlite = bool(value)
124
+
125
+ @property
126
+ def include_html(self):
127
+ """Get or set a boolean for whether an HTML report should be generated."""
128
+ return self._include_html
129
+
130
+ @include_html.setter
131
+ def include_html(self, value):
132
+ self._include_html = bool(value)
133
+
134
+ @property
135
+ def summary_reports(self):
136
+ """Get or set a tuple of EnergyPlus summary report names as strings.
137
+
138
+ These reports will be requested from the simulation and, if None,
139
+ no summary reports will be written.
140
+ """
141
+ return tuple(sorted(self._summary_reports))
142
+
143
+ @summary_reports.setter
144
+ def summary_reports(self, value):
145
+ if value is not None:
146
+ assert not isinstance(value, (str, bytes)), 'Expected list, tuple, or ' \
147
+ 'set for SimulationOutput summary_reports. Got {}.'.format(type(value))
148
+ vals = []
149
+ for output in value:
150
+ vals.append(str(output))
151
+ value = set(vals)
152
+ else:
153
+ value = set(('AllSummary',))
154
+ self._summary_reports = value
155
+
156
+ @property
157
+ def unmet_setpoint_tolerance(self):
158
+ """Get or set a number in Celsius for the tolerance of unmet conditions."""
159
+ return self._unmet_setpoint_tolerance
160
+
161
+ @unmet_setpoint_tolerance.setter
162
+ def unmet_setpoint_tolerance(self, value):
163
+ self._unmet_setpoint_tolerance = \
164
+ float_in_range(value, 0, 10, 'unmet setpoint tolerance')
165
+
166
+ def add_summary_report(self, report_name):
167
+ """Add another summary report to the list of requested reports.
168
+
169
+ See the Input Output Reference SummaryReports
170
+ section for a full list of all reports that can be requested.
171
+ (https://bigladdersoftware.com/epx/docs/9-1/input-output-reference/\
172
+ output-table-summaryreports.html#outputtablesummaryreports)
173
+
174
+ Args:
175
+ report_name: The name of an EnergyPlus simulation report to be requested
176
+ from the model. Note that this method does not check whether the
177
+ output exists within the EnergyPlus IDD.
178
+ (eg. 'AnnualBuildingUtilityPerformanceSummary').
179
+ """
180
+ assert isinstance(report_name, str), \
181
+ 'SummaryReport {} is not valid'.format(report_name)
182
+ self._summary_reports.add(report_name)
183
+
184
+ def add_output(self, output_name):
185
+ """Add another output to the list of requested outputs.
186
+
187
+ Args:
188
+ output_name: The name of an EnergyPlus output that is requested
189
+ from the simulation. Note that this method does not check whether
190
+ the output exists within the EnergyPlus IDD or are request-able
191
+ from a given Model.
192
+ (eg. 'Zone Ideal Loads Supply Air Total Cooling Energy').
193
+ """
194
+ self._outputs.add(str(output_name))
195
+
196
+ def add_zone_energy_use(self, load_type='All'):
197
+ """Add outputs for zone energy use when ideal air loads are assigned.
198
+
199
+ This includes, ideal air heating + cooling, lighting, electric + gas
200
+ equipment, and fan electric energy.
201
+
202
+ Args:
203
+ load_type: A text value to set the type of load outputs requested.
204
+ Default: 'All'. Choose from the following:
205
+
206
+ * All - all energy use including heat lost from the zone
207
+ * Total - total load added/removed from the zone (sensible + latent)
208
+ * Sensible - sensible load added/removed to the zone
209
+ * Latent - latent load added/removed to the zone
210
+ """
211
+ load_type = load_type.title()
212
+ if load_type == 'All':
213
+ outputs = ['Zone Ideal Loads Supply Air Total Cooling Energy',
214
+ 'Zone Ideal Loads Supply Air Total Heating Energy',
215
+ 'Zone Lights Electricity Energy',
216
+ 'Zone Electric Equipment Electricity Energy',
217
+ 'Zone Gas Equipment NaturalGas Energy',
218
+ 'Zone Ventilation Fan Electricity Energy',
219
+ 'Water Use Equipment Heating Energy',
220
+ 'Zone Other Equipment Total Heating Energy',
221
+ 'Zone Other Equipment Lost Heat Energy']
222
+ elif load_type == 'Total':
223
+ outputs = ['Zone Ideal Loads Supply Air Total Cooling Energy',
224
+ 'Zone Ideal Loads Supply Air Total Heating Energy',
225
+ 'Zone Lights Total Heating Energy',
226
+ 'Zone Electric Equipment Total Heating Energy',
227
+ 'Zone Gas Equipment Total Heating Energy',
228
+ 'Water Use Equipment Zone Sensible Heat Gain Energy',
229
+ 'Water Use Equipment Zone Latent Gain Energy',
230
+ 'Zone Other Equipment Total Heating Energy']
231
+ elif load_type == 'Sensible':
232
+ outputs = ['Zone Ideal Loads Supply Air Sensible Cooling Energy',
233
+ 'Zone Ideal Loads Supply Air Sensible Heating Energy',
234
+ 'Zone Lights Total Heating Energy',
235
+ 'Zone Electric Equipment Radiant Heating Energy',
236
+ 'Zone Electric Equipment Convective Heating Energy',
237
+ 'Zone Gas Equipment Radiant Heating Energy',
238
+ 'Zone Gas Equipment Convective Heating Energy',
239
+ 'Water Use Equipment Zone Sensible Heat Gain Energy',
240
+ 'Zone Other Equipment Convective Heating Energy',
241
+ 'Zone Other Equipment Radiant Heating Energy']
242
+ elif load_type == 'Latent':
243
+ outputs = ['Zone Ideal Loads Supply Air Latent Cooling Energy',
244
+ 'Zone Ideal Loads Supply Air Latent Heating Energy',
245
+ 'Zone Electric Equipment Latent Gain Energy',
246
+ 'Zone Gas Equipment Latent Gain Energy',
247
+ 'Water Use Equipment Zone Latent Gain Energy',
248
+ 'Zone Other Equipment Latent Heating Energy']
249
+ else:
250
+ raise ValueError('load_type {} is not valid'.format(load_type))
251
+ for outp in outputs:
252
+ self._outputs.add(outp)
253
+
254
+ def add_hvac_energy_use(self):
255
+ """Add outputs for HVAC energy use when detailed systems are assigned.
256
+
257
+ This includes a range of outputs for different pieces of equipment,
258
+ which is meant to catch all energy-consuming parts of a system.
259
+ (eg. chillers, boilers, coils, humidifiers, fans, pumps).
260
+ """
261
+ outputs = ['Cooling Coil Electricity Energy',
262
+ 'Chiller Electricity Energy',
263
+ 'Boiler NaturalGas Energy',
264
+ 'Heating Coil Total Heating Energy',
265
+ 'Heating Coil NaturalGas Energy',
266
+ 'Heating Coil Electricity Energy',
267
+ 'Humidifier Electricity Energy',
268
+ 'Fan Electricity Energy',
269
+ 'Cooling Tower Fan Electricity Energy',
270
+ 'Pump Electricity Energy',
271
+ 'Zone VRF Air Terminal Cooling Electricity Energy',
272
+ 'Zone VRF Air Terminal Heating Electricity Energy',
273
+ 'VRF Heat Pump Cooling Electricity Energy',
274
+ 'VRF Heat Pump Heating Electricity Energy',
275
+ 'VRF Heat Pump Defrost Electricity Energy',
276
+ 'VRF Heat Pump Crankcase Heater Electricity Energy',
277
+ 'Chiller Heater System Cooling Electricity Energy',
278
+ 'Chiller Heater System Heating Electricity Energy',
279
+ 'District Cooling Water Energy',
280
+ 'District Heating Water Energy',
281
+ 'Baseboard Electricity Energy',
282
+ 'Evaporative Cooler Electricity Energy',
283
+ 'Hot_Water_Loop_Central_Air_Source_Heat_Pump Electricity Consumption',
284
+ 'Boiler Electricity Energy',
285
+ 'Water Heater NaturalGas Energy',
286
+ 'Water Heater Electricity Energy',
287
+ 'Cooling Coil Water Heating Electricity Energy']
288
+ for outp in outputs:
289
+ self._outputs.add(outp)
290
+
291
+ def add_gains_and_losses(self, load_type='Total'):
292
+ """Add outputs for zone gains and losses.
293
+
294
+ This includes such as people gains, solar gains, infiltration losses/gains,
295
+ and ventilation losses/gains.
296
+
297
+ Args:
298
+ load_type: A text value to set the type of load outputs requested.
299
+ Default: 'Total'. Choose from the following:
300
+
301
+ * Total - the total load added to the zone (both sensible and latent)
302
+ * Sensible - the sensible load added to the zone
303
+ * Latent - the latent load added to the zone
304
+ """
305
+ load_type = load_type.title()
306
+ always_sensible = [
307
+ 'Zone Windows Total Transmitted Solar Radiation Energy', # remove after E+ 24.2
308
+ 'Enclosure Windows Total Transmitted Solar Radiation Energy',
309
+ 'AFN Zone Infiltration Sensible Heat Gain Energy',
310
+ 'AFN Zone Infiltration Sensible Heat Loss Energy',
311
+ 'AFN Zone Ventilation Sensible Heat Gain Energy',
312
+ 'AFN Zone Ventilation Sensible Heat Loss Energy']
313
+ if load_type == 'Total':
314
+ outputs = ['Zone People Total Heating Energy',
315
+ 'Zone Ideal Loads Zone Total Heating Energy',
316
+ 'Zone Ideal Loads Zone Total Cooling Energy',
317
+ 'Zone Infiltration Total Heat Loss Energy',
318
+ 'Zone Infiltration Total Heat Gain Energy',
319
+ 'Zone Ventilation Sensible Heat Gain Energy',
320
+ 'Zone Ventilation Latent Heat Gain Energy',
321
+ 'Zone Ventilation Sensible Heat Loss Energy',
322
+ 'Zone Ventilation Latent Heat Loss Energy'] + always_sensible
323
+ elif load_type == 'Sensible':
324
+ outputs = ['Zone People Sensible Heating Energy',
325
+ 'Zone Ventilation Sensible Heat Loss Energy',
326
+ 'Zone Ventilation Sensible Heat Gain Energy',
327
+ 'Zone Ideal Loads Zone Sensible Heating Energy',
328
+ 'Zone Ideal Loads Zone Sensible Cooling Energy',
329
+ 'Zone Infiltration Sensible Heat Loss Energy',
330
+ 'Zone Infiltration Sensible Heat Gain Energy'] + always_sensible
331
+ elif load_type == 'Latent':
332
+ outputs = ['Zone People Latent Gain Energy',
333
+ 'Zone Ventilation Latent Heat Loss Energy',
334
+ 'Zone Ventilation Latent Heat Gain Energy',
335
+ 'Zone Ideal Loads Zone Latent Heating Energy',
336
+ 'Zone Ideal Loads Zone Latent Cooling Energy',
337
+ 'Zone Infiltration Latent Heat Loss Energy',
338
+ 'Zone Infiltration Latent Heat Gain Energy',
339
+ 'AFN Zone Infiltration Latent Heat Loss Energy',
340
+ 'AFN Zone Infiltration Latent Heat Gain Energy',
341
+ 'AFN Zone Ventilation Latent Heat Gain Energy',
342
+ 'AFN Zone Ventilation Latent Heat Loss Energy']
343
+ else:
344
+ raise ValueError('load_type {} is not valid'.format(load_type))
345
+ for outp in outputs:
346
+ self._outputs.add(outp)
347
+
348
+ def add_electricity_generation(self):
349
+ """Add outputs related to on-site electricity generation."""
350
+ outputs = ['Facility Total Produced Electricity Energy',
351
+ 'Facility Net Purchased Electricity Energy',
352
+ 'Generator Produced DC Electricity Energy']
353
+ for outp in outputs:
354
+ self._outputs.add(outp)
355
+
356
+ def add_comfort_metrics(self):
357
+ """Add outputs for zone thermal comfort analysis.
358
+
359
+ This includes air temperature, mean radiant temperature, relative
360
+ humidity.
361
+ """
362
+ outputs = ['Zone Operative Temperature',
363
+ 'Zone Mean Air Temperature',
364
+ 'Zone Mean Radiant Temperature',
365
+ 'Zone Air Relative Humidity']
366
+ for outp in outputs:
367
+ self._outputs.add(outp)
368
+
369
+ def add_unmet_hours(self):
370
+ """Add outputs for time that the heating/cooling setpoints are not met."""
371
+ outputs = ['Zone Heating Setpoint Not Met Time',
372
+ 'Zone Cooling Setpoint Not Met Time']
373
+ for outp in outputs:
374
+ self._outputs.add(outp)
375
+
376
+ def add_surface_temperature(self):
377
+ """Add outputs for indoor and outdoor surface temperature."""
378
+ outputs = ['Surface Outside Face Temperature',
379
+ 'Surface Inside Face Temperature']
380
+ for outp in outputs:
381
+ self._outputs.add(outp)
382
+
383
+ def add_surface_energy_flow(self):
384
+ """Add outputs for energy flow across all surfaces."""
385
+ outputs = ['Surface Inside Face Conduction Heat Transfer Energy',
386
+ 'Surface Window Heat Loss Energy',
387
+ 'Surface Window Heat Gain Energy']
388
+ for outp in outputs:
389
+ self._outputs.add(outp)
390
+
391
+ def add_glazing_solar(self):
392
+ """Add outputs for the transmitted solar gain through individual window surfaces.
393
+
394
+ This includes transmitted beam, diffuse, and total solar gain.
395
+ """
396
+ outputs = ['Surface Window Transmitted Beam Solar Radiation Energy',
397
+ 'Surface Window Transmitted Diffuse Solar Radiation Energy',
398
+ 'Surface Window Transmitted Solar Radiation Energy']
399
+ for outp in outputs:
400
+ self._outputs.add(outp)
401
+
402
+ def add_stratification_variables(self):
403
+ """Add outputs for estimating stratification across a zone.
404
+
405
+ This includes all air flow into the zone as well as all heat gain
406
+ to the air.
407
+ """
408
+ outputs = ['Zone Ventilation Standard Density Volume Flow Rate',
409
+ 'Zone Infiltration Standard Density Volume Flow Rate',
410
+ 'Zone Mechanical Ventilation Standard Density Volume Flow Rate',
411
+ 'Zone Air Heat Balance Internal Convective Heat Gain Rate',
412
+ 'Zone Air Heat Balance Surface Convection Rate',
413
+ 'Zone Air Heat Balance System Air Transfer Rate']
414
+ for outp in outputs:
415
+ self._outputs.add(outp)
416
+
417
+ def add_energy_balance_variables(self, load_type='Total'):
418
+ """Add all outputs needed to generate complete energy balance graphics.
419
+
420
+ This includes zone energy use, zone gains and losses, and surface energy flow.
421
+
422
+ Args:
423
+ load_type: A text value to set the type of load outputs requested.
424
+ Default: 'Total'. Choose from the following:
425
+
426
+ * Total - the total load added to the zone (both sensible and latent)
427
+ * Sensible - the sensible load added to the zone
428
+ * Latent - the latent load added to the zone
429
+ """
430
+ self.add_zone_energy_use(load_type)
431
+ self.add_gains_and_losses(load_type)
432
+ self.add_surface_energy_flow()
433
+
434
+ def add_comfort_map_variables(self, include_stratification=True):
435
+ """Add all outputs needed to generate detailed thermal comfort maps.
436
+
437
+ This includes zone air temperatures, surface temperatures, and
438
+ stratification variables.
439
+
440
+ Args:
441
+ include_stratification: Boolean to note whether stratification variables
442
+ should be included.
443
+ """
444
+ outputs = ['Zone Mean Air Temperature', 'Zone Air Relative Humidity']
445
+ for outp in outputs:
446
+ self._outputs.add(outp)
447
+ self.add_surface_temperature()
448
+ if include_stratification:
449
+ self.add_stratification_variables()
450
+
451
+ @classmethod
452
+ def from_idf(cls, table_style=None, output_variables=None, summary_reports=None,
453
+ reporting_tolerance=None, include_sqlite=True):
454
+ """Create a RunPeriod object from an EnergyPlus IDF text string.
455
+
456
+ Args:
457
+ table_style: An IDF OutputControl:Table:Style string.
458
+ output_variables: A list of IDF Output:Variable strings for the requested
459
+ outputs. If None, no outputs will be been requested.
460
+ summary_reports: An IDF Output:Table:SummaryReports string listing
461
+ the summary reports that are requested. If None, no summary
462
+ reports will be requested.
463
+ reporting_tolerance: An IDF OutputControl:ReportingTolerances string.
464
+ include_sqlite: Boolean to note whether a SQLite report should be
465
+ generated from the simulation, which contains all of the outputs and
466
+ summary_reports. Default: True.
467
+ """
468
+ # extract the table_style
469
+ include_html = True
470
+ if table_style is not None:
471
+ style_strs = parse_idf_string(table_style, 'OutputControl:Table:Style,')
472
+ try:
473
+ include_html = True if 'HTML' in style_strs[0].upper() else False
474
+ except IndexError:
475
+ pass # shorter Table:Style without separator
476
+
477
+ # extract the unmet hours reporting tolerance
478
+ unmet_tol = 1.11
479
+ if reporting_tolerance is not None:
480
+ tol_str = parse_idf_string(
481
+ reporting_tolerance, 'OutputControl:ReportingTolerances,')
482
+ try:
483
+ unmet_tol = float(tol_str[0])
484
+ except (IndexError, ValueError, TypeError):
485
+ unmet_tol = 0.2 # shorter ReportingTolerances with default value
486
+
487
+ # extract the output_variables
488
+ outputs = None
489
+ frequency = 'Hourly'
490
+ if output_variables is not None:
491
+ outputs = []
492
+ for out_str in output_variables:
493
+ ep_out_str = parse_idf_string(out_str, 'Output:Variable,')
494
+ outputs.append(ep_out_str[1])
495
+ try:
496
+ frequency = ep_out_str[2] if ep_out_str[2] != '' else 'Hourly'
497
+ except IndexError:
498
+ pass # shorter output variable with default hourly frequency
499
+
500
+ # extract the summary_reports
501
+ reports = None
502
+ if summary_reports is not None:
503
+ reports = parse_idf_string(summary_reports, 'Output:Table:SummaryReports,')
504
+
505
+ return cls(outputs, frequency, include_sqlite, include_html, reports, unmet_tol)
506
+
507
+ @classmethod
508
+ def from_dict(cls, data):
509
+ """Create a SimulationOutput object from a dictionary.
510
+
511
+ Args:
512
+ data: A SimulationOutput dictionary in following the format below.
513
+
514
+ .. code-block:: python
515
+
516
+ {
517
+ "type": "SimulationOutput",
518
+ "outputs": ['Zone Ideal Loads Supply Air Total Cooling Energy'],
519
+ "reporting_frequency": 'Annual',
520
+ "include_sqlite": True,
521
+ "include_html": True,
522
+ "summary_reports": ['AllSummary', 'AnnualBuildingUtilityPerformanceSummary'],
523
+ "unmet_setpoint_tolerance": 0.2
524
+ }
525
+ """
526
+ assert data['type'] == 'SimulationOutput', \
527
+ 'Expected SimulationOutput dictionary. Got {}.'.format(data['type'])
528
+ outputs = data['outputs'] if 'outputs' in data else None
529
+ frequency = data['reporting_frequency'] if \
530
+ 'reporting_frequency' in data else 'Hourly'
531
+ sqlite = data['include_sqlite'] if 'include_sqlite' in data and \
532
+ data['include_sqlite'] is not None else True
533
+ html = data['include_html'] if 'include_html' in data and \
534
+ data['include_html'] is not None else True
535
+ reports = data['summary_reports'] if 'summary_reports' in data else None
536
+ unmet_tol = data['unmet_setpoint_tolerance'] \
537
+ if 'unmet_setpoint_tolerance' in data else 1.11
538
+ return cls(outputs, frequency, sqlite, html, reports, unmet_tol)
539
+
540
+ def to_idf(self):
541
+ """Get EnergyPlus string representations of the SimulationOutput.
542
+
543
+ Returns:
544
+ A tuple with six elements
545
+
546
+ - table_style: An IDF OutputControl:Table:Style string for the simulation.
547
+
548
+ - output_variables: A list of IDF Output:Variable strings for the requested
549
+ outputs. Will be None if no outputs have been requested.
550
+
551
+ - summary_reports: An IDF Output:Table:SummaryReports string
552
+ listing the summary reports that are requested. Will be None
553
+ if no summary reports have not been requested.
554
+
555
+ - sqlite: An IDF Output:SQLite string to request the SQLite file from
556
+ the simulation. Will be None if include_sqlite is False.
557
+
558
+ - variable_dictionary: An IDF Output:VariableDictionary string, which
559
+ will ensure that a .rdd file is generated from the simulation.
560
+
561
+ - unmet_tolerance: An IDF OutputControl:ReportingTolerances string to
562
+ pass the unmet setpoint tolerance to the IDF file.
563
+ """
564
+ style = 'CommaAndHTML' if self.include_html else 'Comma'
565
+ table_style = generate_idf_string(
566
+ 'OutputControl:Table:Style',
567
+ (style, 'None'), ('column separator', 'unit conversion'))
568
+ output_variables = [self._output_to_idf(out_p) for out_p in self.outputs] if \
569
+ len(self._outputs) != 0 else None
570
+ r_comments = ['report {}'.format(i) for i in range(len(self._summary_reports))]
571
+ summary_reports = generate_idf_string(
572
+ 'Output:Table:SummaryReports', self.summary_reports, r_comments) if \
573
+ len(self._summary_reports) != 0 else None
574
+ sqlite = generate_idf_string(
575
+ 'Output:SQLite', ('SimpleAndTabular',), ('option type',)) if \
576
+ self.include_sqlite else None
577
+ variable_dictionary = generate_idf_string(
578
+ 'Output:VariableDictionary', ('IDF', 'Unsorted'),
579
+ ('key field', 'sort option'))
580
+ unmet_tolerance = generate_idf_string(
581
+ 'OutputControl:ReportingTolerances',
582
+ (self.unmet_setpoint_tolerance, self.unmet_setpoint_tolerance),
583
+ ('heating unmet setpoint tolerance', 'cooling unmet setpoint tolerance'))
584
+ return table_style, output_variables, summary_reports, sqlite, \
585
+ variable_dictionary, unmet_tolerance
586
+
587
+ def to_dict(self):
588
+ """DaylightSavingTime dictionary representation."""
589
+ base = {'type': 'SimulationOutput',
590
+ 'reporting_frequency': self.reporting_frequency}
591
+ if not self.include_sqlite:
592
+ base['include_sqlite'] = False
593
+ if not self.include_html:
594
+ base['include_html'] = False
595
+ if len(self._outputs) != 0:
596
+ base['outputs'] = self.outputs
597
+ if len(self._summary_reports) != 0:
598
+ base['summary_reports'] = self.summary_reports
599
+ if self.unmet_setpoint_tolerance != 1.11:
600
+ base['unmet_setpoint_tolerance'] = self.unmet_setpoint_tolerance
601
+ return base
602
+
603
+ def duplicate(self):
604
+ """Get a copy of this object."""
605
+ return self.__copy__()
606
+
607
+ def _output_to_idf(self, output_name):
608
+ """Convert an output name to an IDF Output:Variable string.
609
+
610
+ .. code-block:: shell
611
+
612
+ Output:Variable,
613
+ *, !- Key Value
614
+ Zone Mean Air Temperature, !- Variable Name
615
+ hourly; !- Timestep
616
+ """
617
+ values = ('*', output_name, self.reporting_frequency)
618
+ comments = ('key value', 'name', 'frequency')
619
+ return generate_idf_string('Output:Variable', values, comments)
620
+
621
+ def ToString(self):
622
+ """Overwrite .NET ToString."""
623
+ return self.__repr__()
624
+
625
+ def __copy__(self):
626
+ return SimulationOutput(
627
+ self._outputs, self.reporting_frequency, self.include_sqlite,
628
+ self.include_html, self._summary_reports, self.unmet_setpoint_tolerance)
629
+
630
+ def __key(self):
631
+ """A tuple based on the object properties, useful for hashing."""
632
+ return self.outputs + self.summary_reports + \
633
+ (self.reporting_frequency, self.include_sqlite, self.include_html,
634
+ self.unmet_setpoint_tolerance)
635
+
636
+ def __hash__(self):
637
+ return hash(self.__key())
638
+
639
+ def __eq__(self, other):
640
+ return isinstance(other, SimulationOutput) and self.__key() == other.__key()
641
+
642
+ def __ne__(self, other):
643
+ return not self.__eq__(other)
644
+
645
+ def __repr__(self):
646
+ return 'SimulationOutput:\n {}'.format('\n '.join(self.outputs))