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,606 @@
1
+ # coding=utf-8
2
+ """Complete set of EnergyPlus Simulation Settings."""
3
+ from __future__ import division
4
+
5
+ from .output import SimulationOutput
6
+ from .runperiod import RunPeriod
7
+ from .control import SimulationControl
8
+ from .shadowcalculation import ShadowCalculation
9
+ from .sizing import SizingParameter
10
+ from ..reader import parse_idf_string
11
+ from ..writer import generate_idf_string
12
+
13
+ from honeybee.typing import int_positive, float_in_range
14
+ from ladybug_geometry.geometry2d.pointvector import Vector2D
15
+
16
+ import re
17
+ import math
18
+
19
+
20
+ class SimulationParameter(object):
21
+ """Complete set of EnergyPlus Simulation Settings.
22
+
23
+ Args:
24
+ output: A SimulationOutput that lists the desired outputs from the
25
+ simulation and the format in which to report them. If None, no
26
+ outputs will be requested. Default: None.
27
+ run_period: A RunPeriod object to describe the time period over which to
28
+ run the simulation. Default: Run for the whole year starting on Sunday.
29
+ timestep: An integer for the number of timesteps per hour at which the
30
+ calculation will be run. Default: 6.
31
+ simulation_control: A SimulationControl object that describes which types
32
+ of calculations to run. Default: perform a sizing calculation but only
33
+ run the simulation for the RunPeriod.
34
+ shadow_calculation: A ShadowCalculation object describing settings for
35
+ the EnergyPlus Shadow Calculation. Default: Average over 30 days with
36
+ FullInteriorAndExteriorWithReflections.
37
+ sizing_parameter: A SizingParameter object with criteria for sizing the
38
+ heating and cooling system.
39
+ north_angle: North angle in degrees. A number between -360 and 360 for the
40
+ counterclockwise difference between the North and the positive Y-axis in
41
+ degrees. 90 is West and 270 is East (Default: 0).
42
+ terrain_type: Text for the terrain type in which the model sits.
43
+ Choose from: 'Ocean', 'Country', 'Suburbs', 'Urban', 'City'.(Default: 'City')
44
+
45
+ Properties:
46
+ * output
47
+ * run_period
48
+ * timestep
49
+ * simulation_control
50
+ * shadow_calculation
51
+ * sizing_parameter
52
+ * global_geometry_rules
53
+ * north_angle
54
+ * north_vector
55
+ * terrain_type
56
+ """
57
+ __slots__ = ('_output', '_run_period', '_timestep', '_simulation_control',
58
+ '_shadow_calculation', '_sizing_parameter', '_north_angle',
59
+ '_north_vector', '_terrain_type')
60
+ VALIDTIMESTEPS = (1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60)
61
+ TERRAIN_TYPES = ('Ocean', 'Country', 'Suburbs', 'Urban', 'City')
62
+
63
+ def __init__(self, output=None, run_period=None, timestep=6,
64
+ simulation_control=None, shadow_calculation=None, sizing_parameter=None,
65
+ north_angle=0, terrain_type='City'):
66
+ """Initialize SimulationParameter."""
67
+ self.output = output
68
+ self.run_period = run_period
69
+ self.timestep = timestep
70
+ self.simulation_control = simulation_control
71
+ self.shadow_calculation = shadow_calculation
72
+ self.sizing_parameter = sizing_parameter
73
+ self.north_angle = north_angle
74
+ self.terrain_type = terrain_type
75
+
76
+ @property
77
+ def output(self):
78
+ """Get or set a SimulationOutput object for the outputs from the simulation."""
79
+ return self._output
80
+
81
+ @output.setter
82
+ def output(self, value):
83
+ if value is not None:
84
+ assert isinstance(value, SimulationOutput), 'Expected SimulationOutput ' \
85
+ 'for SimulationParameter output. Got {}.'.format(type(value))
86
+ self._output = value
87
+ else:
88
+ self._output = SimulationOutput()
89
+
90
+ @property
91
+ def run_period(self):
92
+ """Get or set a RunPeriod object for the time period to run the simulation."""
93
+ return self._run_period
94
+
95
+ @run_period.setter
96
+ def run_period(self, value):
97
+ if value is not None:
98
+ assert isinstance(value, RunPeriod), 'Expected RunPeriod for ' \
99
+ 'SimulationParameter run_period. Got {}.'.format(type(value))
100
+ self._run_period = value
101
+ else:
102
+ self._run_period = RunPeriod()
103
+
104
+ @property
105
+ def timestep(self):
106
+ """Get or set a integer for the number of simulation timesteps per hour."""
107
+ return self._timestep
108
+
109
+ @timestep.setter
110
+ def timestep(self, value):
111
+ value = int_positive(value, 'simulation parameter timestep')
112
+ assert value in self.VALIDTIMESTEPS, 'SimulationParameter timestep "{}" is ' \
113
+ 'invalid. Must be one of the following:{}'.format(value, self.VALIDTIMESTEPS)
114
+ self._timestep = value
115
+
116
+ @property
117
+ def simulation_control(self):
118
+ """Get or set a SimulationControl object for which types of calculations to run.
119
+ """
120
+ return self._simulation_control
121
+
122
+ @simulation_control.setter
123
+ def simulation_control(self, value):
124
+ if value is not None:
125
+ assert isinstance(value, SimulationControl), 'Expected SimulationControl ' \
126
+ 'for SimulationParameter run_period. Got {}.'.format(type(value))
127
+ self._simulation_control = value
128
+ else:
129
+ self._simulation_control = SimulationControl()
130
+
131
+ @property
132
+ def shadow_calculation(self):
133
+ """Get or set a ShadowCalculation object with settings for the shadow calculation.
134
+ """
135
+ return self._shadow_calculation
136
+
137
+ @shadow_calculation.setter
138
+ def shadow_calculation(self, value):
139
+ if value is not None:
140
+ assert isinstance(value, ShadowCalculation), 'Expected ShadowCalculation ' \
141
+ 'for SimulationParameter shadow_calculation. Got {}.'.format(type(value))
142
+ self._shadow_calculation = value
143
+ else:
144
+ self._shadow_calculation = ShadowCalculation()
145
+
146
+ @property
147
+ def sizing_parameter(self):
148
+ """Get or set a SizingParameter object with factors for the peak loads."""
149
+ return self._sizing_parameter
150
+
151
+ @sizing_parameter.setter
152
+ def sizing_parameter(self, value):
153
+ if value is not None:
154
+ assert isinstance(value, SizingParameter), 'Expected SizingParameter ' \
155
+ 'for SimulationParameter sizing_parameter. Got {}.'.format(type(value))
156
+ self._sizing_parameter = value
157
+ else:
158
+ self._sizing_parameter = SizingParameter()
159
+
160
+ @property
161
+ def global_geometry_rules(self):
162
+ """Get an IDF string for the official honeybee global geometry rules.
163
+
164
+ Specifically, these are counter-clockwise vertices starting from the
165
+ upper left corner of the surface. The output string is the following:
166
+
167
+ .. code-block:: shell
168
+
169
+ GlobalGeometryRules,
170
+ UpperLeftCorner, !- starting vertex position
171
+ Counterclockwise, !- vertex entry direction
172
+ Relative; !- coordinate system
173
+ """
174
+ values = ('UpperLeftCorner', 'Counterclockwise', 'Relative')
175
+ comments = ('starting vertex position', 'vertex entry direction',
176
+ 'coordinate system')
177
+ return generate_idf_string('GlobalGeometryRules', values, comments)
178
+
179
+ @property
180
+ def north_angle(self):
181
+ """Get or set a number between -360 and 360 for the north direction in degrees.
182
+
183
+ This is the counterclockwise difference between the North and the positive
184
+ Y-axis. 90 is West and 270 is East (Default: 0). Note that this is different
185
+ than the convention used in EnergyPlus, which uses clockwise difference
186
+ instead of counterclockwise difference.
187
+ """
188
+ return self._north_angle
189
+
190
+ @north_angle.setter
191
+ def north_angle(self, value):
192
+ self._north_angle = float_in_range(value, -360.0, 360.0, 'north angle')
193
+ self._north_vector = Vector2D(0, 1).rotate(math.radians(self._north_angle))
194
+
195
+ @property
196
+ def north_vector(self):
197
+ """Get or set a ladybug_geometry Vector2D for the north direction."""
198
+ return self._north_vector
199
+
200
+ @north_vector.setter
201
+ def north_vector(self, value):
202
+ assert isinstance(value, Vector2D), \
203
+ 'Expected Vector2D for north_vector. Got {}.'.format(type(value))
204
+ self._north_vector = value
205
+ self._north_angle = \
206
+ math.degrees(self._north_vector.angle_clockwise(Vector2D(0, 1)))
207
+
208
+ @property
209
+ def terrain_type(self):
210
+ """Get or set a text string for the terrain in which the model sits.
211
+
212
+ This is used to determine the wind profile over the height of the
213
+ building. Default is 'City'. Choose from the following options:
214
+
215
+ * Ocean
216
+ * Country
217
+ * Suburbs
218
+ * Urban
219
+ * City
220
+ """
221
+ return self._terrain_type
222
+
223
+ @terrain_type.setter
224
+ def terrain_type(self, value):
225
+ if value is not None:
226
+ assert value in self.TERRAIN_TYPES, 'Input terrain_type "{}" is ' \
227
+ 'not valid. Choose from the following options:\n{}'.format(
228
+ value, self.TERRAIN_TYPES)
229
+ self._terrain_type = value
230
+ else:
231
+ self._terrain_type = 'City'
232
+
233
+ def building_idf(self, identifier='Building'):
234
+ """Get an IDF string for an IDF Building object.
235
+
236
+ Args:
237
+ identifier: Text string for to be used as a unique identifier for the
238
+ building object.
239
+ """
240
+ values = (identifier, self.north_angle, self.terrain_type, '', '',
241
+ self.shadow_calculation.solar_distribution)
242
+ comments = ('name',
243
+ 'clockwise north axis',
244
+ 'terrain',
245
+ 'loads convergence tolerance',
246
+ 'temperature convergence tolerance',
247
+ 'solar distribution')
248
+ return generate_idf_string('Building', values, comments)
249
+
250
+ def water_mains_idf(self):
251
+ """Get an IDF string for the water mains object."""
252
+ return generate_idf_string(
253
+ 'Site:WaterMainsTemperature', ('CorrelationFromWeatherFile',),
254
+ ('calculation method',))
255
+
256
+ @classmethod
257
+ def from_idf(cls, idf_string):
258
+ """Create a SimulationParameter object from an EnergyPlus IDF text string.
259
+
260
+ Args:
261
+ idf_string: A text string with all IDF objects that should be included
262
+ in the resulting SimulationParameter object. Note that, unlike other
263
+ from_idf methods throughout honeybee_energy, this method can have
264
+ multiple IDF objects within the idf_string. Any object in the idf_string
265
+ that is not relevant to SimulationParameter will be ignored by this
266
+ method. So the input idf_string can simply be the entire file contents
267
+ of an IDF.
268
+ """
269
+ # Regex patterns for the various objects comprising the SimulationParameter
270
+ out_style_pattern = re.compile(r"(?i)(OutputControl:Table:Style,[\s\S]*?;)")
271
+ unmet_pattern = re.compile(r"(?i)(OutputControl:ReportingTolerances,[\s\S]*?;)")
272
+ out_var_pattern = re.compile(r"(?i)(Output:Variable,[\s\S]*?;)")
273
+ out_report_pattern = re.compile(r"(?i)(Output:Table:SummaryReports,[\s\S]*?;)")
274
+ sqlite_pattern = re.compile(r"(?i)(Output:SQLite,[\s\S]*?;)")
275
+ runper_pattern = re.compile(r"(?i)(RunPeriod,[\s\S]*?;)")
276
+ holiday_pattern = re.compile(r"(?i)(RunPeriodControl:SpecialDays,[\s\S]*?;)")
277
+ dls_pattern = re.compile(r"(?i)(RunPeriodControl:DaylightSavingTime,[\s\S]*?;)")
278
+ timestep_pattern = re.compile(r"(?i)(Timestep,[\s\S]*?;)")
279
+ sh_calc_pattern = re.compile(r"(?i)(ShadowCalculation,[\s\S]*?;)")
280
+ bldg_pattern = re.compile(r"(?i)(Building,[\s\S]*?;)")
281
+ control_pattern = re.compile(r"(?i)(SimulationControl,[\s\S]*?;)")
282
+ sizing_pattern = re.compile(r"(?i)(Sizing:Parameters,[\s\S]*?;)")
283
+ ddy_p = re.compile(r"(SizingPeriod:DesignDay,(.|\n)*?((;\s*!)|(;\s*\n)|(;\n)))")
284
+ loc_pattern = re.compile(r"(?i)(Site:Location,[\s\S]*?;)")
285
+
286
+ # process the outputs within the idf_string
287
+ try:
288
+ out_style_str = out_style_pattern.findall(idf_string)[0]
289
+ except IndexError: # No Table:Style in the file.
290
+ out_style_str = None
291
+ try:
292
+ out_unmet_str = unmet_pattern.findall(idf_string)[0]
293
+ except IndexError: # No ReportingTolerances in the file.
294
+ out_unmet_str = None
295
+ try:
296
+ out_report_str = out_report_pattern.findall(idf_string)[0]
297
+ except IndexError: # No SummaryReports in the file. Default to None.
298
+ out_report_str = None
299
+ sqlite = True if len(sqlite_pattern.findall(idf_string)) != 0 else False
300
+ output = SimulationOutput.from_idf(
301
+ out_style_str, out_var_pattern.findall(idf_string), out_report_str,
302
+ out_unmet_str, sqlite)
303
+
304
+ # process the RunPeriod within the idf_string
305
+ try:
306
+ run_period_str = runper_pattern.findall(idf_string)[0]
307
+ except IndexError: # No RunPeriod in the file. Default to the whole year.
308
+ run_period_str = None
309
+ run_period = None
310
+ if run_period_str is not None:
311
+ holidays_str = holiday_pattern.findall(idf_string)
312
+ if len(holidays_str) == 0:
313
+ holidays_str = None
314
+ try:
315
+ dls_str = dls_pattern.findall(idf_string)[0]
316
+ except IndexError: # No DaylightSavingTime in the file.
317
+ dls_str = None
318
+ run_period = RunPeriod.from_idf(run_period_str, holidays_str, dls_str)
319
+
320
+ # process the Timestep within the idf_string
321
+ try:
322
+ timestep_str = timestep_pattern.findall(idf_string)[0]
323
+ timestep = int(parse_idf_string(timestep_str)[0])
324
+ except IndexError: # No Timestep in the file. Default to 6.
325
+ timestep = 6
326
+
327
+ # process the SimulationControl within the idf_string
328
+ try:
329
+ sim_control_str = control_pattern.findall(idf_string)[0]
330
+ sim_control = SimulationControl.from_idf(sim_control_str)
331
+ except IndexError: # No SimulationControl in the file.
332
+ sim_control = None
333
+
334
+ # process the Building within the idf_string
335
+ try:
336
+ bldg_str = bldg_pattern.findall(idf_string)[0]
337
+ bldg_prop = parse_idf_string(bldg_str)
338
+ north_angle = float(bldg_prop[1]) if bldg_prop[1] != '' else 0
339
+ terrain = bldg_prop[2].title() if bldg_prop[2] != '' else 'Suburbs'
340
+ solar_dist = bldg_prop[5] if bldg_prop[5] != '' else 'FullExterior'
341
+ except IndexError: # No Building in the file. Use honeybee default.
342
+ north_angle = 0
343
+ terrain = 'City'
344
+ solar_dist = 'FullExteriorWithReflections'
345
+
346
+ # process the ShadowCalculation within the idf_string
347
+ try:
348
+ sh_calc_str = sh_calc_pattern.findall(idf_string)[0]
349
+ except IndexError: # No ShadowCalculation in the file.
350
+ sh_calc_str = None
351
+ shadow_calc = None
352
+ if sh_calc_str is not None:
353
+ shadow_calc = ShadowCalculation.from_idf(sh_calc_str, solar_dist)
354
+
355
+ # process the SizingParameter within the idf_string
356
+ try:
357
+ sizing_str = sizing_pattern.findall(idf_string)[0]
358
+ except IndexError: # No Sizing:Parameters in the file.
359
+ sizing_str = None
360
+ try:
361
+ location = loc_pattern.findall(idf_string)[0]
362
+ except IndexError: # No Site:Location in the file.
363
+ location = None
364
+ sizing_par = SizingParameter.from_idf(
365
+ [dy[0] for dy in ddy_p.findall(idf_string)], sizing_str, location)
366
+
367
+ return cls(output, run_period, timestep, sim_control, shadow_calc,
368
+ sizing_par, north_angle, terrain)
369
+
370
+ @classmethod
371
+ def from_dict(cls, data):
372
+ """Create a SimulationParameter object from a dictionary.
373
+
374
+ Args:
375
+ data: A SimulationParameter dictionary in following the format below.
376
+
377
+ .. code-block:: python
378
+
379
+ {
380
+ "type": "SimulationParameter",
381
+ "output": {}, # Honeybee SimulationOutput dictionary
382
+ "run_period": {}, # Honeybee RunPeriod dictionary
383
+ "timestep": 6, # Integer for the simulation timestep
384
+ "simulation_control": {}, # Honeybee SimulationControl dictionary
385
+ "shadow_calculation": {}, # Honeybee ShadowCalculation dictionary
386
+ "sizing_parameter": {} # Honeybee SizingParameter dictionary
387
+ }
388
+ """
389
+ assert data['type'] == 'SimulationParameter', \
390
+ 'Expected SimulationParameter dictionary. Got {}.'.format(data['type'])
391
+
392
+ timestep = data['timestep'] if 'timestep' in data else 6
393
+ output = None
394
+ if 'output' in data and data['output'] is not None:
395
+ output = SimulationOutput.from_dict(data['output'])
396
+ run_period = None
397
+ if 'run_period' in data and data['run_period'] is not None:
398
+ run_period = RunPeriod.from_dict(data['run_period'])
399
+ simulation_control = None
400
+ if 'simulation_control' in data and data['simulation_control'] is not None:
401
+ simulation_control = SimulationControl.from_dict(data['simulation_control'])
402
+ shadow_calculation = None
403
+ if 'shadow_calculation' in data and data['shadow_calculation'] is not None:
404
+ shadow_calculation = ShadowCalculation.from_dict(data['shadow_calculation'])
405
+ sizing_parameter = None
406
+ if 'sizing_parameter' in data and data['sizing_parameter'] is not None:
407
+ sizing_parameter = SizingParameter.from_dict(data['sizing_parameter'])
408
+ north_angle = 0
409
+ if 'north_angle' in data and data['north_angle'] is not None:
410
+ north_angle = data['north_angle']
411
+ terrain_type = 'City'
412
+ if 'terrain_type' in data and data['terrain_type'] is not None:
413
+ terrain_type = data['terrain_type']
414
+
415
+ return cls(output, run_period, timestep, simulation_control,
416
+ shadow_calculation, sizing_parameter, north_angle, terrain_type)
417
+
418
+ def to_idf(self, identifier='Building'):
419
+ """Get an EnergyPlus string representation of the SimulationParameter.
420
+
421
+ Note that this string is a concatenation of the IDF strings that make up
422
+ the SimulationParameter (ie. RunPeriod, SimulationControl, etc.).
423
+
424
+ Args:
425
+ identifier: Text string for to be used as a unique identifier for the
426
+ IDF Building object.
427
+
428
+ .. code-block:: shell
429
+
430
+ !- ==========================================
431
+ !- ========= SIMULATION PARAMETERS =========
432
+ !- ==========================================
433
+
434
+
435
+ OutputControl:Table:Style,
436
+ CommaAndHTML, !- column separator
437
+ None; !- unit conversion
438
+
439
+ Output:Variable,
440
+ *, !- key value
441
+ Zone Ideal Loads Supply Air Total Cooling Energy, !- name
442
+ Hourly; !- frequency
443
+
444
+ Output:Variable,
445
+ *, !- key value
446
+ Zone Ideal Loads Supply Air Total Heating Energy, !- name
447
+ Hourly; !- frequency
448
+
449
+ Output:Table:SummaryReports,
450
+ AllSummary; !- report 0
451
+
452
+ Output:SQLite,
453
+ SimpleAndTabular; !- option type
454
+
455
+ Output:VariableDictionary,
456
+ IDF, !- key field
457
+ Unsorted; !- sort option
458
+
459
+ OutputControl:ReportingTolerances,
460
+ 1.11, !- heating unmet setpoint tolerance
461
+ 1.11; !- cooling unmet setpoint tolerance
462
+
463
+ SimulationControl,
464
+ Yes, !- do zone sizing
465
+ Yes, !- do system sizing
466
+ Yes, !- do plant sizing
467
+ No, !- run for sizing periods
468
+ Yes; !- run for run periods
469
+
470
+ ShadowCalculation,
471
+ PolygonClipping, !- calculation method
472
+ Periodic, !- calculation update method
473
+ 30, !- calculation frequency
474
+ 15000; !- maximum figures
475
+
476
+ Timestep,
477
+ 6; !- timesteps per hour
478
+
479
+ RunPeriod,
480
+ CustomRunPeriod, !- name
481
+ 1, !- start month
482
+ 1, !- start day
483
+ 2017, !- start year
484
+ 12, !- end month
485
+ 31, !- end day
486
+ 2017, !- end year
487
+ Sunday, !- start day of week
488
+ No, !- use weather file holidays
489
+ No, !- use weather file daylight savings
490
+ No, !- apply weekend holiday
491
+ Yes, !- use epw rain
492
+ Yes; !- use epw snow
493
+
494
+ Sizing:Parameters,
495
+ 1.25, !- heating factor
496
+ 1.15; !- cooling factor
497
+
498
+ GlobalGeometryRules,
499
+ UpperLeftCorner, !- starting vertex position
500
+ Counterclockwise, !- vertex entry direction
501
+ Relative; !- coordinate system
502
+
503
+ Building,
504
+ Building, !- name
505
+ 0.0, !- clockwise north axis
506
+ City, !- terrain
507
+ , !- loads convergence tolerance
508
+ , !- temperature convergence tolerance
509
+ FullExteriorWithReflections; !- solar distribution
510
+
511
+ Site:WaterMainsTemperature,
512
+ CorrelationFromWeatherFile; !- calculation method
513
+
514
+
515
+ """
516
+ sim_param_str = ['!- ==========================================\n'
517
+ '!- ========= SIMULATION PARAMETERS =========\n'
518
+ '!- ==========================================\n']
519
+
520
+ # add the outputs requested
521
+ table_style, output_vars, reports, sqlite, rdd, unmet_tol = self.output.to_idf()
522
+ sim_param_str.append(table_style)
523
+ if output_vars is not None:
524
+ sim_param_str.append('\n\n'.join(output_vars))
525
+ if reports is not None:
526
+ sim_param_str.append(reports)
527
+ if sqlite is not None:
528
+ sim_param_str.append(sqlite)
529
+ sim_param_str.append(rdd)
530
+ sim_param_str.append(unmet_tol)
531
+
532
+ # add simulation settings
533
+ sim_param_str.append(self.simulation_control.to_idf())
534
+ sim_param_str.append(self.shadow_calculation.to_idf())
535
+ sim_param_str.append(generate_idf_string(
536
+ 'Timestep', [self.timestep], ['timesteps per hour']))
537
+
538
+ # add the run period
539
+ run_period_str, holidays, daylight_saving = self.run_period.to_idf()
540
+ sim_param_str.append(run_period_str)
541
+ if holidays is not None:
542
+ sim_param_str.append('\n\n'.join(holidays))
543
+ if daylight_saving is not None:
544
+ sim_param_str.append(daylight_saving)
545
+
546
+ # write the sizing parameters
547
+ design_days, siz_par = self.sizing_parameter.to_idf()
548
+ if len(design_days) != 0:
549
+ sim_param_str.append('\n\n'.join(design_days))
550
+ sim_param_str.append(siz_par)
551
+
552
+ # write the global geometry rules
553
+ sim_param_str.append(self.global_geometry_rules)
554
+
555
+ # write the Building and water mains object
556
+ sim_param_str.append(self.building_idf(identifier))
557
+ sim_param_str.append(self.water_mains_idf())
558
+
559
+ return '\n\n'.join(sim_param_str)
560
+
561
+ def to_dict(self):
562
+ """SimulationParameter dictionary representation."""
563
+ return {
564
+ 'type': 'SimulationParameter',
565
+ 'output': self.output.to_dict(),
566
+ 'run_period': self.run_period.to_dict(),
567
+ 'timestep': self.timestep,
568
+ 'simulation_control': self.simulation_control.to_dict(),
569
+ 'shadow_calculation': self.shadow_calculation.to_dict(),
570
+ 'sizing_parameter': self.sizing_parameter.to_dict(),
571
+ 'north_angle': self.north_angle,
572
+ 'terrain_type': self.terrain_type
573
+ }
574
+
575
+ def duplicate(self):
576
+ """Get a copy of this object."""
577
+ return self.__copy__()
578
+
579
+ def ToString(self):
580
+ """Overwrite .NET ToString."""
581
+ return self.__repr__()
582
+
583
+ def __copy__(self):
584
+ return SimulationParameter(
585
+ self.output.duplicate(), self.run_period.duplicate(), self.timestep,
586
+ self.simulation_control.duplicate(), self.shadow_calculation.duplicate(),
587
+ self.sizing_parameter.duplicate(), self.north_angle, self.terrain_type)
588
+
589
+ def __key(self):
590
+ """A tuple based on the object properties, useful for hashing."""
591
+ return (hash(self.output), hash(self.run_period), self.timestep,
592
+ hash(self.simulation_control),
593
+ hash(self.shadow_calculation), hash(self.sizing_parameter),
594
+ self.north_angle, self.terrain_type)
595
+
596
+ def __hash__(self):
597
+ return hash(self.__key())
598
+
599
+ def __eq__(self, other):
600
+ return isinstance(other, SimulationParameter) and self.__key() == other.__key()
601
+
602
+ def __ne__(self, other):
603
+ return not self.__eq__(other)
604
+
605
+ def __repr__(self):
606
+ return 'Energy SimulationParameter:'