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,310 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Schedule type definition."""
|
|
3
|
+
from __future__ import division
|
|
4
|
+
|
|
5
|
+
from ..reader import parse_idf_string, clean_idf_file_contents
|
|
6
|
+
from ..writer import generate_idf_string
|
|
7
|
+
|
|
8
|
+
from honeybee.typing import valid_ep_string, valid_string, float_in_range
|
|
9
|
+
from honeybee.altnumber import no_limit
|
|
10
|
+
from ladybug.datatype import fraction, temperature, temperaturedelta, power, \
|
|
11
|
+
angle, speed, distance, uvalue
|
|
12
|
+
|
|
13
|
+
import re
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ScheduleTypeLimit(object):
|
|
17
|
+
"""Energy schedule type definition.
|
|
18
|
+
|
|
19
|
+
Schedule types exist for the sole purpose of validating schedule values against
|
|
20
|
+
upper/lower limits and assigning a data type and units to the schedule values.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
identifier: Text string for a unique Schedule Type ID. Must be < 100 characters
|
|
24
|
+
and not contain any EnergyPlus special characters. This will be used to
|
|
25
|
+
identify the object across a model and in the exported IDF.
|
|
26
|
+
lower_limit: An optional number for the lower limit for values in the
|
|
27
|
+
schedule. If None or a NoLimit object, there will be no lower limit.
|
|
28
|
+
upper_limit: An optional number for the upper limit for values in the
|
|
29
|
+
schedule. If None or a NoLimit object, there will be no upper limit.
|
|
30
|
+
numeric_type: Either one of two strings: 'Continuous' or 'Discrete'. The
|
|
31
|
+
latter means that only integers are accepted as schedule values. (Default:
|
|
32
|
+
Continuous).
|
|
33
|
+
unit_type: Text for an EnergyPlus unit type, which will be used
|
|
34
|
+
to assign units to the values in the schedule. Note that this field
|
|
35
|
+
is not used in the actual calculations of EnergyPlus. (Default:
|
|
36
|
+
Dimensionless). Choose from the following options:
|
|
37
|
+
|
|
38
|
+
* Dimensionless
|
|
39
|
+
* Temperature
|
|
40
|
+
* DeltaTemperature
|
|
41
|
+
* PrecipitationRate
|
|
42
|
+
* Angle
|
|
43
|
+
* ConvectionCoefficient
|
|
44
|
+
* ActivityLevel
|
|
45
|
+
* Velocity
|
|
46
|
+
* Capacity
|
|
47
|
+
* Power
|
|
48
|
+
* Availability
|
|
49
|
+
* Percent
|
|
50
|
+
* Control
|
|
51
|
+
* Mode
|
|
52
|
+
|
|
53
|
+
Properties:
|
|
54
|
+
* identifier
|
|
55
|
+
* display_name
|
|
56
|
+
* lower_limit
|
|
57
|
+
* upper_limit
|
|
58
|
+
* numeric_type
|
|
59
|
+
* unit_type
|
|
60
|
+
* data_type
|
|
61
|
+
* unit
|
|
62
|
+
"""
|
|
63
|
+
_default_lb_unit_type = {
|
|
64
|
+
'Dimensionless': (fraction.Fraction(), 'fraction'),
|
|
65
|
+
'Temperature': (temperature.Temperature(), 'C'),
|
|
66
|
+
'DeltaTemperature': (temperaturedelta.TemperatureDelta(), 'dC'),
|
|
67
|
+
'PrecipitationRate': [distance.Distance(), 'm'],
|
|
68
|
+
'Angle': [angle.Angle(), 'degrees'],
|
|
69
|
+
'ConvectionCoefficient': [uvalue.ConvectionCoefficient(), 'W/m2-K'],
|
|
70
|
+
'ActivityLevel': [power.ActivityLevel(), 'W'],
|
|
71
|
+
'Velocity': [speed.Speed(), 'm/s'],
|
|
72
|
+
'Capacity': [power.Power(), 'W'],
|
|
73
|
+
'Power': [power.Power(), 'W'],
|
|
74
|
+
'Availability': [fraction.Fraction(), 'fraction'],
|
|
75
|
+
'Percent': [fraction.Fraction(), '%'],
|
|
76
|
+
'Control': [fraction.Fraction(), 'fraction'],
|
|
77
|
+
'Mode': [fraction.Fraction(), 'fraction']}
|
|
78
|
+
|
|
79
|
+
UNIT_TYPES = tuple(_default_lb_unit_type.keys())
|
|
80
|
+
NUMERIC_TYPES = ('Continuous', 'Discrete')
|
|
81
|
+
|
|
82
|
+
def __init__(self, identifier, lower_limit=no_limit, upper_limit=no_limit,
|
|
83
|
+
numeric_type='Continuous', unit_type='Dimensionless'):
|
|
84
|
+
"""Initialize ScheduleTypeLimit."""
|
|
85
|
+
# process the identifier and limits
|
|
86
|
+
self._identifier = valid_ep_string(identifier, 'schedule type identifier')
|
|
87
|
+
self._display_name = None
|
|
88
|
+
self._lower_limit = float_in_range(lower_limit) if lower_limit is not \
|
|
89
|
+
None and lower_limit != no_limit else no_limit
|
|
90
|
+
self._upper_limit = float_in_range(upper_limit) if upper_limit is not \
|
|
91
|
+
None and upper_limit != no_limit else no_limit
|
|
92
|
+
if self._lower_limit != no_limit and self._upper_limit != no_limit:
|
|
93
|
+
assert self._lower_limit <= self._upper_limit, 'ScheduleTypeLimit ' \
|
|
94
|
+
'lower_limit must be less than upper_limit. {} > {}.'.format(
|
|
95
|
+
self._lower_limit, self._upper_limit)
|
|
96
|
+
|
|
97
|
+
# process the numeric type
|
|
98
|
+
self._numeric_type = numeric_type.capitalize() or 'Continuous'
|
|
99
|
+
assert self._numeric_type in self.NUMERIC_TYPES, '"{}" is not an acceptable ' \
|
|
100
|
+
'numeric type. Choose from the following:\n{}'.format(
|
|
101
|
+
numeric_type, self.NUMERIC_TYPES)
|
|
102
|
+
|
|
103
|
+
# process the unit type and assign the ladybug data type and unit
|
|
104
|
+
if unit_type is None:
|
|
105
|
+
self._data_type, self._unit = self._default_lb_unit_type['Dimensionless']
|
|
106
|
+
self._unit_type = 'Dimensionless'
|
|
107
|
+
else:
|
|
108
|
+
clean_input = valid_string(unit_type).lower()
|
|
109
|
+
for key in self.UNIT_TYPES:
|
|
110
|
+
if key.lower() == clean_input:
|
|
111
|
+
unit_type = key
|
|
112
|
+
break
|
|
113
|
+
else:
|
|
114
|
+
raise ValueError(
|
|
115
|
+
'unit_type {} is not recognized.\nChoose from the '
|
|
116
|
+
'following:\n{}'.format(unit_type, self.UNIT_TYPES))
|
|
117
|
+
self._data_type, self._unit = self._default_lb_unit_type[unit_type]
|
|
118
|
+
self._unit_type = unit_type
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def identifier(self):
|
|
122
|
+
"""Get the text string for unique schedule type identifier."""
|
|
123
|
+
return self._identifier
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def display_name(self):
|
|
127
|
+
"""Get or set a string for the object name without any character restrictions.
|
|
128
|
+
|
|
129
|
+
If not set, this will be equal to the identifier.
|
|
130
|
+
"""
|
|
131
|
+
if self._display_name is None:
|
|
132
|
+
return self._identifier
|
|
133
|
+
return self._display_name
|
|
134
|
+
|
|
135
|
+
@display_name.setter
|
|
136
|
+
def display_name(self, value):
|
|
137
|
+
if value is not None:
|
|
138
|
+
try:
|
|
139
|
+
value = str(value)
|
|
140
|
+
except UnicodeEncodeError: # Python 2 machine lacking the character set
|
|
141
|
+
pass # keep it as unicode
|
|
142
|
+
self._display_name = value
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def lower_limit(self):
|
|
146
|
+
"""Get the lower limit of the schedule type."""
|
|
147
|
+
return self._lower_limit
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def upper_limit(self):
|
|
151
|
+
"""Get the upper limit of the schedule type."""
|
|
152
|
+
return self._upper_limit
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def numeric_type(self):
|
|
156
|
+
"""Text noting whether schedule values are 'Continuous' or 'Discrete'."""
|
|
157
|
+
return self._numeric_type
|
|
158
|
+
|
|
159
|
+
@property
|
|
160
|
+
def unit_type(self):
|
|
161
|
+
"""Get the text string describing the energyplus unit type."""
|
|
162
|
+
return self._unit_type
|
|
163
|
+
|
|
164
|
+
@property
|
|
165
|
+
def data_type(self):
|
|
166
|
+
"""Get the Ladybug DataType object corresponding to the energyplus unit type.
|
|
167
|
+
|
|
168
|
+
This object can be used for creating Ladybug DataCollections, performing unit
|
|
169
|
+
conversions of schedule values, etc.
|
|
170
|
+
"""
|
|
171
|
+
return self._data_type
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def unit(self):
|
|
175
|
+
"""Get the string describing the units of the schedule values (ie. 'C', 'W')."""
|
|
176
|
+
return self._unit
|
|
177
|
+
|
|
178
|
+
@classmethod
|
|
179
|
+
def from_idf(cls, idf_string):
|
|
180
|
+
"""Create a ScheduleTypeLimit from an IDF string of ScheduleTypeLimits.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
idf_string: A text string describing EnergyPlus ScheduleTypeLimits.
|
|
184
|
+
"""
|
|
185
|
+
ep_strs = parse_idf_string(idf_string, 'ScheduleTypeLimits,')
|
|
186
|
+
ep_fields = [prop if prop != '' else None for prop in ep_strs]
|
|
187
|
+
return cls(*ep_fields)
|
|
188
|
+
|
|
189
|
+
@classmethod
|
|
190
|
+
def from_dict(cls, data):
|
|
191
|
+
"""Create a ScheduleTypeLimit from a dictionary.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
data: ScheduleTypeLimit dictionary following the format below.
|
|
195
|
+
|
|
196
|
+
.. code-block:: python
|
|
197
|
+
|
|
198
|
+
{
|
|
199
|
+
"type": 'ScheduleTypeLimit',
|
|
200
|
+
"identifier": 'Fractional',
|
|
201
|
+
"display_name": 'Fractional',
|
|
202
|
+
"lower_limit": 0,
|
|
203
|
+
"upper_limit": 1,
|
|
204
|
+
"numeric_type": Continuous,
|
|
205
|
+
"unit_type": "Dimensionless"
|
|
206
|
+
}
|
|
207
|
+
"""
|
|
208
|
+
assert data['type'] == 'ScheduleTypeLimit', \
|
|
209
|
+
'Expected ScheduleTypeLimit dictionary. Got {}.'.format(data['type'])
|
|
210
|
+
lower_limit = no_limit if 'lower_limit' not in data or \
|
|
211
|
+
data['lower_limit'] == no_limit.to_dict() else data['lower_limit']
|
|
212
|
+
upper_limit = no_limit if 'upper_limit' not in data or \
|
|
213
|
+
data['upper_limit'] == no_limit.to_dict() else data['upper_limit']
|
|
214
|
+
numeric_type = data['numeric_type'] if 'numeric_type' in data else 'Continuous'
|
|
215
|
+
unit_type = data['unit_type'] if 'unit_type' in data else 'Dimensionless'
|
|
216
|
+
new_obj = cls(data['identifier'], lower_limit, upper_limit,
|
|
217
|
+
numeric_type, unit_type)
|
|
218
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
219
|
+
new_obj.display_name = data['display_name']
|
|
220
|
+
return new_obj
|
|
221
|
+
|
|
222
|
+
def to_idf(self):
|
|
223
|
+
"""IDF string for the ScheduleTypeLimits of this object.
|
|
224
|
+
|
|
225
|
+
.. code-block:: shell
|
|
226
|
+
|
|
227
|
+
ScheduleTypeLimits,
|
|
228
|
+
my type limit, !- name
|
|
229
|
+
, !- lower limit value
|
|
230
|
+
, !- upper limit value
|
|
231
|
+
Continuous, !- numeric type
|
|
232
|
+
Percent; !- unit type
|
|
233
|
+
"""
|
|
234
|
+
values = [self.identifier, self.lower_limit, self.upper_limit,
|
|
235
|
+
self.numeric_type, self.unit_type]
|
|
236
|
+
if values[1] == no_limit:
|
|
237
|
+
values[1] = ''
|
|
238
|
+
if values[2] == no_limit:
|
|
239
|
+
values[2] = ''
|
|
240
|
+
comments = ('name', 'lower limit value', 'upper limit value',
|
|
241
|
+
'numeric type', 'unit type')
|
|
242
|
+
return generate_idf_string('ScheduleTypeLimits', values, comments)
|
|
243
|
+
|
|
244
|
+
def to_dict(self):
|
|
245
|
+
"""Shade construction dictionary representation."""
|
|
246
|
+
base = {'type': 'ScheduleTypeLimit'}
|
|
247
|
+
base['identifier'] = self.identifier
|
|
248
|
+
base['lower_limit'] = self.lower_limit if \
|
|
249
|
+
isinstance(self.lower_limit, float) else self.lower_limit.to_dict()
|
|
250
|
+
base['upper_limit'] = self.upper_limit if \
|
|
251
|
+
isinstance(self.upper_limit, float) else self.upper_limit.to_dict()
|
|
252
|
+
base['numeric_type'] = self.numeric_type
|
|
253
|
+
base['unit_type'] = self.unit_type
|
|
254
|
+
if self._display_name is not None:
|
|
255
|
+
base['display_name'] = self.display_name
|
|
256
|
+
return base
|
|
257
|
+
|
|
258
|
+
@staticmethod
|
|
259
|
+
def extract_all_from_idf_file(idf_file):
|
|
260
|
+
"""Extract all ScheduleTypeLimit objects from an EnergyPlus IDF file.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
idf_file: A path to an IDF file containing objects for ScheduleTypeLimits.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
schedule_type_limits -- A list of all ScheduleTypeLimits objects in the
|
|
267
|
+
IDF file as honeybee_energy ScheduleTypeLimit objects.
|
|
268
|
+
"""
|
|
269
|
+
# read the file and remove lines of comments
|
|
270
|
+
file_contents = clean_idf_file_contents(idf_file)
|
|
271
|
+
# extract all of the ScheduleTypeLimit objects
|
|
272
|
+
type_pattern = re.compile(r"(?i)(ScheduleTypeLimits,[\s\S]*?;)")
|
|
273
|
+
type_idf_strings = type_pattern.findall(file_contents)
|
|
274
|
+
schedule_type_limits = []
|
|
275
|
+
for type_str in type_idf_strings:
|
|
276
|
+
type_str = type_str.strip()
|
|
277
|
+
schedule_type_limits.append(ScheduleTypeLimit.from_idf(type_str))
|
|
278
|
+
return schedule_type_limits
|
|
279
|
+
|
|
280
|
+
def duplicate(self):
|
|
281
|
+
"""Get a copy of this object."""
|
|
282
|
+
return self.__copy__()
|
|
283
|
+
|
|
284
|
+
def __copy__(self):
|
|
285
|
+
new_obj = ScheduleTypeLimit(
|
|
286
|
+
self.identifier, self._lower_limit, self._upper_limit, self._numeric_type,
|
|
287
|
+
self._unit_type)
|
|
288
|
+
new_obj._display_name = self._display_name
|
|
289
|
+
return new_obj
|
|
290
|
+
|
|
291
|
+
def __key(self):
|
|
292
|
+
"""A tuple based on the object properties, useful for hashing."""
|
|
293
|
+
return (self.identifier, str(self._lower_limit), str(self._upper_limit),
|
|
294
|
+
self._numeric_type, self._unit_type)
|
|
295
|
+
|
|
296
|
+
def __hash__(self):
|
|
297
|
+
return hash(self.__key())
|
|
298
|
+
|
|
299
|
+
def __eq__(self, other):
|
|
300
|
+
return isinstance(other, ScheduleTypeLimit) and self.__key() == other.__key()
|
|
301
|
+
|
|
302
|
+
def __ne__(self, other):
|
|
303
|
+
return not self.__eq__(other)
|
|
304
|
+
|
|
305
|
+
def ToString(self):
|
|
306
|
+
"""Overwrite .NET ToString."""
|
|
307
|
+
return self.__repr__()
|
|
308
|
+
|
|
309
|
+
def __repr__(self):
|
|
310
|
+
return self.to_idf()
|
honeybee_energy/shw.py
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Detailed Service Hot Water (SHW) system template used to meet hot water demand."""
|
|
3
|
+
from __future__ import division
|
|
4
|
+
|
|
5
|
+
from honeybee._lockable import lockable
|
|
6
|
+
from honeybee.typing import valid_ep_string, valid_string, float_positive
|
|
7
|
+
from honeybee.altnumber import autocalculate
|
|
8
|
+
from .properties.extension import SHWSystemProperties
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@lockable
|
|
12
|
+
class SHWSystem(object):
|
|
13
|
+
"""Detailed Service Hot Water (SHW) system template used to meet hot water demand.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
identifier: Text string for the system identifier. Must be < 100 characters
|
|
17
|
+
and not contain any EnergyPlus special characters. This will be used to
|
|
18
|
+
identify the object across a model and in the exported IDF.
|
|
19
|
+
equipment_type: Text for the specific type of the system and equipment. (Default:
|
|
20
|
+
Gas_WaterHeater) Choose from.
|
|
21
|
+
|
|
22
|
+
* Gas_WaterHeater
|
|
23
|
+
* Electric_WaterHeater
|
|
24
|
+
* HeatPump_WaterHeater
|
|
25
|
+
* Gas_TanklessHeater
|
|
26
|
+
* Electric_TanklessHeater
|
|
27
|
+
|
|
28
|
+
heater_efficiency: A number for the efficiency of the heater within
|
|
29
|
+
the system. For Gas systems, this is the efficiency of the burner.
|
|
30
|
+
For HeatPump systems, this is the rated COP of the system. For electric
|
|
31
|
+
systems, this should usually be set to 1. If set to None or Autocalculate,
|
|
32
|
+
this value will automatically be set based on the equipment_type. See below
|
|
33
|
+
for the default value for each equipment type. (Default: None).
|
|
34
|
+
|
|
35
|
+
* Gas_WaterHeater - 0.8
|
|
36
|
+
* Electric_WaterHeater - 1.0
|
|
37
|
+
* HeatPump_WaterHeater - 3.5
|
|
38
|
+
* Gas_TanklessHeater - 0.8
|
|
39
|
+
* Electric_TanklessHeater - 1.0
|
|
40
|
+
|
|
41
|
+
ambient_condition: A number for the ambient temperature in which the hot
|
|
42
|
+
water tank is located [C]. This can also be the identifier of a Room
|
|
43
|
+
in which the tank is located. (Default: 22).
|
|
44
|
+
ambient_loss_coefficient: A number for the loss of heat from the water heater
|
|
45
|
+
tank to the surrounding ambient conditions [W/K]. (Default: 6 W/K).
|
|
46
|
+
|
|
47
|
+
Properties:
|
|
48
|
+
* identifier
|
|
49
|
+
* display_name
|
|
50
|
+
* equipment_type
|
|
51
|
+
* heater_efficiency
|
|
52
|
+
* ambient_condition
|
|
53
|
+
* ambient_loss_coefficient
|
|
54
|
+
* user_data
|
|
55
|
+
"""
|
|
56
|
+
__slots__ = ('_identifier', '_display_name', '_equipment_type', '_heater_efficiency',
|
|
57
|
+
'_ambient_condition', '_ambient_loss_coefficient',
|
|
58
|
+
'_locked', '_user_data', '_properties')
|
|
59
|
+
|
|
60
|
+
EQUIPMENT_TYPES = (
|
|
61
|
+
'Gas_WaterHeater',
|
|
62
|
+
'Electric_WaterHeater',
|
|
63
|
+
'HeatPump_WaterHeater',
|
|
64
|
+
'Gas_TanklessHeater',
|
|
65
|
+
'Electric_TanklessHeater'
|
|
66
|
+
)
|
|
67
|
+
DEFAULT_EFFICIENCIES = {
|
|
68
|
+
'Gas_WaterHeater': 0.8,
|
|
69
|
+
'Electric_WaterHeater': 1.0,
|
|
70
|
+
'HeatPump_WaterHeater': 3.5,
|
|
71
|
+
'Gas_TanklessHeater': 0.8,
|
|
72
|
+
'Electric_TanklessHeater': 1.0
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
def __init__(self, identifier, equipment_type='Gas_WaterHeater',
|
|
76
|
+
heater_efficiency=autocalculate, ambient_condition=22,
|
|
77
|
+
ambient_loss_coefficient=6):
|
|
78
|
+
"""Initialize SHWSystem."""
|
|
79
|
+
# assign the identifier and general properties
|
|
80
|
+
self.identifier = identifier
|
|
81
|
+
self._display_name = None
|
|
82
|
+
self._user_data = None
|
|
83
|
+
self._properties = SHWSystemProperties(self)
|
|
84
|
+
|
|
85
|
+
# set some dummy values that will get overwritten but let the checks pass
|
|
86
|
+
self._heater_efficiency = None
|
|
87
|
+
self._ambient_condition = ''
|
|
88
|
+
|
|
89
|
+
# set the main features of the HVAC system
|
|
90
|
+
self.equipment_type = equipment_type
|
|
91
|
+
self.heater_efficiency = heater_efficiency
|
|
92
|
+
self.ambient_condition = ambient_condition
|
|
93
|
+
self.ambient_loss_coefficient = ambient_loss_coefficient
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def identifier(self):
|
|
97
|
+
"""Get or set the text string for HVAC system identifier."""
|
|
98
|
+
return self._identifier
|
|
99
|
+
|
|
100
|
+
@identifier.setter
|
|
101
|
+
def identifier(self, identifier):
|
|
102
|
+
self._identifier = valid_ep_string(identifier, 'HVAC system identifier')
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def display_name(self):
|
|
106
|
+
"""Get or set a string for the object name without any character restrictions.
|
|
107
|
+
|
|
108
|
+
If not set, this will be equal to the identifier.
|
|
109
|
+
"""
|
|
110
|
+
if self._display_name is None:
|
|
111
|
+
return self._identifier
|
|
112
|
+
return self._display_name
|
|
113
|
+
|
|
114
|
+
@display_name.setter
|
|
115
|
+
def display_name(self, value):
|
|
116
|
+
if value is not None:
|
|
117
|
+
try:
|
|
118
|
+
value = str(value)
|
|
119
|
+
except UnicodeEncodeError: # Python 2 machine lacking the character set
|
|
120
|
+
pass # keep it as unicode
|
|
121
|
+
self._display_name = value
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def equipment_type(self):
|
|
125
|
+
"""Get or set text to indicate the type of the equipment."""
|
|
126
|
+
return self._equipment_type
|
|
127
|
+
|
|
128
|
+
@equipment_type.setter
|
|
129
|
+
def equipment_type(self, value):
|
|
130
|
+
clean_input = valid_string(value).lower()
|
|
131
|
+
for key in self.EQUIPMENT_TYPES:
|
|
132
|
+
if key.lower() == clean_input:
|
|
133
|
+
value = key
|
|
134
|
+
break
|
|
135
|
+
else:
|
|
136
|
+
raise ValueError(
|
|
137
|
+
'equipment_type {} is not recognized.\nChoose from the '
|
|
138
|
+
'following:\n{}'.format(value, self.EQUIPMENT_TYPES))
|
|
139
|
+
self._equipment_type = value
|
|
140
|
+
self._check_efficiency_equipment_type()
|
|
141
|
+
self._check_condition_equipment_type()
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def heater_efficiency(self):
|
|
145
|
+
"""Get or set a number for the efficiency of the heater within the system."""
|
|
146
|
+
return self._heater_efficiency if self._heater_efficiency is not None \
|
|
147
|
+
else self.DEFAULT_EFFICIENCIES[self._equipment_type]
|
|
148
|
+
|
|
149
|
+
@heater_efficiency.setter
|
|
150
|
+
def heater_efficiency(self, value):
|
|
151
|
+
if value == autocalculate:
|
|
152
|
+
value = None
|
|
153
|
+
elif value is not None:
|
|
154
|
+
value = float_positive(value, 'shw heater efficiency')
|
|
155
|
+
self._heater_efficiency = value
|
|
156
|
+
self._check_efficiency_equipment_type()
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def ambient_condition(self):
|
|
160
|
+
"""Get or set a number for the ambient temperature where the tank is located [C].
|
|
161
|
+
|
|
162
|
+
This can also be the identifier of a Room in which the tank is located.
|
|
163
|
+
"""
|
|
164
|
+
return self._ambient_condition
|
|
165
|
+
|
|
166
|
+
@ambient_condition.setter
|
|
167
|
+
def ambient_condition(self, value):
|
|
168
|
+
try:
|
|
169
|
+
value = float_positive(value, 'shw ambient condition')
|
|
170
|
+
except Exception:
|
|
171
|
+
assert isinstance(value, str), 'SHW ambient_condition must be either a ' \
|
|
172
|
+
'temperature in Celsius or the identifier of a Room to locate the ' \
|
|
173
|
+
'tank. Got {}.'.format(type(value))
|
|
174
|
+
value = valid_ep_string(value)
|
|
175
|
+
self._ambient_condition = value
|
|
176
|
+
self._check_condition_equipment_type()
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def ambient_loss_coefficient(self):
|
|
180
|
+
"""Get or set a number the loss to the surrounding ambient conditions [W/K]."""
|
|
181
|
+
return self._ambient_loss_coefficient
|
|
182
|
+
|
|
183
|
+
@ambient_loss_coefficient.setter
|
|
184
|
+
def ambient_loss_coefficient(self, value):
|
|
185
|
+
self._ambient_loss_coefficient = \
|
|
186
|
+
float_positive(value, 'shw ambient loss coefficient')
|
|
187
|
+
|
|
188
|
+
@property
|
|
189
|
+
def user_data(self):
|
|
190
|
+
"""Get or set an optional dictionary for additional meta data for this object.
|
|
191
|
+
|
|
192
|
+
This will be None until it has been set. All keys and values of this
|
|
193
|
+
dictionary should be of a standard Python type to ensure correct
|
|
194
|
+
serialization of the object to/from JSON (eg. str, float, int, list, dict)
|
|
195
|
+
"""
|
|
196
|
+
return self._user_data
|
|
197
|
+
|
|
198
|
+
@user_data.setter
|
|
199
|
+
def user_data(self, value):
|
|
200
|
+
if value is not None:
|
|
201
|
+
assert isinstance(value, dict), 'Expected dictionary for honeybee_energy' \
|
|
202
|
+
'object user_data. Got {}.'.format(type(value))
|
|
203
|
+
self._user_data = value
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def properties(self):
|
|
207
|
+
"""Get properties for extensions."""
|
|
208
|
+
return self._properties
|
|
209
|
+
|
|
210
|
+
@classmethod
|
|
211
|
+
def from_dict(cls, data):
|
|
212
|
+
"""Create a SHWSystem object from a dictionary.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
data: A SHWSystem dictionary in following the format below.
|
|
216
|
+
|
|
217
|
+
.. code-block:: python
|
|
218
|
+
|
|
219
|
+
{
|
|
220
|
+
"type": "SHWSystem",
|
|
221
|
+
"identifier": "HP SHW System 3.8", # identifier for the SHWSystem
|
|
222
|
+
"display_name": "Bathroom Service Hot Water", # name for the SHWSystem
|
|
223
|
+
"equipment_type": 'HeatPump_WaterHeater', # Equipment type
|
|
224
|
+
"heater_efficiency": 3.8, # Heater efficiency/COP
|
|
225
|
+
"ambient_condition": "Basement Room", # Identifier for room with the tank
|
|
226
|
+
"ambient_loss_coefficient": 5 # Ambient loss from the tank [W/K]
|
|
227
|
+
}
|
|
228
|
+
"""
|
|
229
|
+
assert data['type'] == 'SHWSystem', \
|
|
230
|
+
'Expected SHWSystem dictionary. Got {}.'.format(data['type'])
|
|
231
|
+
|
|
232
|
+
# extract the key features and properties of the SHW
|
|
233
|
+
equip = data['equipment_type'] if 'equipment_type' in data and \
|
|
234
|
+
data['equipment_type'] is not None else 'Gas_WaterHeater'
|
|
235
|
+
eff = data['heater_efficiency'] if 'heater_efficiency' in data and \
|
|
236
|
+
data['heater_efficiency'] != autocalculate.to_dict() else None
|
|
237
|
+
cond = data['ambient_condition'] if 'ambient_condition' in data and \
|
|
238
|
+
data['ambient_condition'] is not None else 22
|
|
239
|
+
coeff = data['ambient_loss_coefficient'] if 'ambient_loss_coefficient' \
|
|
240
|
+
in data and data['ambient_loss_coefficient'] is not None else 6
|
|
241
|
+
|
|
242
|
+
new_obj = cls(data['identifier'], equip, eff, cond, coeff)
|
|
243
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
244
|
+
new_obj.display_name = data['display_name']
|
|
245
|
+
if 'user_data' in data and data['user_data'] is not None:
|
|
246
|
+
new_obj.user_data = data['user_data']
|
|
247
|
+
if 'properties' in data and data['properties'] is not None:
|
|
248
|
+
new_obj.properties._load_extension_attr_from_dict(data['properties'])
|
|
249
|
+
return new_obj
|
|
250
|
+
|
|
251
|
+
def to_dict(self):
|
|
252
|
+
"""SHWSystem dictionary representation."""
|
|
253
|
+
base = {'type': 'SHWSystem'}
|
|
254
|
+
base['identifier'] = self.identifier
|
|
255
|
+
base['equipment_type'] = self.equipment_type
|
|
256
|
+
base['heater_efficiency'] = self.heater_efficiency
|
|
257
|
+
base['ambient_condition'] = self.ambient_condition
|
|
258
|
+
base['ambient_loss_coefficient'] = self.ambient_loss_coefficient
|
|
259
|
+
if self._display_name is not None:
|
|
260
|
+
base['display_name'] = self.display_name
|
|
261
|
+
if self._user_data is not None:
|
|
262
|
+
base['user_data'] = self.user_data
|
|
263
|
+
prop_dict = self.properties.to_dict()
|
|
264
|
+
if prop_dict is not None:
|
|
265
|
+
base['properties'] = prop_dict
|
|
266
|
+
return base
|
|
267
|
+
|
|
268
|
+
def _check_efficiency_equipment_type(self):
|
|
269
|
+
"""Check that the efficiency is suitable for the equipment type"""
|
|
270
|
+
if self._heater_efficiency is not None:
|
|
271
|
+
if self._equipment_type != 'HeatPump_WaterHeater':
|
|
272
|
+
assert self.heater_efficiency <= 1, 'heater_efficiency must be less ' \
|
|
273
|
+
'then 1 when using {} equipment_tpe. Got {}.'.format(
|
|
274
|
+
self._equipment_type, self._heater_efficiency)
|
|
275
|
+
|
|
276
|
+
def _check_condition_equipment_type(self):
|
|
277
|
+
"""Check that the ambient condition is suitable for th equipment type"""
|
|
278
|
+
if self._equipment_type == 'HeatPump_WaterHeater':
|
|
279
|
+
assert isinstance(self.ambient_condition, str), 'ambient_condition ' \
|
|
280
|
+
'must be a Room when using HeatPump_WaterHeater.'
|
|
281
|
+
|
|
282
|
+
def duplicate(self):
|
|
283
|
+
"""Get a copy of this object."""
|
|
284
|
+
return self.__copy__()
|
|
285
|
+
|
|
286
|
+
def ToString(self):
|
|
287
|
+
"""Overwrite .NET ToString."""
|
|
288
|
+
return self.__repr__()
|
|
289
|
+
|
|
290
|
+
def __copy__(self):
|
|
291
|
+
new_obj = SHWSystem(
|
|
292
|
+
self._identifier, self._equipment_type, self._heater_efficiency,
|
|
293
|
+
self._ambient_condition, self._ambient_loss_coefficient)
|
|
294
|
+
new_obj._display_name = self._display_name
|
|
295
|
+
new_obj._user_data = None if self._user_data is None else self._user_data.copy()
|
|
296
|
+
new_obj._properties._duplicate_extension_attr(self._properties)
|
|
297
|
+
return new_obj
|
|
298
|
+
|
|
299
|
+
def __key(self):
|
|
300
|
+
"""A tuple based on the object properties, useful for hashing."""
|
|
301
|
+
return (
|
|
302
|
+
self._identifier, self._equipment_type, self._heater_efficiency,
|
|
303
|
+
self._ambient_condition, self._ambient_loss_coefficient)
|
|
304
|
+
|
|
305
|
+
def __hash__(self):
|
|
306
|
+
return hash(self.__key())
|
|
307
|
+
|
|
308
|
+
def __eq__(self, other):
|
|
309
|
+
return isinstance(other, SHWSystem) and self.__key() == other.__key()
|
|
310
|
+
|
|
311
|
+
def __ne__(self, other):
|
|
312
|
+
return not self.__eq__(other)
|
|
313
|
+
|
|
314
|
+
def __repr__(self):
|
|
315
|
+
return 'SHWSystem: {}'.format(self.display_name)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""honeybee-energy simulation settings."""
|