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,723 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Complete definition of a zone program, including schedules and loads."""
|
|
3
|
+
from __future__ import division
|
|
4
|
+
import random
|
|
5
|
+
|
|
6
|
+
from .load.people import People
|
|
7
|
+
from .load.lighting import Lighting
|
|
8
|
+
from .load.equipment import ElectricEquipment, GasEquipment
|
|
9
|
+
from .load.hotwater import ServiceHotWater
|
|
10
|
+
from .load.infiltration import Infiltration
|
|
11
|
+
from .load.ventilation import Ventilation
|
|
12
|
+
from .load.setpoint import Setpoint
|
|
13
|
+
|
|
14
|
+
from honeybee._lockable import lockable
|
|
15
|
+
from honeybee.typing import valid_ep_string, tuple_with_length, clean_and_id_ep_string
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@lockable
|
|
19
|
+
class ProgramType(object):
|
|
20
|
+
"""Program Type object possessing all schedules and loads defining a program.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
identifier: Text string for a unique ProgramType 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
|
+
people: A People object to describe the occupancy of the program. If None,
|
|
27
|
+
no occupancy will be assumed for the program. (Default: None).
|
|
28
|
+
lighting: A Lighting object to describe the lighting usage of the program.
|
|
29
|
+
If None, no lighting will be assumed for the program. (Default: None).
|
|
30
|
+
electric_equipment: An ElectricEquipment object to describe the usage
|
|
31
|
+
of electric equipment within the program. If None, no electric equipment
|
|
32
|
+
will be assumed for the program. (Default: None).
|
|
33
|
+
gas_equipment: A GasEquipment object to describe the usage of gas equipment
|
|
34
|
+
within the program. If None, no gas equipment will be assumed for
|
|
35
|
+
the program. (Default: None).
|
|
36
|
+
service_hot_water: A ServiceHotWater object to describe the usage of hot
|
|
37
|
+
water within the program. If None, no hot water will be assumed for
|
|
38
|
+
the program. (Default: None).
|
|
39
|
+
infiltration: An Infiltration object to describe the outdoor air leakage of
|
|
40
|
+
the program. If None, no infiltration will be assumed for the program.
|
|
41
|
+
(Default: None).
|
|
42
|
+
ventilation: A Ventilation object to describe the minimum outdoor air
|
|
43
|
+
requirement of the program. If None, no ventilation requirement will
|
|
44
|
+
be assumed for the program. Default: None
|
|
45
|
+
setpoint: A Setpoint object to describe the temperature and humidity
|
|
46
|
+
setpoints of the program. If None, the ProgramType cannot be assigned
|
|
47
|
+
to a Room that is conditioned. (Default: None).
|
|
48
|
+
|
|
49
|
+
Properties:
|
|
50
|
+
* identifier
|
|
51
|
+
* display_name
|
|
52
|
+
* people
|
|
53
|
+
* lighting
|
|
54
|
+
* electric_equipment
|
|
55
|
+
* gas_equipment
|
|
56
|
+
* service_hot_water
|
|
57
|
+
* infiltration
|
|
58
|
+
* ventilation
|
|
59
|
+
* setpoint
|
|
60
|
+
* schedules
|
|
61
|
+
* schedules_unique
|
|
62
|
+
* user_data
|
|
63
|
+
"""
|
|
64
|
+
__slots__ = ('_identifier', '_display_name', '_people', '_lighting',
|
|
65
|
+
'_electric_equipment', '_gas_equipment', '_service_hot_water',
|
|
66
|
+
'_infiltration', '_ventilation', '_setpoint', '_locked', '_user_data')
|
|
67
|
+
|
|
68
|
+
def __init__(self, identifier, people=None, lighting=None, electric_equipment=None,
|
|
69
|
+
gas_equipment=None, service_hot_water=None,
|
|
70
|
+
infiltration=None, ventilation=None, setpoint=None):
|
|
71
|
+
"""Initialize ProgramType"""
|
|
72
|
+
self._locked = False # unlocked by default
|
|
73
|
+
self.identifier = identifier
|
|
74
|
+
self._display_name = None
|
|
75
|
+
self.people = people
|
|
76
|
+
self.lighting = lighting
|
|
77
|
+
self.electric_equipment = electric_equipment
|
|
78
|
+
self.gas_equipment = gas_equipment
|
|
79
|
+
self.service_hot_water = service_hot_water
|
|
80
|
+
self.infiltration = infiltration
|
|
81
|
+
self.ventilation = ventilation
|
|
82
|
+
self.setpoint = setpoint
|
|
83
|
+
self._user_data = None
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def identifier(self):
|
|
87
|
+
"""Get or set the text string for a unique program type identifier."""
|
|
88
|
+
return self._identifier
|
|
89
|
+
|
|
90
|
+
@identifier.setter
|
|
91
|
+
def identifier(self, identifier):
|
|
92
|
+
self._identifier = valid_ep_string(identifier, 'program type identifier')
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def display_name(self):
|
|
96
|
+
"""Get or set a string for the object name without any character restrictions.
|
|
97
|
+
|
|
98
|
+
If not set, this will be equal to the identifier.
|
|
99
|
+
"""
|
|
100
|
+
if self._display_name is None:
|
|
101
|
+
return self._identifier
|
|
102
|
+
return self._display_name
|
|
103
|
+
|
|
104
|
+
@display_name.setter
|
|
105
|
+
def display_name(self, value):
|
|
106
|
+
if value is not None:
|
|
107
|
+
try:
|
|
108
|
+
value = str(value)
|
|
109
|
+
except UnicodeEncodeError: # Python 2 machine lacking the character set
|
|
110
|
+
pass # keep it as unicode
|
|
111
|
+
self._display_name = value
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def people(self):
|
|
115
|
+
"""Get or set a People object to describe the occupancy of the program."""
|
|
116
|
+
return self._people
|
|
117
|
+
|
|
118
|
+
@people.setter
|
|
119
|
+
def people(self, value):
|
|
120
|
+
if value is not None:
|
|
121
|
+
assert isinstance(value, People), 'Expected People object for ' \
|
|
122
|
+
'ProgramType.people. Got {}.'.format(type(value))
|
|
123
|
+
self._people = value
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def lighting(self):
|
|
127
|
+
"""Get or set a Lighting object to describe the lighting usage of the program."""
|
|
128
|
+
return self._lighting
|
|
129
|
+
|
|
130
|
+
@lighting.setter
|
|
131
|
+
def lighting(self, value):
|
|
132
|
+
if value is not None:
|
|
133
|
+
assert isinstance(value, Lighting), 'Expected Lighting object for ' \
|
|
134
|
+
'ProgramType.lighting. Got {}.'.format(type(value))
|
|
135
|
+
self._lighting = value
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def electric_equipment(self):
|
|
139
|
+
"""Get or set an ElectricEquipment object to describe the usage of equipment."""
|
|
140
|
+
return self._electric_equipment
|
|
141
|
+
|
|
142
|
+
@electric_equipment.setter
|
|
143
|
+
def electric_equipment(self, value):
|
|
144
|
+
if value is not None:
|
|
145
|
+
assert isinstance(value, ElectricEquipment), 'Expected ElectricEquipment ' \
|
|
146
|
+
'object for ProgramType.electric_equipment. Got {}.'.format(type(value))
|
|
147
|
+
self._electric_equipment = value
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def gas_equipment(self):
|
|
151
|
+
"""Get or set a GasEquipment object to describe the usage of equipment."""
|
|
152
|
+
return self._gas_equipment
|
|
153
|
+
|
|
154
|
+
@gas_equipment.setter
|
|
155
|
+
def gas_equipment(self, value):
|
|
156
|
+
if value is not None:
|
|
157
|
+
assert isinstance(value, GasEquipment), 'Expected GasEquipment ' \
|
|
158
|
+
'object for ProgramType.gas_equipment. Got {}.'.format(type(value))
|
|
159
|
+
self._gas_equipment = value
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def service_hot_water(self):
|
|
163
|
+
"""Get or set a ServiceHotWater object to describe the usage of hot water."""
|
|
164
|
+
return self._service_hot_water
|
|
165
|
+
|
|
166
|
+
@service_hot_water.setter
|
|
167
|
+
def service_hot_water(self, value):
|
|
168
|
+
if value is not None:
|
|
169
|
+
assert isinstance(value, ServiceHotWater), 'Expected ServiceHotWater ' \
|
|
170
|
+
'object for ProgramType.service_hot_water. Got {}.'.format(type(value))
|
|
171
|
+
self._service_hot_water = value
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def infiltration(self):
|
|
175
|
+
"""Get or set an Infiltration object to describe the outdoor air leakage."""
|
|
176
|
+
return self._infiltration
|
|
177
|
+
|
|
178
|
+
@infiltration.setter
|
|
179
|
+
def infiltration(self, value):
|
|
180
|
+
if value is not None:
|
|
181
|
+
assert isinstance(value, Infiltration), 'Expected Infiltration ' \
|
|
182
|
+
'object for ProgramType.infiltration. Got {}.'.format(type(value))
|
|
183
|
+
self._infiltration = value
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def ventilation(self):
|
|
187
|
+
"""Get or set a Ventilation object to describe the minimum outdoor air flow."""
|
|
188
|
+
return self._ventilation
|
|
189
|
+
|
|
190
|
+
@ventilation.setter
|
|
191
|
+
def ventilation(self, value):
|
|
192
|
+
if value is not None:
|
|
193
|
+
assert isinstance(value, Ventilation), 'Expected Ventilation ' \
|
|
194
|
+
'object for ProgramType.ventilation. Got {}.'.format(type(value))
|
|
195
|
+
self._ventilation = value
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def setpoint(self):
|
|
199
|
+
"""Get or set a Setpoint object to describe the temperature setpoints."""
|
|
200
|
+
return self._setpoint
|
|
201
|
+
|
|
202
|
+
@setpoint.setter
|
|
203
|
+
def setpoint(self, value):
|
|
204
|
+
if value is not None:
|
|
205
|
+
assert isinstance(value, Setpoint), 'Expected Setpoint ' \
|
|
206
|
+
'object for ProgramType.setpoint. Got {}.'.format(type(value))
|
|
207
|
+
self._setpoint = value
|
|
208
|
+
|
|
209
|
+
@property
|
|
210
|
+
def schedules(self):
|
|
211
|
+
"""List of all schedules contained within the ProgramType."""
|
|
212
|
+
sched = []
|
|
213
|
+
if self.people is not None:
|
|
214
|
+
sched.append(self.people.occupancy_schedule)
|
|
215
|
+
sched.append(self.people.activity_schedule)
|
|
216
|
+
if self.lighting is not None:
|
|
217
|
+
sched.append(self.lighting.schedule)
|
|
218
|
+
if self.electric_equipment is not None:
|
|
219
|
+
sched.append(self.electric_equipment.schedule)
|
|
220
|
+
if self.gas_equipment is not None:
|
|
221
|
+
sched.append(self.gas_equipment.schedule)
|
|
222
|
+
if self.service_hot_water is not None:
|
|
223
|
+
sched.append(self.service_hot_water.schedule)
|
|
224
|
+
if self.infiltration is not None:
|
|
225
|
+
sched.append(self.infiltration.schedule)
|
|
226
|
+
if self.ventilation is not None and self.ventilation.schedule is not None:
|
|
227
|
+
sched.append(self.ventilation.schedule)
|
|
228
|
+
if self.setpoint is not None:
|
|
229
|
+
sched.append(self.setpoint.heating_schedule)
|
|
230
|
+
sched.append(self.setpoint.cooling_schedule)
|
|
231
|
+
if self.setpoint.humidifying_schedule is not None:
|
|
232
|
+
sched.append(self.setpoint.humidifying_schedule)
|
|
233
|
+
sched.append(self.setpoint.dehumidifying_schedule)
|
|
234
|
+
return sched
|
|
235
|
+
|
|
236
|
+
@property
|
|
237
|
+
def schedules_unique(self):
|
|
238
|
+
"""List of all unique schedules contained within the ProgramType."""
|
|
239
|
+
return list(set(self.schedules))
|
|
240
|
+
|
|
241
|
+
@property
|
|
242
|
+
def user_data(self):
|
|
243
|
+
"""Get or set an optional dictionary for additional meta data for this object.
|
|
244
|
+
|
|
245
|
+
This will be None until it has been set. All keys and values of this
|
|
246
|
+
dictionary should be of a standard Python type to ensure correct
|
|
247
|
+
serialization of the object to/from JSON (eg. str, float, int, list, dict)
|
|
248
|
+
"""
|
|
249
|
+
return self._user_data
|
|
250
|
+
|
|
251
|
+
@user_data.setter
|
|
252
|
+
def user_data(self, value):
|
|
253
|
+
if value is not None:
|
|
254
|
+
assert isinstance(value, dict), 'Expected dictionary for honeybee_energy' \
|
|
255
|
+
'object user_data. Got {}.'.format(type(value))
|
|
256
|
+
self._user_data = value
|
|
257
|
+
|
|
258
|
+
@classmethod
|
|
259
|
+
def from_dict(cls, data):
|
|
260
|
+
"""Create a ProgramType from a dictionary.
|
|
261
|
+
|
|
262
|
+
Note that the dictionary must be a non-abridged version for this
|
|
263
|
+
classmethod to work.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
data: Dictionary describing the ProgramType with the format below.
|
|
267
|
+
|
|
268
|
+
.. code-block:: python
|
|
269
|
+
|
|
270
|
+
{
|
|
271
|
+
"type": 'ProgramType',
|
|
272
|
+
"identifier": str, # ProgramType identifier
|
|
273
|
+
"display_name": str, # ProgramType display name
|
|
274
|
+
'people': {}, # A People dictionary
|
|
275
|
+
'lighting': {}, # A Lighting dictionary
|
|
276
|
+
'electric_equipment': {}, # A ElectricEquipment dictionary
|
|
277
|
+
'gas_equipment': {}, # A GasEquipment dictionary
|
|
278
|
+
'service_hot_water': {}, # A ServiceHotWater dictionary
|
|
279
|
+
'infiltration': {}, # A Infliltration dictionary
|
|
280
|
+
'ventilation': {}, # A Ventilation dictionary
|
|
281
|
+
'setpoint': {} # A Setpoint dictionary
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
"""
|
|
285
|
+
assert data['type'] == 'ProgramType', \
|
|
286
|
+
'Expected ProgramType. Got {}.'.format(data['type'])
|
|
287
|
+
|
|
288
|
+
# build each of the load objects
|
|
289
|
+
people = People.from_dict(data['people']) if 'people' in data and \
|
|
290
|
+
data['people'] is not None else None
|
|
291
|
+
lighting = Lighting.from_dict(data['lighting']) if 'lighting' in data and \
|
|
292
|
+
data['lighting'] is not None else None
|
|
293
|
+
electric_equipment = ElectricEquipment.from_dict(data['electric_equipment']) \
|
|
294
|
+
if 'electric_equipment' in data and \
|
|
295
|
+
data['electric_equipment'] is not None else None
|
|
296
|
+
gas_equipment = GasEquipment.from_dict(data['gas_equipment']) \
|
|
297
|
+
if 'gas_equipment' in data and \
|
|
298
|
+
data['gas_equipment'] is not None else None
|
|
299
|
+
shw = ServiceHotWater.from_dict(data['service_hot_water']) \
|
|
300
|
+
if 'service_hot_water' in data and \
|
|
301
|
+
data['service_hot_water'] is not None else None
|
|
302
|
+
infiltration = Infiltration.from_dict(data['infiltration']) if 'infiltration' \
|
|
303
|
+
in data and data['infiltration'] is not None else None
|
|
304
|
+
ventilation = Ventilation.from_dict(data['ventilation']) if 'ventilation' \
|
|
305
|
+
in data and data['ventilation'] is not None else None
|
|
306
|
+
setpoint = Setpoint.from_dict(data['setpoint']) if 'setpoint' in data and \
|
|
307
|
+
data['setpoint'] is not None else None
|
|
308
|
+
|
|
309
|
+
new_obj = cls(data['identifier'], people, lighting, electric_equipment,
|
|
310
|
+
gas_equipment, shw, infiltration, ventilation, setpoint)
|
|
311
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
312
|
+
new_obj.display_name = data['display_name']
|
|
313
|
+
if 'user_data' in data and data['user_data'] is not None:
|
|
314
|
+
new_obj.user_data = data['user_data']
|
|
315
|
+
return new_obj
|
|
316
|
+
|
|
317
|
+
@classmethod
|
|
318
|
+
def from_dict_abridged(cls, data, schedule_dict):
|
|
319
|
+
"""Create a ProgramType object from an abridged dictionary.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
data: A ProgramTypeAbridged dictionary.
|
|
323
|
+
schedule_dict: A dictionary with schedule identifiers as keys and
|
|
324
|
+
honeybee schedule objects as values (either ScheduleRuleset or
|
|
325
|
+
ScheduleFixedInterval). These will be used to assign the schedules
|
|
326
|
+
to the ProgramType object.
|
|
327
|
+
|
|
328
|
+
.. code-block:: python
|
|
329
|
+
|
|
330
|
+
{
|
|
331
|
+
"type": 'ProgramTypeAbridged',
|
|
332
|
+
"identifier": str, # ProgramType identifier
|
|
333
|
+
"display_name": str, # ProgramType display name
|
|
334
|
+
'people': {}, # A PeopleAbridged dictionary
|
|
335
|
+
'lighting': {}, # A LightingAbridged dictionary
|
|
336
|
+
'electric_equipment': {}, # A ElectricEquipmentAbridged dictionary
|
|
337
|
+
'gas_equipment': {}, # A GasEquipmentAbridged dictionary
|
|
338
|
+
'service_hot_water': {}, # A ServiceHotWaterAbridged dictionary
|
|
339
|
+
'infiltration': {}, # A InfiltrationAbridged dictionary
|
|
340
|
+
'ventilation': {}, # A VentilationAbridged dictionary
|
|
341
|
+
'setpoint': {} # A SetpointAbridged dictionary
|
|
342
|
+
}
|
|
343
|
+
"""
|
|
344
|
+
assert data['type'] == 'ProgramTypeAbridged', \
|
|
345
|
+
'Expected ProgramTypeAbridged dictionary. Got {}.'.format(data['type'])
|
|
346
|
+
|
|
347
|
+
# build each of the load objects
|
|
348
|
+
try:
|
|
349
|
+
people, lighting, electric_equipment, gas_equipment, shw, infiltration, \
|
|
350
|
+
ventilation, setpoint = cls._get_loads_from_abridged(data, schedule_dict)
|
|
351
|
+
except KeyError as e:
|
|
352
|
+
raise ValueError(
|
|
353
|
+
'The following schedule is missing from the model: {}'.format(e)
|
|
354
|
+
)
|
|
355
|
+
new_obj = cls(data['identifier'], people, lighting, electric_equipment,
|
|
356
|
+
gas_equipment, shw, infiltration, ventilation, setpoint)
|
|
357
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
358
|
+
new_obj.display_name = data['display_name']
|
|
359
|
+
if 'user_data' in data and data['user_data'] is not None:
|
|
360
|
+
new_obj.user_data = data['user_data']
|
|
361
|
+
return new_obj
|
|
362
|
+
|
|
363
|
+
def to_dict(self, abridged=False):
|
|
364
|
+
"""Get ProgramType as a dictionary.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
abridged: Boolean noting whether detailed schedule objects should be
|
|
368
|
+
written into the ProgramType (False) or just an abridged version (True)
|
|
369
|
+
that references the schedules by identifier. Default: False.
|
|
370
|
+
"""
|
|
371
|
+
base = {'type': 'ProgramType'} if not \
|
|
372
|
+
abridged else {'type': 'ProgramTypeAbridged'}
|
|
373
|
+
base['identifier'] = self.identifier
|
|
374
|
+
if self.people is not None:
|
|
375
|
+
base['people'] = self.people.to_dict(abridged)
|
|
376
|
+
if self.lighting is not None:
|
|
377
|
+
base['lighting'] = self.lighting.to_dict(abridged)
|
|
378
|
+
if self.electric_equipment is not None:
|
|
379
|
+
base['electric_equipment'] = self.electric_equipment.to_dict(abridged)
|
|
380
|
+
if self.gas_equipment is not None:
|
|
381
|
+
base['gas_equipment'] = self.gas_equipment.to_dict(abridged)
|
|
382
|
+
if self.service_hot_water is not None:
|
|
383
|
+
base['service_hot_water'] = self.service_hot_water.to_dict(abridged)
|
|
384
|
+
if self.infiltration is not None:
|
|
385
|
+
base['infiltration'] = self.infiltration.to_dict(abridged)
|
|
386
|
+
if self.ventilation is not None:
|
|
387
|
+
base['ventilation'] = self.ventilation.to_dict(abridged)
|
|
388
|
+
if self.setpoint is not None:
|
|
389
|
+
base['setpoint'] = self.setpoint.to_dict(abridged)
|
|
390
|
+
|
|
391
|
+
if self._display_name is not None:
|
|
392
|
+
base['display_name'] = self.display_name
|
|
393
|
+
if self._user_data is not None:
|
|
394
|
+
base['user_data'] = self.user_data
|
|
395
|
+
return base
|
|
396
|
+
|
|
397
|
+
def diversify(self, program_count, occupancy_stdev=20, lighting_stdev=20,
|
|
398
|
+
electric_equip_stdev=20, gas_equip_stdev=20, hot_water_stdev=20,
|
|
399
|
+
infiltration_stdev=20, schedule_offset=1, timestep=1):
|
|
400
|
+
"""Get an array of diversified ProgramTypes derived from this "average" one.
|
|
401
|
+
|
|
402
|
+
This method is useful when attempting to account for the fact that not
|
|
403
|
+
all rooms within a building will be used by occupants according to a
|
|
404
|
+
strict regimen. Some rooms will be used more than expected and others less.
|
|
405
|
+
|
|
406
|
+
This method uses a random number generator and gaussian distribution to
|
|
407
|
+
generate loads that vary about the mean program. Note that the randomly
|
|
408
|
+
generated values can be set to something predictable by using the native
|
|
409
|
+
Python random.seed() method before running this method.
|
|
410
|
+
|
|
411
|
+
In addition to diversifying load values, approximately 2/3 of the schedules
|
|
412
|
+
in the output programs will be offset from the mean by the input
|
|
413
|
+
schedule_offset (1/3 ahead and another 1/3 behind).
|
|
414
|
+
|
|
415
|
+
Args:
|
|
416
|
+
program_count: An positive integer for the number of diversified programs
|
|
417
|
+
to generate from this mean program.
|
|
418
|
+
occupancy_stdev: A number between 0 and 100 for the percent of the
|
|
419
|
+
occupancy people_per_area representing one standard deviation
|
|
420
|
+
of diversification from the mean. (Default 20 percent).
|
|
421
|
+
lighting_stdev: A number between 0 and 100 for the percent of the
|
|
422
|
+
lighting watts_per_area representing one standard deviation
|
|
423
|
+
of diversification from the mean. (Default 20 percent).
|
|
424
|
+
electric_equip_stdev: A number between 0 and 100 for the percent of the
|
|
425
|
+
electric equipment watts_per_area representing one standard deviation
|
|
426
|
+
of diversification from the mean. (Default 20 percent).
|
|
427
|
+
gas_equip_stdev: A number between 0 and 100 for the percent of the
|
|
428
|
+
gas equipment watts_per_area representing one standard deviation
|
|
429
|
+
of diversification from the mean. (Default 20 percent).
|
|
430
|
+
hot_water_stdev: A number between 0 and 100 for the percent of the
|
|
431
|
+
service hot water flow_per_area representing one standard deviation
|
|
432
|
+
of diversification from the mean. (Default 20 percent).
|
|
433
|
+
infiltration_stdev: A number between 0 and 100 for the percent of the
|
|
434
|
+
infiltration flow_per_exterior_area representing one standard deviation
|
|
435
|
+
of diversification from the mean. (Default 20 percent).
|
|
436
|
+
schedule_offset: A positive integer for the number of timesteps at which all
|
|
437
|
+
schedules of the resulting programs will be shifted - roughly 1/3 of
|
|
438
|
+
the programs ahead and another 1/3 behind. (Default: 1).
|
|
439
|
+
timestep: An integer for the number of timesteps per hour at which the
|
|
440
|
+
shifting is occurring. This must be a value between 1 and 60, which
|
|
441
|
+
is evenly divisible by 60. 1 indicates that each step is an hour
|
|
442
|
+
while 60 indicates that each step is a minute. (Default: 1).
|
|
443
|
+
"""
|
|
444
|
+
# duplicate the input programs so that they can be diversified
|
|
445
|
+
div_programs = [self.duplicate() for i in range(program_count)]
|
|
446
|
+
for program in div_programs:
|
|
447
|
+
program.identifier = clean_and_id_ep_string(self.identifier)
|
|
448
|
+
sch_int = [random.randint(0, 2) for i in range(program_count)]
|
|
449
|
+
|
|
450
|
+
# go through each load and generate diversified versions for the div_programs
|
|
451
|
+
if self.people is not None and occupancy_stdev != 0:
|
|
452
|
+
div_people = self.people.diversify(
|
|
453
|
+
program_count, occupancy_stdev, schedule_offset, timestep, sch_int)
|
|
454
|
+
for i, ppl in enumerate(div_people):
|
|
455
|
+
div_programs[i].people = ppl
|
|
456
|
+
if self.lighting is not None and lighting_stdev != 0:
|
|
457
|
+
div_lighting = self.lighting.diversify(
|
|
458
|
+
program_count, lighting_stdev, schedule_offset, timestep, sch_int)
|
|
459
|
+
for i, light in enumerate(div_lighting):
|
|
460
|
+
div_programs[i].lighting = light
|
|
461
|
+
if self.electric_equipment is not None and electric_equip_stdev != 0:
|
|
462
|
+
div_e_equipment = self.electric_equipment.diversify(
|
|
463
|
+
program_count, electric_equip_stdev, schedule_offset, timestep, sch_int)
|
|
464
|
+
for i, e_equip in enumerate(div_e_equipment):
|
|
465
|
+
div_programs[i].electric_equipment = e_equip
|
|
466
|
+
if self.gas_equipment is not None and gas_equip_stdev != 0:
|
|
467
|
+
div_g_equipment = self.gas_equipment.diversify(
|
|
468
|
+
program_count, gas_equip_stdev, schedule_offset, timestep, sch_int)
|
|
469
|
+
for i, g_equip in enumerate(div_g_equipment):
|
|
470
|
+
div_programs[i].gas_equipment = g_equip
|
|
471
|
+
if self.service_hot_water is not None and hot_water_stdev != 0:
|
|
472
|
+
div_hot_water = self.service_hot_water.diversify(
|
|
473
|
+
program_count, hot_water_stdev, schedule_offset, timestep, sch_int)
|
|
474
|
+
for i, shw in enumerate(div_hot_water):
|
|
475
|
+
div_programs[i].service_hot_water = shw
|
|
476
|
+
if self.infiltration is not None and infiltration_stdev != 0:
|
|
477
|
+
div_infiltration = self.infiltration.diversify(
|
|
478
|
+
program_count, infiltration_stdev, schedule_offset, timestep, sch_int)
|
|
479
|
+
for i, inf in enumerate(div_infiltration):
|
|
480
|
+
div_programs[i].infiltration = inf
|
|
481
|
+
if self.setpoint is not None and schedule_offset != 0:
|
|
482
|
+
div_setpoint = self.setpoint.diversify(
|
|
483
|
+
program_count, schedule_offset, timestep, sch_int)
|
|
484
|
+
for i, setpt in enumerate(div_setpoint):
|
|
485
|
+
div_programs[i].setpoint = setpt
|
|
486
|
+
return div_programs
|
|
487
|
+
|
|
488
|
+
@staticmethod
|
|
489
|
+
def average(identifier, program_types, weights=None, timestep_resolution=1):
|
|
490
|
+
"""Get a ProgramType object that's a weighted average between other objects.
|
|
491
|
+
|
|
492
|
+
Args:
|
|
493
|
+
identifier: A unique ID text string for the new averaged ProgramType.
|
|
494
|
+
Must be < 100 characters and not contain any EnergyPlus special
|
|
495
|
+
characters. This will be used to identify the object across a model
|
|
496
|
+
and in the exported IDF.
|
|
497
|
+
program_types: A list of ProgramType objects that will be averaged
|
|
498
|
+
together to make a new ProgramType.
|
|
499
|
+
weights: An optional list of fractional numbers with the same length
|
|
500
|
+
as the input program_types that sum to 1. These will be used to weight
|
|
501
|
+
each of the ProgramType objects in the resulting average. If None, the
|
|
502
|
+
individual objects will be weighted equally. (Default: None).
|
|
503
|
+
timestep_resolution: An optional integer for the timestep resolution
|
|
504
|
+
at which the schedules will be averaged. Any schedule details
|
|
505
|
+
smaller than this timestep will be lost in the averaging process.
|
|
506
|
+
(Default: 1).
|
|
507
|
+
"""
|
|
508
|
+
# check the weights input
|
|
509
|
+
if weights is None:
|
|
510
|
+
weights = [1 / len(program_types)] * len(program_types) if \
|
|
511
|
+
len(program_types) > 0 else []
|
|
512
|
+
else:
|
|
513
|
+
weights = tuple_with_length(weights, len(program_types), float,
|
|
514
|
+
'average ProgramType weights')
|
|
515
|
+
assert abs(sum(weights) - 1.0) <= 1e-3, 'Average ProgramType weights ' \
|
|
516
|
+
'must be equal to 1. Got {}.'.format(sum(weights))
|
|
517
|
+
|
|
518
|
+
# gather all of the load objects across all of the programs
|
|
519
|
+
people_mtx = [[pr.people, w] for pr, w in zip(program_types, weights)
|
|
520
|
+
if pr.people is not None]
|
|
521
|
+
lighting_mtx = [[pr.lighting, w] for pr, w in zip(program_types, weights)
|
|
522
|
+
if pr.lighting is not None]
|
|
523
|
+
e_equip_mtx = [[p.electric_equipment, w] for p, w in zip(program_types, weights)
|
|
524
|
+
if p.electric_equipment is not None]
|
|
525
|
+
g_equip_mtx = [[pr.gas_equipment, w] for pr, w in zip(program_types, weights)
|
|
526
|
+
if pr.gas_equipment is not None]
|
|
527
|
+
shw_mtx = [[pr.service_hot_water, w] for pr, w in zip(program_types, weights)
|
|
528
|
+
if pr.service_hot_water is not None]
|
|
529
|
+
inf_mtx = [[pr.infiltration, w] for pr, w in zip(program_types, weights)
|
|
530
|
+
if pr.infiltration is not None]
|
|
531
|
+
vent_mtx = [[pr.ventilation, w] for pr, w in zip(program_types, weights)
|
|
532
|
+
if pr.ventilation is not None]
|
|
533
|
+
setp_mtx = [[pr.setpoint, w] for pr, w in zip(program_types, weights)
|
|
534
|
+
if pr.setpoint is not None]
|
|
535
|
+
|
|
536
|
+
# compute the average loads
|
|
537
|
+
people = None
|
|
538
|
+
if len(people_mtx) != 0:
|
|
539
|
+
t_people_mtx = tuple(zip(*people_mtx))
|
|
540
|
+
people = People.average('{}_People'.format(identifier), t_people_mtx[0],
|
|
541
|
+
t_people_mtx[1], timestep_resolution)
|
|
542
|
+
lighting = None
|
|
543
|
+
if len(lighting_mtx) != 0:
|
|
544
|
+
t_lighting_mtx = tuple(zip(*lighting_mtx))
|
|
545
|
+
lighting = Lighting.average(
|
|
546
|
+
'{}_Lighting'.format(identifier), t_lighting_mtx[0], t_lighting_mtx[1],
|
|
547
|
+
timestep_resolution)
|
|
548
|
+
electric_equipment = None
|
|
549
|
+
if len(e_equip_mtx) != 0:
|
|
550
|
+
t_e_equip_mtx = tuple(zip(*e_equip_mtx))
|
|
551
|
+
electric_equipment = ElectricEquipment.average(
|
|
552
|
+
'{}_Electric Equipment'.format(identifier), t_e_equip_mtx[0],
|
|
553
|
+
t_e_equip_mtx[1], timestep_resolution)
|
|
554
|
+
gas_equipment = None
|
|
555
|
+
if len(g_equip_mtx) != 0:
|
|
556
|
+
t_g_equip_mtx = tuple(zip(*g_equip_mtx))
|
|
557
|
+
gas_equipment = GasEquipment.average(
|
|
558
|
+
'{}_Gas Equipment'.format(identifier), t_g_equip_mtx[0],
|
|
559
|
+
t_g_equip_mtx[1], timestep_resolution)
|
|
560
|
+
shw = None
|
|
561
|
+
if len(shw_mtx) != 0:
|
|
562
|
+
t_shw_mtx = tuple(zip(*shw_mtx))
|
|
563
|
+
shw = ServiceHotWater.average(
|
|
564
|
+
'{}_Service Hot Water'.format(identifier), t_shw_mtx[0],
|
|
565
|
+
t_shw_mtx[1], timestep_resolution)
|
|
566
|
+
infiltration = None
|
|
567
|
+
if len(inf_mtx) != 0:
|
|
568
|
+
t_inf_mtx = tuple(zip(*inf_mtx))
|
|
569
|
+
infiltration = Infiltration.average(
|
|
570
|
+
'{}_Infiltration'.format(identifier), t_inf_mtx[0],
|
|
571
|
+
t_inf_mtx[1], timestep_resolution)
|
|
572
|
+
ventilation = None
|
|
573
|
+
if len(vent_mtx) != 0:
|
|
574
|
+
t_vent_mtx = tuple(zip(*vent_mtx))
|
|
575
|
+
ventilation = Ventilation.average(
|
|
576
|
+
'{}_Ventilation'.format(identifier), t_vent_mtx[0],
|
|
577
|
+
t_vent_mtx[1], timestep_resolution)
|
|
578
|
+
setpoint = None
|
|
579
|
+
if len(setp_mtx) != 0:
|
|
580
|
+
t_setp_mtx = tuple(zip(*setp_mtx))
|
|
581
|
+
setpoint = Setpoint.average('{}_Setpoint'.format(identifier), t_setp_mtx[0],
|
|
582
|
+
t_setp_mtx[1], timestep_resolution)
|
|
583
|
+
|
|
584
|
+
# return the averaged object
|
|
585
|
+
return ProgramType(
|
|
586
|
+
identifier, people, lighting, electric_equipment, gas_equipment, shw,
|
|
587
|
+
infiltration, ventilation, setpoint)
|
|
588
|
+
|
|
589
|
+
def duplicate(self):
|
|
590
|
+
"""Get a copy of this object."""
|
|
591
|
+
return self.__copy__()
|
|
592
|
+
|
|
593
|
+
def lock(self):
|
|
594
|
+
"""The lock() method to will also lock the loads."""
|
|
595
|
+
self._locked = True
|
|
596
|
+
if self.people is not None:
|
|
597
|
+
self.people.lock()
|
|
598
|
+
if self.lighting is not None:
|
|
599
|
+
self.lighting.lock()
|
|
600
|
+
if self.electric_equipment is not None:
|
|
601
|
+
self.electric_equipment.lock()
|
|
602
|
+
if self.gas_equipment is not None:
|
|
603
|
+
self.gas_equipment.lock()
|
|
604
|
+
if self.service_hot_water is not None:
|
|
605
|
+
self.service_hot_water.lock()
|
|
606
|
+
if self.infiltration is not None:
|
|
607
|
+
self.infiltration.lock()
|
|
608
|
+
if self.ventilation is not None:
|
|
609
|
+
self.ventilation.lock()
|
|
610
|
+
if self.setpoint is not None:
|
|
611
|
+
self.setpoint.lock()
|
|
612
|
+
|
|
613
|
+
def unlock(self):
|
|
614
|
+
"""The unlock() method will also unlock the loads."""
|
|
615
|
+
self._locked = False
|
|
616
|
+
if self.people is not None:
|
|
617
|
+
self.people.unlock()
|
|
618
|
+
if self.lighting is not None:
|
|
619
|
+
self.lighting.unlock()
|
|
620
|
+
if self.electric_equipment is not None:
|
|
621
|
+
self.electric_equipment.unlock()
|
|
622
|
+
if self.gas_equipment is not None:
|
|
623
|
+
self.gas_equipment.unlock()
|
|
624
|
+
if self.service_hot_water is not None:
|
|
625
|
+
self.service_hot_water.unlock()
|
|
626
|
+
if self.infiltration is not None:
|
|
627
|
+
self.infiltration.unlock()
|
|
628
|
+
if self.ventilation is not None:
|
|
629
|
+
self.ventilation.unlock()
|
|
630
|
+
if self.setpoint is not None:
|
|
631
|
+
self.setpoint.unlock()
|
|
632
|
+
|
|
633
|
+
def ToString(self):
|
|
634
|
+
"""Overwrite .NET ToString."""
|
|
635
|
+
return self.__repr__()
|
|
636
|
+
|
|
637
|
+
@staticmethod
|
|
638
|
+
def _get_loads_from_abridged(data, schedule_dict):
|
|
639
|
+
"""Get re-built load objects from abridged dictionaries."""
|
|
640
|
+
people = None
|
|
641
|
+
lighting = None
|
|
642
|
+
electric_equipment = None
|
|
643
|
+
gas_equipment = None
|
|
644
|
+
shw = None
|
|
645
|
+
infiltration = None
|
|
646
|
+
ventilation = None
|
|
647
|
+
setpoint = None
|
|
648
|
+
if 'people' in data and data['people'] is not None:
|
|
649
|
+
people = People.from_dict_abridged(data['people'], schedule_dict)
|
|
650
|
+
if 'lighting' in data and data['lighting'] is not None:
|
|
651
|
+
lighting = Lighting.from_dict_abridged(data['lighting'], schedule_dict)
|
|
652
|
+
if 'electric_equipment' in data and data['electric_equipment'] is not None:
|
|
653
|
+
electric_equipment = ElectricEquipment.from_dict_abridged(
|
|
654
|
+
data['electric_equipment'], schedule_dict)
|
|
655
|
+
if 'gas_equipment' in data and data['gas_equipment'] is not None:
|
|
656
|
+
gas_equipment = GasEquipment.from_dict_abridged(
|
|
657
|
+
data['gas_equipment'], schedule_dict)
|
|
658
|
+
if 'service_hot_water' in data and data['service_hot_water'] is not None:
|
|
659
|
+
shw = ServiceHotWater.from_dict_abridged(
|
|
660
|
+
data['service_hot_water'], schedule_dict)
|
|
661
|
+
if 'infiltration' in data and data['infiltration'] is not None:
|
|
662
|
+
infiltration = Infiltration.from_dict_abridged(
|
|
663
|
+
data['infiltration'], schedule_dict)
|
|
664
|
+
if 'ventilation' in data and data['ventilation'] is not None:
|
|
665
|
+
ventilation = Ventilation.from_dict_abridged(
|
|
666
|
+
data['ventilation'], schedule_dict)
|
|
667
|
+
if 'setpoint' in data and data['setpoint'] is not None:
|
|
668
|
+
setpoint = Setpoint.from_dict_abridged(data['setpoint'], schedule_dict)
|
|
669
|
+
return people, lighting, electric_equipment, gas_equipment, shw, \
|
|
670
|
+
infiltration, ventilation, setpoint
|
|
671
|
+
|
|
672
|
+
@staticmethod
|
|
673
|
+
def _instance_in_array(object_instance, object_array):
|
|
674
|
+
"""Check if a specific object instance is already in an array.
|
|
675
|
+
|
|
676
|
+
This can be much faster than `if object_instance in object_array`
|
|
677
|
+
when you expect to be testing a lot of the same instance of an object for
|
|
678
|
+
inclusion in an array since the builtin method uses an == operator to
|
|
679
|
+
test inclusion.
|
|
680
|
+
"""
|
|
681
|
+
for val in object_array:
|
|
682
|
+
if val is object_instance:
|
|
683
|
+
return True
|
|
684
|
+
return False
|
|
685
|
+
|
|
686
|
+
def __copy__(self):
|
|
687
|
+
people = self.people.duplicate() if self.people is not None else None
|
|
688
|
+
lighting = self.lighting.duplicate() if self.lighting is not None else None
|
|
689
|
+
electric_equipment = self.electric_equipment.duplicate() if \
|
|
690
|
+
self.electric_equipment is not None else None
|
|
691
|
+
gas_equipment = self.gas_equipment.duplicate() if \
|
|
692
|
+
self.gas_equipment is not None else None
|
|
693
|
+
shw = self.service_hot_water.duplicate() if \
|
|
694
|
+
self.service_hot_water is not None else None
|
|
695
|
+
infiltration = self.infiltration.duplicate() if \
|
|
696
|
+
self.infiltration is not None else None
|
|
697
|
+
ventilation = self.ventilation.duplicate() if \
|
|
698
|
+
self.ventilation is not None else None
|
|
699
|
+
setpoint = self.setpoint.duplicate() if self.setpoint is not None else None
|
|
700
|
+
new_obj = ProgramType(self.identifier, people, lighting, electric_equipment,
|
|
701
|
+
gas_equipment, shw, infiltration, ventilation, setpoint)
|
|
702
|
+
new_obj._display_name = self._display_name
|
|
703
|
+
new_obj._user_data = None if self._user_data is None else self._user_data.copy()
|
|
704
|
+
return new_obj
|
|
705
|
+
|
|
706
|
+
def __key(self):
|
|
707
|
+
"""A tuple based on the object properties, useful for hashing."""
|
|
708
|
+
return (self.identifier, hash(self.people), hash(self.lighting),
|
|
709
|
+
hash(self.electric_equipment), hash(self.gas_equipment),
|
|
710
|
+
hash(self.service_hot_water), hash(self.infiltration),
|
|
711
|
+
hash(self.ventilation), hash(self.setpoint))
|
|
712
|
+
|
|
713
|
+
def __hash__(self):
|
|
714
|
+
return hash(self.__key())
|
|
715
|
+
|
|
716
|
+
def __eq__(self, other):
|
|
717
|
+
return isinstance(other, ProgramType) and self.__key() == other.__key()
|
|
718
|
+
|
|
719
|
+
def __ne__(self, other):
|
|
720
|
+
return not self.__eq__(other)
|
|
721
|
+
|
|
722
|
+
def __repr__(self):
|
|
723
|
+
return 'Program Type: {}'.format(self.display_name)
|