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.
- honeybee_energy/__init__.py +24 -0
- honeybee_energy/__main__.py +4 -0
- honeybee_energy/_extend_honeybee.py +145 -0
- honeybee_energy/altnumber.py +21 -0
- honeybee_energy/baseline/__init__.py +2 -0
- honeybee_energy/baseline/create.py +608 -0
- honeybee_energy/baseline/data/__init__.py +1 -0
- honeybee_energy/baseline/data/constructions.csv +64 -0
- honeybee_energy/baseline/data/fen_ratios.csv +15 -0
- honeybee_energy/baseline/data/lpd_building.csv +21 -0
- honeybee_energy/baseline/data/pci_2016.csv +22 -0
- honeybee_energy/baseline/data/pci_2019.csv +22 -0
- honeybee_energy/baseline/data/pci_2022.csv +22 -0
- honeybee_energy/baseline/data/shw.csv +21 -0
- honeybee_energy/baseline/pci.py +512 -0
- honeybee_energy/baseline/result.py +371 -0
- honeybee_energy/boundarycondition.py +128 -0
- honeybee_energy/cli/__init__.py +69 -0
- honeybee_energy/cli/baseline.py +475 -0
- honeybee_energy/cli/edit.py +327 -0
- honeybee_energy/cli/lib.py +1154 -0
- honeybee_energy/cli/result.py +810 -0
- honeybee_energy/cli/setconfig.py +124 -0
- honeybee_energy/cli/settings.py +569 -0
- honeybee_energy/cli/simulate.py +380 -0
- honeybee_energy/cli/translate.py +1714 -0
- honeybee_energy/cli/validate.py +224 -0
- honeybee_energy/config.json +11 -0
- honeybee_energy/config.py +842 -0
- honeybee_energy/construction/__init__.py +1 -0
- honeybee_energy/construction/_base.py +374 -0
- honeybee_energy/construction/air.py +325 -0
- honeybee_energy/construction/dictutil.py +89 -0
- honeybee_energy/construction/dynamic.py +607 -0
- honeybee_energy/construction/opaque.py +460 -0
- honeybee_energy/construction/shade.py +319 -0
- honeybee_energy/construction/window.py +1096 -0
- honeybee_energy/construction/windowshade.py +847 -0
- honeybee_energy/constructionset.py +1655 -0
- honeybee_energy/dictutil.py +56 -0
- honeybee_energy/generator/__init__.py +5 -0
- honeybee_energy/generator/loadcenter.py +204 -0
- honeybee_energy/generator/pv.py +535 -0
- honeybee_energy/hvac/__init__.py +21 -0
- honeybee_energy/hvac/_base.py +124 -0
- honeybee_energy/hvac/_template.py +270 -0
- honeybee_energy/hvac/allair/__init__.py +22 -0
- honeybee_energy/hvac/allair/_base.py +349 -0
- honeybee_energy/hvac/allair/furnace.py +168 -0
- honeybee_energy/hvac/allair/psz.py +131 -0
- honeybee_energy/hvac/allair/ptac.py +163 -0
- honeybee_energy/hvac/allair/pvav.py +109 -0
- honeybee_energy/hvac/allair/vav.py +128 -0
- honeybee_energy/hvac/detailed.py +337 -0
- honeybee_energy/hvac/doas/__init__.py +28 -0
- honeybee_energy/hvac/doas/_base.py +345 -0
- honeybee_energy/hvac/doas/fcu.py +127 -0
- honeybee_energy/hvac/doas/radiant.py +329 -0
- honeybee_energy/hvac/doas/vrf.py +81 -0
- honeybee_energy/hvac/doas/wshp.py +91 -0
- honeybee_energy/hvac/heatcool/__init__.py +23 -0
- honeybee_energy/hvac/heatcool/_base.py +177 -0
- honeybee_energy/hvac/heatcool/baseboard.py +61 -0
- honeybee_energy/hvac/heatcool/evapcool.py +72 -0
- honeybee_energy/hvac/heatcool/fcu.py +92 -0
- honeybee_energy/hvac/heatcool/gasunit.py +53 -0
- honeybee_energy/hvac/heatcool/radiant.py +269 -0
- honeybee_energy/hvac/heatcool/residential.py +77 -0
- honeybee_energy/hvac/heatcool/vrf.py +54 -0
- honeybee_energy/hvac/heatcool/windowac.py +70 -0
- honeybee_energy/hvac/heatcool/wshp.py +62 -0
- honeybee_energy/hvac/idealair.py +699 -0
- honeybee_energy/internalmass.py +310 -0
- honeybee_energy/lib/__init__.py +1 -0
- honeybee_energy/lib/_loadconstructions.py +194 -0
- honeybee_energy/lib/_loadconstructionsets.py +117 -0
- honeybee_energy/lib/_loadmaterials.py +83 -0
- honeybee_energy/lib/_loadprogramtypes.py +125 -0
- honeybee_energy/lib/_loadschedules.py +87 -0
- honeybee_energy/lib/_loadtypelimits.py +64 -0
- honeybee_energy/lib/constructions.py +207 -0
- honeybee_energy/lib/constructionsets.py +95 -0
- honeybee_energy/lib/materials.py +67 -0
- honeybee_energy/lib/programtypes.py +125 -0
- honeybee_energy/lib/schedules.py +61 -0
- honeybee_energy/lib/scheduletypelimits.py +31 -0
- honeybee_energy/load/__init__.py +1 -0
- honeybee_energy/load/_base.py +190 -0
- honeybee_energy/load/daylight.py +397 -0
- honeybee_energy/load/dictutil.py +47 -0
- honeybee_energy/load/equipment.py +771 -0
- honeybee_energy/load/hotwater.py +543 -0
- honeybee_energy/load/infiltration.py +460 -0
- honeybee_energy/load/lighting.py +480 -0
- honeybee_energy/load/people.py +497 -0
- honeybee_energy/load/process.py +472 -0
- honeybee_energy/load/setpoint.py +816 -0
- honeybee_energy/load/ventilation.py +550 -0
- honeybee_energy/material/__init__.py +1 -0
- honeybee_energy/material/_base.py +166 -0
- honeybee_energy/material/dictutil.py +59 -0
- honeybee_energy/material/frame.py +367 -0
- honeybee_energy/material/gas.py +1087 -0
- honeybee_energy/material/glazing.py +854 -0
- honeybee_energy/material/opaque.py +1351 -0
- honeybee_energy/material/shade.py +1360 -0
- honeybee_energy/measure.py +472 -0
- honeybee_energy/programtype.py +723 -0
- honeybee_energy/properties/__init__.py +1 -0
- honeybee_energy/properties/aperture.py +333 -0
- honeybee_energy/properties/door.py +342 -0
- honeybee_energy/properties/extension.py +244 -0
- honeybee_energy/properties/face.py +274 -0
- honeybee_energy/properties/model.py +2640 -0
- honeybee_energy/properties/room.py +1747 -0
- honeybee_energy/properties/shade.py +314 -0
- honeybee_energy/properties/shademesh.py +262 -0
- honeybee_energy/reader.py +48 -0
- honeybee_energy/result/__init__.py +1 -0
- honeybee_energy/result/colorobj.py +648 -0
- honeybee_energy/result/emissions.py +290 -0
- honeybee_energy/result/err.py +101 -0
- honeybee_energy/result/eui.py +100 -0
- honeybee_energy/result/generation.py +160 -0
- honeybee_energy/result/loadbalance.py +890 -0
- honeybee_energy/result/match.py +202 -0
- honeybee_energy/result/osw.py +90 -0
- honeybee_energy/result/rdd.py +59 -0
- honeybee_energy/result/zsz.py +190 -0
- honeybee_energy/run.py +1577 -0
- honeybee_energy/schedule/__init__.py +1 -0
- honeybee_energy/schedule/day.py +626 -0
- honeybee_energy/schedule/dictutil.py +59 -0
- honeybee_energy/schedule/fixedinterval.py +1012 -0
- honeybee_energy/schedule/rule.py +619 -0
- honeybee_energy/schedule/ruleset.py +1867 -0
- honeybee_energy/schedule/typelimit.py +310 -0
- honeybee_energy/shw.py +315 -0
- honeybee_energy/simulation/__init__.py +1 -0
- honeybee_energy/simulation/control.py +214 -0
- honeybee_energy/simulation/daylightsaving.py +185 -0
- honeybee_energy/simulation/dictutil.py +51 -0
- honeybee_energy/simulation/output.py +646 -0
- honeybee_energy/simulation/parameter.py +606 -0
- honeybee_energy/simulation/runperiod.py +443 -0
- honeybee_energy/simulation/shadowcalculation.py +295 -0
- honeybee_energy/simulation/sizing.py +546 -0
- honeybee_energy/ventcool/__init__.py +5 -0
- honeybee_energy/ventcool/_crack_data.py +91 -0
- honeybee_energy/ventcool/afn.py +289 -0
- honeybee_energy/ventcool/control.py +269 -0
- honeybee_energy/ventcool/crack.py +126 -0
- honeybee_energy/ventcool/fan.py +493 -0
- honeybee_energy/ventcool/opening.py +365 -0
- honeybee_energy/ventcool/simulation.py +314 -0
- honeybee_energy/writer.py +1078 -0
- honeybee_energy-1.116.106.dist-info/METADATA +113 -0
- honeybee_energy-1.116.106.dist-info/RECORD +162 -0
- honeybee_energy-1.116.106.dist-info/WHEEL +5 -0
- honeybee_energy-1.116.106.dist-info/entry_points.txt +2 -0
- honeybee_energy-1.116.106.dist-info/licenses/LICENSE +661 -0
- 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:'
|