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,699 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Simple ideal air system object used to condition zones."""
|
|
3
|
+
from __future__ import division
|
|
4
|
+
|
|
5
|
+
from honeybee._lockable import lockable
|
|
6
|
+
from honeybee.typing import valid_string, float_positive, float_in_range
|
|
7
|
+
from honeybee.altnumber import autosize, no_limit
|
|
8
|
+
|
|
9
|
+
from ._base import _HVACSystem
|
|
10
|
+
from ..reader import parse_idf_string
|
|
11
|
+
from ..writer import generate_idf_string
|
|
12
|
+
from ..properties.extension import IdealAirSystemProperties
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@lockable
|
|
16
|
+
class IdealAirSystem(_HVACSystem):
|
|
17
|
+
"""Simple ideal air system object used to condition zones.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
identifier: Text string for ideal air system identifier. Must be < 100 characters
|
|
21
|
+
and not contain any EnergyPlus special characters. This will be used to
|
|
22
|
+
identify the object across a model and in the exported IDF.
|
|
23
|
+
economizer_type: Text to indicate the type of air-side economizer used on
|
|
24
|
+
the ideal air system. Economizers will mix in a greater amount of
|
|
25
|
+
outdoor air to cool the zone (rather than running the cooling system)
|
|
26
|
+
when the zone needs cooling and the outdoor air is cooler than the zone.
|
|
27
|
+
Choose from the options below. (Default: DifferentialDryBulb).
|
|
28
|
+
|
|
29
|
+
* NoEconomizer
|
|
30
|
+
* DifferentialDryBulb
|
|
31
|
+
* DifferentialEnthalpy
|
|
32
|
+
|
|
33
|
+
demand_controlled_ventilation: Boolean to note whether demand controlled
|
|
34
|
+
ventilation should be used on the system, which will vary the amount
|
|
35
|
+
of ventilation air according to the occupancy schedule of the
|
|
36
|
+
Room. (Default: False).
|
|
37
|
+
sensible_heat_recovery: A number between 0 and 1 for the effectiveness
|
|
38
|
+
of sensible heat recovery within the system. (Default: 0).
|
|
39
|
+
latent_heat_recovery: A number between 0 and 1 for the effectiveness
|
|
40
|
+
of latent heat recovery within the system. (Default: 0).
|
|
41
|
+
heating_air_temperature: A number for the maximum heating supply air
|
|
42
|
+
temperature [C]. (Default: 50, which is typical for many air-based
|
|
43
|
+
HVAC systems).
|
|
44
|
+
cooling_air_temperature: A number for the minimum cooling supply air
|
|
45
|
+
temperature [C]. (Default: 13, which is typical for many air-based
|
|
46
|
+
HVAC systems).
|
|
47
|
+
heating_limit: A number for the maximum heating capacity in Watts. This
|
|
48
|
+
can also be an Autosize object to indicate that the capacity should
|
|
49
|
+
be determined during the EnergyPlus sizing calculation. This can also
|
|
50
|
+
be a NoLimit object to indicate no upper limit to the heating
|
|
51
|
+
capacity. (Default: autosize).
|
|
52
|
+
cooling_limit: A number for the maximum cooling capacity in Watts. This
|
|
53
|
+
can also be an Autosize object to indicate that the capacity should
|
|
54
|
+
be determined during the EnergyPlus sizing calculation. This can also
|
|
55
|
+
be a NoLimit object to indicate no upper limit to the cooling
|
|
56
|
+
capacity. (Default: autosize).
|
|
57
|
+
heating_availability: An optional on/off schedule to set the availability of
|
|
58
|
+
heating over the course of the simulation. (Default: None).
|
|
59
|
+
cooling_availability: An optional on/off schedule to set the availability of
|
|
60
|
+
cooling over the course of the simulation. (Default: None).
|
|
61
|
+
|
|
62
|
+
Properties:
|
|
63
|
+
* identifier
|
|
64
|
+
* display_name
|
|
65
|
+
* economizer_type
|
|
66
|
+
* demand_controlled_ventilation
|
|
67
|
+
* sensible_heat_recovery
|
|
68
|
+
* latent_heat_recovery
|
|
69
|
+
* heating_air_temperature
|
|
70
|
+
* cooling_air_temperature
|
|
71
|
+
* heating_limit
|
|
72
|
+
* cooling_limit
|
|
73
|
+
* heating_availability
|
|
74
|
+
* cooling_availability
|
|
75
|
+
* schedules
|
|
76
|
+
* properties
|
|
77
|
+
"""
|
|
78
|
+
__slots__ = ('_economizer_type', '_demand_controlled_ventilation',
|
|
79
|
+
'_sensible_heat_recovery', '_latent_heat_recovery',
|
|
80
|
+
'_heating_air_temperature', '_cooling_air_temperature',
|
|
81
|
+
'_heating_limit', '_cooling_limit', '_heating_availability',
|
|
82
|
+
'_cooling_availability', '_properties')
|
|
83
|
+
ECONOMIZER_TYPES = ('NoEconomizer', 'DifferentialDryBulb', 'DifferentialEnthalpy')
|
|
84
|
+
|
|
85
|
+
def __init__(self, identifier, economizer_type='DifferentialDryBulb',
|
|
86
|
+
demand_controlled_ventilation=False,
|
|
87
|
+
sensible_heat_recovery=0, latent_heat_recovery=0,
|
|
88
|
+
heating_air_temperature=50, cooling_air_temperature=13,
|
|
89
|
+
heating_limit=autosize, cooling_limit=autosize,
|
|
90
|
+
heating_availability=None, cooling_availability=None):
|
|
91
|
+
"""Initialize IdealAirSystem."""
|
|
92
|
+
# initialize base HVAC system properties
|
|
93
|
+
_HVACSystem.__init__(self, identifier)
|
|
94
|
+
|
|
95
|
+
# set the main features of the HVAC system
|
|
96
|
+
self.economizer_type = economizer_type
|
|
97
|
+
self.demand_controlled_ventilation = demand_controlled_ventilation
|
|
98
|
+
self.sensible_heat_recovery = sensible_heat_recovery
|
|
99
|
+
self.latent_heat_recovery = latent_heat_recovery
|
|
100
|
+
|
|
101
|
+
# set the options affecting heating and cooling
|
|
102
|
+
# set heating_air_temperature without the setter to ensure > cooling check works
|
|
103
|
+
self._heating_air_temperature = \
|
|
104
|
+
float_positive(heating_air_temperature, 'ideal air heating air temperature')
|
|
105
|
+
self.cooling_air_temperature = cooling_air_temperature
|
|
106
|
+
self.heating_limit = heating_limit
|
|
107
|
+
self.cooling_limit = cooling_limit
|
|
108
|
+
self.heating_availability = heating_availability
|
|
109
|
+
self.cooling_availability = cooling_availability
|
|
110
|
+
|
|
111
|
+
# initialize properties for extensions
|
|
112
|
+
self._properties = IdealAirSystemProperties(self)
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def economizer_type(self):
|
|
116
|
+
"""Get or set text to indicate the type of air-side economizer.
|
|
117
|
+
|
|
118
|
+
Choose from the following options:
|
|
119
|
+
|
|
120
|
+
* NoEconomizer
|
|
121
|
+
* DifferentialDryBulb
|
|
122
|
+
* DifferentialEnthalpy
|
|
123
|
+
"""
|
|
124
|
+
return self._economizer_type
|
|
125
|
+
|
|
126
|
+
@economizer_type.setter
|
|
127
|
+
def economizer_type(self, value):
|
|
128
|
+
clean_input = valid_string(value).lower()
|
|
129
|
+
for key in self.ECONOMIZER_TYPES:
|
|
130
|
+
if key.lower() == clean_input:
|
|
131
|
+
value = key
|
|
132
|
+
break
|
|
133
|
+
else:
|
|
134
|
+
raise ValueError(
|
|
135
|
+
'economizer_type {} is not recognized.\nChoose from the '
|
|
136
|
+
'following:\n{}'.format(value, self.ECONOMIZER_TYPES))
|
|
137
|
+
self._economizer_type = value
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def demand_controlled_ventilation(self):
|
|
141
|
+
"""Get or set a boolean for whether demand controlled ventilation is present."""
|
|
142
|
+
return self._demand_controlled_ventilation
|
|
143
|
+
|
|
144
|
+
@demand_controlled_ventilation.setter
|
|
145
|
+
def demand_controlled_ventilation(self, value):
|
|
146
|
+
self._demand_controlled_ventilation = bool(value)
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def sensible_heat_recovery(self):
|
|
150
|
+
"""Get or set a number for the effectiveness of sensible heat recovery."""
|
|
151
|
+
return self._sensible_heat_recovery
|
|
152
|
+
|
|
153
|
+
@sensible_heat_recovery.setter
|
|
154
|
+
def sensible_heat_recovery(self, value):
|
|
155
|
+
self._sensible_heat_recovery = float_in_range(
|
|
156
|
+
value, 0.0, 1.0, 'ideal air sensible heat recovery')
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def latent_heat_recovery(self):
|
|
160
|
+
"""Get or set a number for the effectiveness of latent heat recovery."""
|
|
161
|
+
return self._latent_heat_recovery
|
|
162
|
+
|
|
163
|
+
@latent_heat_recovery.setter
|
|
164
|
+
def latent_heat_recovery(self, value):
|
|
165
|
+
self._latent_heat_recovery = float_in_range(
|
|
166
|
+
value, 0.0, 1.0, 'ideal air latent heat recovery')
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def heating_air_temperature(self):
|
|
170
|
+
"""Get or set a number for the maximum heating supply air temperature."""
|
|
171
|
+
return self._heating_air_temperature
|
|
172
|
+
|
|
173
|
+
@heating_air_temperature.setter
|
|
174
|
+
def heating_air_temperature(self, value):
|
|
175
|
+
self._heating_air_temperature = float_in_range(
|
|
176
|
+
value, 0, 100, 'ideal air heating air temperature')
|
|
177
|
+
self._air_temperature_check()
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def cooling_air_temperature(self):
|
|
181
|
+
"""Get or set a number for the minimum cooling supply air temperature."""
|
|
182
|
+
return self._cooling_air_temperature
|
|
183
|
+
|
|
184
|
+
@cooling_air_temperature.setter
|
|
185
|
+
def cooling_air_temperature(self, value):
|
|
186
|
+
self._cooling_air_temperature = float_in_range(
|
|
187
|
+
value, -100, 50, 'ideal air cooling air temperature')
|
|
188
|
+
self._air_temperature_check()
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def heating_limit(self):
|
|
192
|
+
"""Get or set a number for the maximum heating capacity in Watts."""
|
|
193
|
+
return self._heating_limit
|
|
194
|
+
|
|
195
|
+
@heating_limit.setter
|
|
196
|
+
def heating_limit(self, value):
|
|
197
|
+
if value == autosize or value is None:
|
|
198
|
+
self._heating_limit = autosize
|
|
199
|
+
elif value == no_limit:
|
|
200
|
+
self._heating_limit = no_limit
|
|
201
|
+
else:
|
|
202
|
+
self._heating_limit = float_positive(value, 'ideal air heating limit')
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def cooling_limit(self):
|
|
206
|
+
"""Get or set a number for the maximum cooling capacity in Watts."""
|
|
207
|
+
return self._cooling_limit
|
|
208
|
+
|
|
209
|
+
@cooling_limit.setter
|
|
210
|
+
def cooling_limit(self, value):
|
|
211
|
+
if value == autosize or value is None:
|
|
212
|
+
self._cooling_limit = autosize
|
|
213
|
+
elif value == no_limit:
|
|
214
|
+
assert self.economizer_type == 'NoEconomizer', 'Ideal air system ' \
|
|
215
|
+
'economizer_type must be "NoEconomizer" to have no cooling limit.'
|
|
216
|
+
self._cooling_limit = no_limit
|
|
217
|
+
else:
|
|
218
|
+
self._cooling_limit = float_positive(value, 'ideal air cooling limit')
|
|
219
|
+
|
|
220
|
+
@property
|
|
221
|
+
def heating_availability(self):
|
|
222
|
+
"""Get or set a ScheduleRuleset/ScheduleFixedInterval for heating availability.
|
|
223
|
+
"""
|
|
224
|
+
return self._heating_availability
|
|
225
|
+
|
|
226
|
+
@heating_availability.setter
|
|
227
|
+
def heating_availability(self, value):
|
|
228
|
+
if value is not None:
|
|
229
|
+
self._check_schedule(value, 'heating_availability')
|
|
230
|
+
value.lock() # lock editing in case schedule has multiple references
|
|
231
|
+
self._heating_availability = value
|
|
232
|
+
|
|
233
|
+
@property
|
|
234
|
+
def cooling_availability(self):
|
|
235
|
+
"""Get or set a ScheduleRuleset/ScheduleFixedInterval for cooling availability.
|
|
236
|
+
"""
|
|
237
|
+
return self._cooling_availability
|
|
238
|
+
|
|
239
|
+
@cooling_availability.setter
|
|
240
|
+
def cooling_availability(self, value):
|
|
241
|
+
if value is not None:
|
|
242
|
+
self._check_schedule(value, 'cooling_availability')
|
|
243
|
+
value.lock() # lock editing in case schedule has multiple references
|
|
244
|
+
self._cooling_availability = value
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def schedules(self):
|
|
248
|
+
"""Get an array of all the schedules associated with the HVAC system."""
|
|
249
|
+
schedules = []
|
|
250
|
+
if self._heating_availability is not None:
|
|
251
|
+
schedules.append(self._heating_availability)
|
|
252
|
+
if self._cooling_availability is not None:
|
|
253
|
+
schedules.append(self._cooling_availability)
|
|
254
|
+
return schedules
|
|
255
|
+
|
|
256
|
+
@classmethod
|
|
257
|
+
def from_idf(cls, idf_string, schedule_dict):
|
|
258
|
+
"""Create an IdealAirSystem object from an EnergyPlus IDF text string.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
idf_string: A text string fully describing an EnergyPlus
|
|
262
|
+
HVACTemplate:Zone:IdealLoadsAirSystem definition.
|
|
263
|
+
schedule_dict: A dictionary with schedule identifiers as keys and honeybee
|
|
264
|
+
schedule objects as values (either ScheduleRuleset or
|
|
265
|
+
ScheduleFixedInterval). These will be used to assign the schedules to
|
|
266
|
+
the IdealAirSystem object.
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
A tuple with two elements
|
|
270
|
+
|
|
271
|
+
- ideal_air_system: An IdealAirSystem object loaded from the idf_string.
|
|
272
|
+
|
|
273
|
+
- zone_identifier: The identifier of the zone to which the IdealAirSystem
|
|
274
|
+
object should be assigned.
|
|
275
|
+
"""
|
|
276
|
+
# check the inputs
|
|
277
|
+
ep_strs = parse_idf_string(idf_string, 'HVACTemplate:Zone:IdealLoadsAirSystem,')
|
|
278
|
+
|
|
279
|
+
# set defaults for anything not included
|
|
280
|
+
identifier = '{} Ideal Loads Air System'.format(ep_strs[0])
|
|
281
|
+
econ = 'DifferentialDryBulb'
|
|
282
|
+
dcv = False
|
|
283
|
+
sensible = 0
|
|
284
|
+
latent = 0
|
|
285
|
+
heat_temp = 50
|
|
286
|
+
cool_temp = 13
|
|
287
|
+
heat_limit = autosize
|
|
288
|
+
cool_limit = autosize
|
|
289
|
+
heat_sch = None
|
|
290
|
+
cool_sch = None
|
|
291
|
+
|
|
292
|
+
# extract the properties from the string
|
|
293
|
+
try:
|
|
294
|
+
heat_temp = ep_strs[3] if ep_strs[3] != '' else heat_temp
|
|
295
|
+
cool_temp = ep_strs[4] if ep_strs[4] != '' else cool_temp
|
|
296
|
+
if ep_strs[7].lower() == 'limitcapacity' or \
|
|
297
|
+
ep_strs[7].lower() == 'limitflowrateandcapacity':
|
|
298
|
+
heat_limit = autosize if ep_strs[9] == '' or \
|
|
299
|
+
ep_strs[9].lower() == 'autosize' else ep_strs[9]
|
|
300
|
+
else:
|
|
301
|
+
heat_limit = no_limit
|
|
302
|
+
if ep_strs[10].lower() == 'limitcapacity' or \
|
|
303
|
+
ep_strs[10].lower() == 'limitflowrateandcapacity':
|
|
304
|
+
cool_limit = autosize if ep_strs[12] == '' or \
|
|
305
|
+
ep_strs[12].lower() == 'autosize' else ep_strs[12]
|
|
306
|
+
else:
|
|
307
|
+
cool_limit = no_limit
|
|
308
|
+
if ep_strs[13] != '':
|
|
309
|
+
heat_sch = schedule_dict[ep_strs[13]]
|
|
310
|
+
if ep_strs[14] != '':
|
|
311
|
+
cool_sch = schedule_dict[ep_strs[14]]
|
|
312
|
+
if ep_strs[25].lower() == 'occupancyschedule':
|
|
313
|
+
dcv = True
|
|
314
|
+
if ep_strs[26].lower() != 'differentialdrybulb':
|
|
315
|
+
econ = ep_strs[26]
|
|
316
|
+
if ep_strs[27].lower() == 'sensible':
|
|
317
|
+
sensible = ep_strs[28] if ep_strs[28] != '' else 0.7
|
|
318
|
+
elif ep_strs[27].lower() == 'enthalpy':
|
|
319
|
+
sensible = ep_strs[28] if ep_strs[28] != '' else 0.7
|
|
320
|
+
latent = ep_strs[29] if ep_strs[29] != '' else 0.65
|
|
321
|
+
except IndexError:
|
|
322
|
+
pass # shorter Ideal air loads definition
|
|
323
|
+
|
|
324
|
+
# return the object and the zone identifier for the object
|
|
325
|
+
ideal_air_system = cls(
|
|
326
|
+
identifier, econ, dcv, sensible, latent, heat_temp, cool_temp,
|
|
327
|
+
heat_limit, cool_limit, heat_sch, cool_sch)
|
|
328
|
+
zone_identifier = ep_strs[0]
|
|
329
|
+
return ideal_air_system, zone_identifier
|
|
330
|
+
|
|
331
|
+
@classmethod
|
|
332
|
+
def from_dict(cls, data):
|
|
333
|
+
"""Create a IdealAirSystem object from a dictionary.
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
data: A IdealAirSystem dictionary in following the format below.
|
|
337
|
+
|
|
338
|
+
.. code-block:: python
|
|
339
|
+
|
|
340
|
+
{
|
|
341
|
+
"type": "IdealAirSystem",
|
|
342
|
+
"identifier": "Classroom1 Ideal Loads Air System", # identifier for the HVAC
|
|
343
|
+
"display_name": "Standard IdealAir", # name for the HVAC
|
|
344
|
+
"economizer_type": 'DifferentialDryBulb', # Economizer type
|
|
345
|
+
"demand_controlled_ventilation": True, # Demand controlled ventilation
|
|
346
|
+
"sensible_heat_recovery": 0.75, # Sensible heat recovery effectiveness
|
|
347
|
+
"latent_heat_recovery": 0.7, # Latent heat recovery effectiveness
|
|
348
|
+
"heating_air_temperature": 50, # Heating supply air temperature
|
|
349
|
+
"cooling_air_temperature": 13, # Cooling supply air temperature
|
|
350
|
+
"heating_limit": {'type': 'Autosize'}, # Max size of the heating system
|
|
351
|
+
"cooling_limit": {'type': 'Autosize'}, # Max size of the cooling system
|
|
352
|
+
"heating_availability": {}, # Schedule for availability of heat or None
|
|
353
|
+
"cooling_availability": {} # Schedule for availability of cooling or None
|
|
354
|
+
}
|
|
355
|
+
"""
|
|
356
|
+
assert data['type'] == 'IdealAirSystem', \
|
|
357
|
+
'Expected IdealAirSystem dictionary. Got {}.'.format(data['type'])
|
|
358
|
+
|
|
359
|
+
# extract the key features and properties of the HVAC
|
|
360
|
+
econ, dcv, sensible, latent, heat_temp, cool_temp, heat_limit, cool_limit = \
|
|
361
|
+
cls._properties_from_dict(data)
|
|
362
|
+
|
|
363
|
+
# extract the schedules
|
|
364
|
+
heat_avail = cls._get_schedule_from_dict(data['heating_availability']) if \
|
|
365
|
+
'heating_availability' in data and data['heating_availability'] is not None \
|
|
366
|
+
else None
|
|
367
|
+
cool_avail = cls._get_schedule_from_dict(data['cooling_availability']) if \
|
|
368
|
+
'cooling_availability' in data and data['cooling_availability'] is not None \
|
|
369
|
+
else None
|
|
370
|
+
|
|
371
|
+
new_obj = cls(data['identifier'], econ, dcv, sensible, latent, heat_temp,
|
|
372
|
+
cool_temp, heat_limit, cool_limit, heat_avail, cool_avail)
|
|
373
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
374
|
+
new_obj.display_name = data['display_name']
|
|
375
|
+
if 'user_data' in data and data['user_data'] is not None:
|
|
376
|
+
new_obj.user_data = data['user_data']
|
|
377
|
+
if 'properties' in data and data['properties'] is not None:
|
|
378
|
+
new_obj.properties._load_extension_attr_from_dict(data['properties'])
|
|
379
|
+
return new_obj
|
|
380
|
+
|
|
381
|
+
@classmethod
|
|
382
|
+
def from_dict_abridged(cls, data, schedule_dict):
|
|
383
|
+
"""Create a IdealAirSystem object from an abridged dictionary.
|
|
384
|
+
|
|
385
|
+
Args:
|
|
386
|
+
data: A IdealAirSystemAbridged dictionary in following the format below.
|
|
387
|
+
schedule_dict: A dictionary with schedule identifiers as keys and honeybee
|
|
388
|
+
schedule objects as values (either ScheduleRuleset or
|
|
389
|
+
ScheduleFixedInterval). These will be used to assign the schedules
|
|
390
|
+
to the Setpoint object.
|
|
391
|
+
|
|
392
|
+
.. code-block:: python
|
|
393
|
+
|
|
394
|
+
{
|
|
395
|
+
"type": 'IdealAirSystemAbridged',
|
|
396
|
+
"identifier": 'Warehouse1 Ideal Loads Air System', # identifier for the HVAC
|
|
397
|
+
"economizer_type": 'DifferentialDryBulb', # Economizer type
|
|
398
|
+
"demand_controlled_ventilation": True, # Demand controlled ventilation
|
|
399
|
+
"sensible_heat_recovery": 0.75, # Sensible heat recovery effectiveness
|
|
400
|
+
"latent_heat_recovery": 0.7, # Latent heat recovery effectiveness
|
|
401
|
+
"heating_air_temperature": 40, # Heating supply air temperature
|
|
402
|
+
"cooling_air_temperature": 15, # Cooling supply air temperature
|
|
403
|
+
"heating_limit": 'autosize', # Max size of the heating system in Watts
|
|
404
|
+
"cooling_limit": 'autosize', # Max size of the cooling system in Watts
|
|
405
|
+
"heating_availability": "Warehouse Heating Control", # schedule identifier
|
|
406
|
+
"cooling_availability": "Warehouse Cooling Control", # schedule identifier
|
|
407
|
+
}
|
|
408
|
+
"""
|
|
409
|
+
assert data['type'] == 'IdealAirSystemAbridged', \
|
|
410
|
+
'Expected IdealAirSystemAbridged dictionary. Got {}.'.format(data['type'])
|
|
411
|
+
|
|
412
|
+
# extract the key features and properties of the HVAC
|
|
413
|
+
econ, dcv, sensible, latent, heat_temp, cool_temp, heat_limit, cool_limit = \
|
|
414
|
+
cls._properties_from_dict(data)
|
|
415
|
+
|
|
416
|
+
# extract the schedules
|
|
417
|
+
heat_avail = None
|
|
418
|
+
cool_avail = None
|
|
419
|
+
if 'heating_availability' in data and data['heating_availability'] is not None:
|
|
420
|
+
try:
|
|
421
|
+
heat_avail = schedule_dict[data['heating_availability']]
|
|
422
|
+
except KeyError as e:
|
|
423
|
+
raise ValueError('Failed to find {} in the schedule_dict.'.format(e))
|
|
424
|
+
if 'cooling_availability' in data and data['cooling_availability'] is not None:
|
|
425
|
+
try:
|
|
426
|
+
cool_avail = schedule_dict[data['cooling_availability']]
|
|
427
|
+
except KeyError as e:
|
|
428
|
+
raise ValueError('Failed to find {} in the schedule_dict.'.format(e))
|
|
429
|
+
|
|
430
|
+
new_obj = cls(data['identifier'], econ, dcv, sensible, latent, heat_temp,
|
|
431
|
+
cool_temp, heat_limit, cool_limit, heat_avail, cool_avail)
|
|
432
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
433
|
+
new_obj.display_name = data['display_name']
|
|
434
|
+
if 'user_data' in data and data['user_data'] is not None:
|
|
435
|
+
new_obj.user_data = data['user_data']
|
|
436
|
+
if 'properties' in data and data['properties'] is not None:
|
|
437
|
+
new_obj.properties._load_extension_attr_from_dict(data['properties'])
|
|
438
|
+
return new_obj
|
|
439
|
+
|
|
440
|
+
def to_idf(self, room):
|
|
441
|
+
"""IDF string representation of IdealAirSystem object.
|
|
442
|
+
|
|
443
|
+
Note that this method does not return full definitions of heating/cooling
|
|
444
|
+
availability schedules and so this objects's schedules must also be translated
|
|
445
|
+
into the final IDF file.
|
|
446
|
+
|
|
447
|
+
Args:
|
|
448
|
+
room: A Honeybee Room for which the specific IDF string will be generated.
|
|
449
|
+
This Room must have a Setpoint object for this method to work
|
|
450
|
+
correctly since all setpoints (and any ventilation requirements)
|
|
451
|
+
are pulled from this Room.
|
|
452
|
+
|
|
453
|
+
.. code-block:: shell
|
|
454
|
+
|
|
455
|
+
HVACTemplate:Zone:IdealLoadsAirSystem,
|
|
456
|
+
Zone 1, !- Zone Name
|
|
457
|
+
All Zones, !- Thermostat Name
|
|
458
|
+
FanAvailSched, !- System Availability Schedule Name
|
|
459
|
+
50, !- Maximum Heating Supply Air Temperature {C}
|
|
460
|
+
13, !- Minimum Cooling Supply Air Temperature {C}
|
|
461
|
+
0.0156, !- Maximum Heating Supply Air Humidity Ratio {kgWater/kgDryAir}
|
|
462
|
+
0.0077, !- Minimum Cooling Supply Air Humidity Ratio {kgWater/kgDryAir}
|
|
463
|
+
NoLimit, !- Heating Limit
|
|
464
|
+
, !- Maximum Heating Air Flow Rate {m3/s}
|
|
465
|
+
, !- Maximum Sensible Heating Capacity {W}
|
|
466
|
+
NoLimit, !- Cooling Limit
|
|
467
|
+
, !- Maximum Cooling Air Flow Rate {m3/s}
|
|
468
|
+
, !- Maximum Total Cooling Capacity {W}
|
|
469
|
+
, !- Heating Availability Schedule Name
|
|
470
|
+
, !- Cooling Availability Schedule Name
|
|
471
|
+
ConstantSensibleHeatRatio, !- Dehumidification Control Type
|
|
472
|
+
0.7, !- Cooling Sensible Heat Ratio
|
|
473
|
+
60, !- Dehumidification Setpoint {percent}
|
|
474
|
+
None, !- Humidification Control Type
|
|
475
|
+
30, !- Humidification Setpoint {percent}
|
|
476
|
+
flow/person, !- Outdoor Air Method
|
|
477
|
+
0.00944, !- Outdoor Air Flow Rate per Person {m3/s}
|
|
478
|
+
0.0, !- Outdoor Air Flow Rate per Zone Floor Area {m3/s-m2}
|
|
479
|
+
0.0, !- Outdoor Air Flow Rate per Zone {m3/s}
|
|
480
|
+
, !- Design Specification Outdoor Air Object Name
|
|
481
|
+
None, !- Demand Controlled Ventilation Type
|
|
482
|
+
NoEconomizer, !- Outdoor Air Economizer Type
|
|
483
|
+
None, !- Heat Recovery Type
|
|
484
|
+
0.70, !- Sensible Heat Recovery Effectiveness
|
|
485
|
+
0.65; !- Latent Heat Recovery Effectiveness
|
|
486
|
+
"""
|
|
487
|
+
# check that a setpoint object is assigned
|
|
488
|
+
r_set_p = room.properties.energy.setpoint
|
|
489
|
+
r_vent = room.properties.energy.ventilation
|
|
490
|
+
assert r_set_p is not None, 'IdealAirSystem must be assigned to a Room ' \
|
|
491
|
+
'with a setpoint object to use IdealAirSystem.to_idf.'
|
|
492
|
+
return self.to_idf_zone(room.identifier, r_set_p, r_vent)
|
|
493
|
+
|
|
494
|
+
def to_idf_zone(self, zone_identifier, setpoint, ventilation=None):
|
|
495
|
+
"""IDF string representation of IdealAirSystem using custom zone inputs.
|
|
496
|
+
|
|
497
|
+
This method is identical to the to_idf() method but it is intended to work
|
|
498
|
+
with the case that the ideal air system is assigned to multiple Rooms that
|
|
499
|
+
together form a single thermal Zone. As such, there are custom inputs for
|
|
500
|
+
the name of the zone as well as the setpoint and ventilation.
|
|
501
|
+
|
|
502
|
+
Args:
|
|
503
|
+
zone_identifier: Text for the identifier of the zone to which the
|
|
504
|
+
ideal air system is assigned.
|
|
505
|
+
setpoint: A Setpoint object representing the thermostat setpoints
|
|
506
|
+
of the Zone.
|
|
507
|
+
ventilation: An optional Ventilation object that represents the minimum
|
|
508
|
+
outdoor air requirements of the Zone. (Default: None).
|
|
509
|
+
"""
|
|
510
|
+
# extract all of the fields from this object and its room
|
|
511
|
+
# heating limit
|
|
512
|
+
if self.heating_limit != no_limit:
|
|
513
|
+
h_lim_type = 'LimitCapacity'
|
|
514
|
+
heat_limit = str(self.heating_limit) # stringify Autosize
|
|
515
|
+
else:
|
|
516
|
+
h_lim_type = 'NoLimit'
|
|
517
|
+
heat_limit = ''
|
|
518
|
+
# cooling limit
|
|
519
|
+
if self.cooling_limit != no_limit:
|
|
520
|
+
c_lim_type = 'LimitFlowRateAndCapacity'
|
|
521
|
+
air_limit = 'Autosize'
|
|
522
|
+
cool_limit = str(self.cooling_limit) # stringify Autosize
|
|
523
|
+
else:
|
|
524
|
+
c_lim_type = 'NoLimit'
|
|
525
|
+
air_limit = cool_limit = ''
|
|
526
|
+
# availability schedules
|
|
527
|
+
heat_avail = self.heating_availability.identifier if \
|
|
528
|
+
self.heating_availability is not None else ''
|
|
529
|
+
cool_avail = self.cooling_availability.identifier if \
|
|
530
|
+
self.cooling_availability is not None else ''
|
|
531
|
+
# humidifying setpoint
|
|
532
|
+
if setpoint.humidifying_setpoint is not None:
|
|
533
|
+
humid_type = 'Humidistat'
|
|
534
|
+
humid_setpt = setpoint.humidifying_setpoint
|
|
535
|
+
else:
|
|
536
|
+
humid_type = 'None'
|
|
537
|
+
humid_setpt = ''
|
|
538
|
+
# dehumidifying setpoint
|
|
539
|
+
if setpoint.dehumidifying_setpoint is not None:
|
|
540
|
+
dehumid_type = 'Humidistat'
|
|
541
|
+
dehumid_setpt = setpoint.dehumidifying_setpoint
|
|
542
|
+
else:
|
|
543
|
+
dehumid_type = 'None'
|
|
544
|
+
dehumid_setpt = ''
|
|
545
|
+
# ventilation requirements
|
|
546
|
+
if ventilation is not None:
|
|
547
|
+
oa_method = 'DetailedSpecification'
|
|
548
|
+
oa_id = '{}..{}'.format(ventilation.identifier, zone_identifier)
|
|
549
|
+
else:
|
|
550
|
+
oa_method = 'None'
|
|
551
|
+
oa_id = ''
|
|
552
|
+
# demand controlled ventilation
|
|
553
|
+
dcv = 'OccupancySchedule' if self.demand_controlled_ventilation else 'None'
|
|
554
|
+
# heat recovery
|
|
555
|
+
if self.sensible_heat_recovery == 0 and self.latent_heat_recovery == 0:
|
|
556
|
+
heat_recovery = 'None'
|
|
557
|
+
elif self.latent_heat_recovery != 0:
|
|
558
|
+
heat_recovery = 'Enthalpy'
|
|
559
|
+
else:
|
|
560
|
+
heat_recovery = 'Sensible'
|
|
561
|
+
|
|
562
|
+
# return a full IDF string
|
|
563
|
+
thermostat = '{}..{}'.format(setpoint.identifier, zone_identifier) \
|
|
564
|
+
if setpoint.setpoint_cutout_difference == 0 else ''
|
|
565
|
+
values = (zone_identifier, thermostat,
|
|
566
|
+
'', self.heating_air_temperature, self.cooling_air_temperature,
|
|
567
|
+
'', '', h_lim_type, '', heat_limit, c_lim_type, air_limit, cool_limit,
|
|
568
|
+
heat_avail, cool_avail, dehumid_type, '', dehumid_setpt,
|
|
569
|
+
humid_type, humid_setpt, oa_method, '', '', '', oa_id, dcv,
|
|
570
|
+
self.economizer_type, heat_recovery, self.sensible_heat_recovery,
|
|
571
|
+
self.latent_heat_recovery)
|
|
572
|
+
comments = (
|
|
573
|
+
'zone name', 'template thermostat name', 'availability schedule',
|
|
574
|
+
'heating supply air temp {C}', 'cooling supply air temp {C}',
|
|
575
|
+
'max heating supply air hr {kg-H2O/kg-air}',
|
|
576
|
+
'min cooling supply air hr {kg-H2O/kg-air}',
|
|
577
|
+
'heating limit', 'max heating fow rate {m3/s}', 'max sensible heat capacity',
|
|
578
|
+
'cooling limit', 'max cooling fow rate {m3/s}', 'max total cooling capacity',
|
|
579
|
+
'heating availability schedule', 'cooling availability schedule',
|
|
580
|
+
'dehumidification type', 'cooling shr', 'dehumidification setpoint',
|
|
581
|
+
'humidification type', 'humidification setpoint', 'outdoor air method',
|
|
582
|
+
'oa per person', 'oa per area', 'oa per zone', 'outdoor air object name',
|
|
583
|
+
'demand controlled vent type', 'economizer type', 'heat recovery type',
|
|
584
|
+
'sensible heat recovery effectiveness', 'latent heat recovery effectiveness')
|
|
585
|
+
return generate_idf_string(
|
|
586
|
+
'HVACTemplate:Zone:IdealLoadsAirSystem', values, comments)
|
|
587
|
+
|
|
588
|
+
def to_dict(self, abridged=False):
|
|
589
|
+
"""IdealAirSystem dictionary representation.
|
|
590
|
+
|
|
591
|
+
Args:
|
|
592
|
+
abridged: Boolean to note whether the full dictionary describing the
|
|
593
|
+
object should be returned (False) or just an abridged version (True),
|
|
594
|
+
which only specifies the identifiers of schedules. Default: False.
|
|
595
|
+
"""
|
|
596
|
+
base = {'type': 'IdealAirSystem'} if not \
|
|
597
|
+
abridged else {'type': 'IdealAirSystemAbridged'}
|
|
598
|
+
base['identifier'] = self.identifier
|
|
599
|
+
base['economizer_type'] = self.economizer_type
|
|
600
|
+
base['demand_controlled_ventilation'] = self.demand_controlled_ventilation
|
|
601
|
+
base['sensible_heat_recovery'] = self.sensible_heat_recovery
|
|
602
|
+
base['latent_heat_recovery'] = self.latent_heat_recovery
|
|
603
|
+
base['heating_air_temperature'] = self.heating_air_temperature
|
|
604
|
+
base['cooling_air_temperature'] = self.cooling_air_temperature
|
|
605
|
+
base['heating_limit'] = self.heating_limit if \
|
|
606
|
+
isinstance(self.heating_limit, float) else self.heating_limit.to_dict()
|
|
607
|
+
base['cooling_limit'] = self.cooling_limit if \
|
|
608
|
+
isinstance(self.cooling_limit, float) else self.cooling_limit.to_dict()
|
|
609
|
+
if self.heating_availability is not None:
|
|
610
|
+
base['heating_availability'] = self.heating_availability.identifier if \
|
|
611
|
+
abridged else self.heating_availability.to_dict()
|
|
612
|
+
if self.cooling_availability is not None:
|
|
613
|
+
base['cooling_availability'] = self.cooling_availability.identifier if \
|
|
614
|
+
abridged else self.cooling_availability.to_dict()
|
|
615
|
+
if self._display_name is not None:
|
|
616
|
+
base['display_name'] = self.display_name
|
|
617
|
+
if self._user_data is not None:
|
|
618
|
+
base['user_data'] = self.user_data
|
|
619
|
+
prop_dict = self.properties.to_dict()
|
|
620
|
+
if prop_dict is not None:
|
|
621
|
+
base['properties'] = prop_dict
|
|
622
|
+
return base
|
|
623
|
+
|
|
624
|
+
def _air_temperature_check(self):
|
|
625
|
+
"""Check that heating_air_temperature is greater than cooling_air_temperature."""
|
|
626
|
+
assert self._heating_air_temperature > self._cooling_air_temperature, \
|
|
627
|
+
'Ideal air heating_air_temperature must be greater than ' \
|
|
628
|
+
'cooling_air_temperature.'
|
|
629
|
+
|
|
630
|
+
@staticmethod
|
|
631
|
+
def _properties_from_dict(data):
|
|
632
|
+
"""Extract basic properties from a dictionary and assign defaults."""
|
|
633
|
+
# extract the key features of the HVAC
|
|
634
|
+
econ = data['economizer_type'] if 'economizer_type' in data and \
|
|
635
|
+
data['economizer_type'] is not None else 'DifferentialDryBulb'
|
|
636
|
+
dcv = data['demand_controlled_ventilation'] if \
|
|
637
|
+
'demand_controlled_ventilation' in data else False
|
|
638
|
+
sensible = data['sensible_heat_recovery'] if \
|
|
639
|
+
'sensible_heat_recovery' in data else 0
|
|
640
|
+
latent = data['latent_heat_recovery'] if \
|
|
641
|
+
'latent_heat_recovery' in data else 0
|
|
642
|
+
|
|
643
|
+
# extract the heating and cooling temperature
|
|
644
|
+
heat_temp = data['heating_air_temperature'] if \
|
|
645
|
+
'heating_air_temperature' in data else 50
|
|
646
|
+
cool_temp = data['cooling_air_temperature'] if \
|
|
647
|
+
'cooling_air_temperature' in data else 13
|
|
648
|
+
|
|
649
|
+
# extract the heating and cooling limits
|
|
650
|
+
if 'heating_limit' not in data or data['heating_limit'] == autosize.to_dict():
|
|
651
|
+
heat_limit = autosize
|
|
652
|
+
else:
|
|
653
|
+
heat_limit = no_limit if data['heating_limit'] == no_limit.to_dict() \
|
|
654
|
+
else data['heating_limit']
|
|
655
|
+
if 'cooling_limit' not in data or data['cooling_limit'] == autosize.to_dict():
|
|
656
|
+
cool_limit = autosize
|
|
657
|
+
else:
|
|
658
|
+
cool_limit = no_limit if data['cooling_limit'] == no_limit.to_dict() \
|
|
659
|
+
else data['cooling_limit']
|
|
660
|
+
|
|
661
|
+
return econ, dcv, sensible, latent, heat_temp, cool_temp, heat_limit, cool_limit
|
|
662
|
+
|
|
663
|
+
@property
|
|
664
|
+
def properties(self):
|
|
665
|
+
"""Get properties for extensions."""
|
|
666
|
+
return self._properties
|
|
667
|
+
|
|
668
|
+
def __copy__(self):
|
|
669
|
+
new_obj = IdealAirSystem(
|
|
670
|
+
self._identifier, self._economizer_type, self._demand_controlled_ventilation,
|
|
671
|
+
self._sensible_heat_recovery, self._latent_heat_recovery,
|
|
672
|
+
self._heating_air_temperature, self._cooling_air_temperature,
|
|
673
|
+
self._heating_limit, self._cooling_limit, self._heating_availability,
|
|
674
|
+
self._cooling_availability)
|
|
675
|
+
new_obj._display_name = self._display_name
|
|
676
|
+
new_obj._user_data = None if self._user_data is None else self._user_data.copy()
|
|
677
|
+
new_obj._properties._duplicate_extension_attr(self._properties)
|
|
678
|
+
return new_obj
|
|
679
|
+
|
|
680
|
+
def __key(self):
|
|
681
|
+
"""A tuple based on the object properties, useful for hashing."""
|
|
682
|
+
return (
|
|
683
|
+
self._identifier, self._economizer_type, self._demand_controlled_ventilation,
|
|
684
|
+
self._sensible_heat_recovery, self._latent_heat_recovery,
|
|
685
|
+
self._heating_air_temperature, self._cooling_air_temperature,
|
|
686
|
+
str(self._heating_limit), str(self._cooling_limit),
|
|
687
|
+
hash(self._heating_availability), hash(self._cooling_availability))
|
|
688
|
+
|
|
689
|
+
def __hash__(self):
|
|
690
|
+
return hash(self.__key())
|
|
691
|
+
|
|
692
|
+
def __eq__(self, other):
|
|
693
|
+
return isinstance(other, IdealAirSystem) and self.__key() == other.__key()
|
|
694
|
+
|
|
695
|
+
def __ne__(self, other):
|
|
696
|
+
return not self.__eq__(other)
|
|
697
|
+
|
|
698
|
+
def __repr__(self):
|
|
699
|
+
return 'IdealAirSystem: {}'.format(self.display_name)
|