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,472 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Load object used to represent various types of specific processes."""
|
|
3
|
+
from __future__ import division
|
|
4
|
+
|
|
5
|
+
from honeybee._lockable import lockable
|
|
6
|
+
from honeybee.typing import float_in_range, float_positive, valid_string, \
|
|
7
|
+
valid_ep_string
|
|
8
|
+
|
|
9
|
+
from ._base import _LoadBase
|
|
10
|
+
from ..schedule.ruleset import ScheduleRuleset
|
|
11
|
+
from ..schedule.fixedinterval import ScheduleFixedInterval
|
|
12
|
+
from ..reader import parse_idf_string
|
|
13
|
+
from ..writer import generate_idf_string
|
|
14
|
+
from ..properties.extension import ProcessProperties
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@lockable
|
|
18
|
+
class Process(_LoadBase):
|
|
19
|
+
"""Load object used to represent various types of specific processes.
|
|
20
|
+
|
|
21
|
+
Examples include kilns, manufacturing equipment, and various industrial
|
|
22
|
+
processes. They can also be used to represent wood burning fireplaces
|
|
23
|
+
or certain pieces of equipment to be separated from the other end uses.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
identifier: Text string for a unique Process ID. Must be < 100 characters
|
|
27
|
+
and not contain any EnergyPlus special characters. This will be used to
|
|
28
|
+
identify the object across a model and in the exported IDF.
|
|
29
|
+
watts: A numerical value for the process load power in Watts.
|
|
30
|
+
schedule: A ScheduleRuleset or ScheduleFixedInterval for the use of process
|
|
31
|
+
over the course of the year. The type of this schedule should be
|
|
32
|
+
Fractional and the fractional values will get multiplied by the
|
|
33
|
+
watts to yield a complete process load profile.
|
|
34
|
+
fuel_type: Text to denote the type of fuel consumed by the process.
|
|
35
|
+
Using the "None" type indicates that no end uses will be associated
|
|
36
|
+
with the process, only the zone gains. Choose from the following.
|
|
37
|
+
|
|
38
|
+
* Electricity
|
|
39
|
+
* NaturalGas
|
|
40
|
+
* Propane
|
|
41
|
+
* FuelOilNo1
|
|
42
|
+
* FuelOilNo2
|
|
43
|
+
* Diesel
|
|
44
|
+
* Gasoline
|
|
45
|
+
* Coal
|
|
46
|
+
* Steam
|
|
47
|
+
* DistrictHeating
|
|
48
|
+
* DistrictCooling
|
|
49
|
+
* OtherFuel1
|
|
50
|
+
* OtherFuel2
|
|
51
|
+
* None
|
|
52
|
+
|
|
53
|
+
end_use_category: Text to indicate the end-use subcategory, which will identify
|
|
54
|
+
the process load in the output end use table. Examples include
|
|
55
|
+
“Cooking”, “Clothes Drying”, etc. Setting this to "General" will
|
|
56
|
+
result in the process load being reported as part of the other Interior
|
|
57
|
+
Equipment. (Default: Process).
|
|
58
|
+
radiant_fraction: A number between 0 and 1 for the fraction of the total
|
|
59
|
+
load given off as long wave radiant heat. (Default: 0).
|
|
60
|
+
latent_fraction: A number between 0 and 1 for the fraction of the total
|
|
61
|
+
load that is latent (as opposed to sensible). (Default: 0).
|
|
62
|
+
lost_fraction: A number between 0 and 1 for the fraction of the total
|
|
63
|
+
load that is lost outside of the zone and the HVAC system.
|
|
64
|
+
Typically, this is used to represent heat that is exhausted directly
|
|
65
|
+
out of a zone (as you would for a stove). (Default: 0).
|
|
66
|
+
|
|
67
|
+
Properties:
|
|
68
|
+
* identifier
|
|
69
|
+
* display_name
|
|
70
|
+
* watts
|
|
71
|
+
* schedule
|
|
72
|
+
* fuel_type
|
|
73
|
+
* end_use_category
|
|
74
|
+
* radiant_fraction
|
|
75
|
+
* latent_fraction
|
|
76
|
+
* lost_fraction
|
|
77
|
+
* convected_fraction
|
|
78
|
+
* user_data
|
|
79
|
+
"""
|
|
80
|
+
__slots__ = ('_watts', '_schedule', '_fuel_type', '_end_use_category',
|
|
81
|
+
'_radiant_fraction', '_latent_fraction', '_lost_fraction')
|
|
82
|
+
FUEL_TYPES = (
|
|
83
|
+
'Electricity',
|
|
84
|
+
'NaturalGas',
|
|
85
|
+
'Propane',
|
|
86
|
+
'FuelOilNo1',
|
|
87
|
+
'FuelOilNo2',
|
|
88
|
+
'Diesel',
|
|
89
|
+
'Gasoline',
|
|
90
|
+
'Coal',
|
|
91
|
+
'Steam',
|
|
92
|
+
'DistrictHeating',
|
|
93
|
+
'DistrictCooling',
|
|
94
|
+
'OtherFuel1',
|
|
95
|
+
'OtherFuel2',
|
|
96
|
+
'None'
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
def __init__(self, identifier, watts, schedule, fuel_type,
|
|
100
|
+
end_use_category='Process', radiant_fraction=0,
|
|
101
|
+
latent_fraction=0, lost_fraction=0):
|
|
102
|
+
"""Initialize Process."""
|
|
103
|
+
_LoadBase.__init__(self, identifier)
|
|
104
|
+
self._latent_fraction = 0 # starting value so that check runs correctly
|
|
105
|
+
self._lost_fraction = 0 # starting value so that check runs correctly
|
|
106
|
+
|
|
107
|
+
self.watts = watts
|
|
108
|
+
self.schedule = schedule
|
|
109
|
+
self.fuel_type = fuel_type
|
|
110
|
+
self.end_use_category = end_use_category
|
|
111
|
+
self.radiant_fraction = radiant_fraction
|
|
112
|
+
self.latent_fraction = latent_fraction
|
|
113
|
+
self.lost_fraction = lost_fraction
|
|
114
|
+
self._properties = ProcessProperties(self)
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def watts(self):
|
|
118
|
+
"""Get or set the process total power in Watts."""
|
|
119
|
+
return self._watts
|
|
120
|
+
|
|
121
|
+
@watts.setter
|
|
122
|
+
def watts(self, value):
|
|
123
|
+
self._watts = float_positive(value, 'process watts')
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def schedule(self):
|
|
127
|
+
"""Get or set a ScheduleRuleset or ScheduleFixedInterval for process usage."""
|
|
128
|
+
return self._schedule
|
|
129
|
+
|
|
130
|
+
@schedule.setter
|
|
131
|
+
def schedule(self, value):
|
|
132
|
+
assert isinstance(value, (ScheduleRuleset, ScheduleFixedInterval)), \
|
|
133
|
+
'Expected ScheduleRuleset or ScheduleFixedInterval for process ' \
|
|
134
|
+
'schedule. Got {}.'.format(type(value))
|
|
135
|
+
self._check_fractional_schedule_type(value, 'Equipment')
|
|
136
|
+
value.lock() # lock editing in case schedule has multiple references
|
|
137
|
+
self._schedule = value
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def fuel_type(self):
|
|
141
|
+
"""Get or set text to denote the type of fuel consumed by the process.
|
|
142
|
+
|
|
143
|
+
Choose from the following options.
|
|
144
|
+
|
|
145
|
+
* Electricity
|
|
146
|
+
* NaturalGas
|
|
147
|
+
* Propane
|
|
148
|
+
* FuelOilNo1
|
|
149
|
+
* FuelOilNo2
|
|
150
|
+
* Diesel
|
|
151
|
+
* Gasoline
|
|
152
|
+
* Coal
|
|
153
|
+
* Steam
|
|
154
|
+
* DistrictHeating
|
|
155
|
+
* DistrictCooling
|
|
156
|
+
* OtherFuel1
|
|
157
|
+
* OtherFuel2
|
|
158
|
+
* None
|
|
159
|
+
"""
|
|
160
|
+
return self._fuel_type
|
|
161
|
+
|
|
162
|
+
@fuel_type.setter
|
|
163
|
+
def fuel_type(self, value):
|
|
164
|
+
clean_input = valid_string(value).lower()
|
|
165
|
+
for key in self.FUEL_TYPES:
|
|
166
|
+
if key.lower() == clean_input:
|
|
167
|
+
value = key
|
|
168
|
+
break
|
|
169
|
+
else:
|
|
170
|
+
raise ValueError(
|
|
171
|
+
'fuel_type {} is not recognized.\nChoose from the '
|
|
172
|
+
'following:\n{}'.format(value, '\n'.join(self.FUEL_TYPES)))
|
|
173
|
+
self._fuel_type = value
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def end_use_category(self):
|
|
177
|
+
"""Get or set text to indicate the end-use subcategory."""
|
|
178
|
+
return self._end_use_category
|
|
179
|
+
|
|
180
|
+
@end_use_category.setter
|
|
181
|
+
def end_use_category(self, value):
|
|
182
|
+
self._end_use_category = valid_ep_string(value)
|
|
183
|
+
|
|
184
|
+
@property
|
|
185
|
+
def radiant_fraction(self):
|
|
186
|
+
"""Get or set the fraction of process heat given off as long wave radiation."""
|
|
187
|
+
return self._radiant_fraction
|
|
188
|
+
|
|
189
|
+
@radiant_fraction.setter
|
|
190
|
+
def radiant_fraction(self, value):
|
|
191
|
+
self._radiant_fraction = float_in_range(
|
|
192
|
+
value, 0.0, 1.0, 'process radiant fraction')
|
|
193
|
+
self._check_fractions()
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def latent_fraction(self):
|
|
197
|
+
"""Get or set the fraction of process heat that is latent."""
|
|
198
|
+
return self._latent_fraction
|
|
199
|
+
|
|
200
|
+
@latent_fraction.setter
|
|
201
|
+
def latent_fraction(self, value):
|
|
202
|
+
self._latent_fraction = float_in_range(
|
|
203
|
+
value, 0.0, 1.0, 'process latent fraction')
|
|
204
|
+
self._check_fractions()
|
|
205
|
+
|
|
206
|
+
@property
|
|
207
|
+
def lost_fraction(self):
|
|
208
|
+
"""Get or set the fraction of process heat that is lost out of the zone."""
|
|
209
|
+
return self._lost_fraction
|
|
210
|
+
|
|
211
|
+
@lost_fraction.setter
|
|
212
|
+
def lost_fraction(self, value):
|
|
213
|
+
self._lost_fraction = float_in_range(
|
|
214
|
+
value, 0.0, 1.0, 'process lost fraction')
|
|
215
|
+
self._check_fractions()
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def convected_fraction(self):
|
|
219
|
+
"""Get the fraction of process heat that convects to the zone air."""
|
|
220
|
+
return 1 - sum((self._radiant_fraction, self._latent_fraction,
|
|
221
|
+
self._lost_fraction))
|
|
222
|
+
|
|
223
|
+
@classmethod
|
|
224
|
+
def from_idf(cls, idf_string, schedule_dict):
|
|
225
|
+
"""Create a Process object from an EnergyPlus OtherEquipment IDF text string.
|
|
226
|
+
|
|
227
|
+
Note that the OtherEquipment idf_string must use the 'equipment level'
|
|
228
|
+
method in order to be successfully imported.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
idf_string: A text string fully describing an EnergyPlus
|
|
232
|
+
OtherEquipment definition.
|
|
233
|
+
schedule_dict: A dictionary with schedule identifiers as keys and honeybee
|
|
234
|
+
schedule objects as values (either ScheduleRuleset or
|
|
235
|
+
ScheduleFixedInterval). These will be used to assign the schedules to
|
|
236
|
+
the OtherEquipment object.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
A tuple with two elements
|
|
240
|
+
|
|
241
|
+
- process: An Process object loaded from the idf_string.
|
|
242
|
+
|
|
243
|
+
- zone_identifier: The identifier of the zone to which the
|
|
244
|
+
Process object should be assigned.
|
|
245
|
+
"""
|
|
246
|
+
# check the inputs
|
|
247
|
+
ep_strs = parse_idf_string(idf_string, 'OtherEquipment,')
|
|
248
|
+
# check the inputs
|
|
249
|
+
if len(ep_strs) > 4:
|
|
250
|
+
assert ep_strs[4].lower() == 'equipmentlevel', 'Equipment must use ' \
|
|
251
|
+
'Watts/Area method to be loaded from IDF to honeybee.'
|
|
252
|
+
# extract the properties from the string
|
|
253
|
+
watts = 0
|
|
254
|
+
rad_fract = 0
|
|
255
|
+
lat_fract = 0
|
|
256
|
+
lost_fract = 0
|
|
257
|
+
cat = 'General'
|
|
258
|
+
try:
|
|
259
|
+
watts = ep_strs[5] if ep_strs[5] != '' else 0
|
|
260
|
+
lat_fract = ep_strs[8] if ep_strs[8] != '' else 0
|
|
261
|
+
rad_fract = ep_strs[9] if ep_strs[9] != '' else 0
|
|
262
|
+
lost_fract = ep_strs[10] if ep_strs[10] != '' else 0
|
|
263
|
+
cat = ep_strs[12] if ep_strs[12] != '' else 'General'
|
|
264
|
+
except IndexError:
|
|
265
|
+
pass # shorter equipment definition lacking fractions
|
|
266
|
+
# extract the schedules from the string
|
|
267
|
+
try:
|
|
268
|
+
sched = schedule_dict[ep_strs[3]]
|
|
269
|
+
except KeyError as e:
|
|
270
|
+
raise ValueError('Failed to find {} in the schedule_dict.'.format(e))
|
|
271
|
+
|
|
272
|
+
# return the equipment object and the zone identifier for the equip object
|
|
273
|
+
obj_id = ep_strs[0].split('..')[0]
|
|
274
|
+
fuel = ep_strs[1] if ep_strs[1] != '' else 'None'
|
|
275
|
+
zone_id = ep_strs[2]
|
|
276
|
+
equipment = cls(obj_id, watts, sched, fuel, cat,
|
|
277
|
+
rad_fract, lat_fract, lost_fract)
|
|
278
|
+
return equipment, zone_id
|
|
279
|
+
|
|
280
|
+
@classmethod
|
|
281
|
+
def from_dict(cls, data):
|
|
282
|
+
"""Create a Process object from a dictionary.
|
|
283
|
+
|
|
284
|
+
Note that the dictionary must be a non-abridged version for this classmethod
|
|
285
|
+
to work.
|
|
286
|
+
|
|
287
|
+
Args:
|
|
288
|
+
data: A Process dictionary in following the format below.
|
|
289
|
+
|
|
290
|
+
.. code-block:: python
|
|
291
|
+
|
|
292
|
+
{
|
|
293
|
+
"type": 'Process',
|
|
294
|
+
"identifier": 'Wood_Burning_Fireplace_500_03',
|
|
295
|
+
"display_name": 'Hearth',
|
|
296
|
+
"watts": 500, # watts consumed by the process
|
|
297
|
+
"schedule": {}, # ScheduleRuleset/ScheduleFixedInterval dictionary
|
|
298
|
+
"fuel_type": 'OtherFuel1', # Text for the fuel type
|
|
299
|
+
"end_use_category": "Fireplaces", # Text for the end use category
|
|
300
|
+
"radiant_fraction": 0.4, # fraction of heat that is long wave radiant
|
|
301
|
+
"latent_fraction": 0, # fraction of heat that is latent
|
|
302
|
+
"lost_fraction": 0.5 # fraction of heat that is lost
|
|
303
|
+
}
|
|
304
|
+
"""
|
|
305
|
+
cat, rad_f, lat_f, lost_f = cls._extract_dict_props(data, 'Process')
|
|
306
|
+
sched = cls._get_schedule_from_dict(data['schedule'])
|
|
307
|
+
new_obj = cls(data['identifier'], data['watts'], sched, data['fuel_type'],
|
|
308
|
+
cat, rad_f, lat_f, lost_f)
|
|
309
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
310
|
+
new_obj.display_name = data['display_name']
|
|
311
|
+
if 'user_data' in data and data['user_data'] is not None:
|
|
312
|
+
new_obj.user_data = data['user_data']
|
|
313
|
+
if 'properties' in data and data['properties'] is not None:
|
|
314
|
+
new_obj.properties._load_extension_attr_from_dict(data['properties'])
|
|
315
|
+
return new_obj
|
|
316
|
+
|
|
317
|
+
@classmethod
|
|
318
|
+
def from_dict_abridged(cls, data, schedule_dict):
|
|
319
|
+
"""Create a Process object from an abridged dictionary.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
data: A ProcessAbridged dictionary in following the format below.
|
|
323
|
+
schedule_dict: A dictionary with schedule identifiers as keys and honeybee
|
|
324
|
+
schedule objects as values (either ScheduleRuleset or
|
|
325
|
+
ScheduleFixedInterval). These will be used to assign the schedules
|
|
326
|
+
to the equipment object.
|
|
327
|
+
|
|
328
|
+
.. code-block:: python
|
|
329
|
+
|
|
330
|
+
{
|
|
331
|
+
"type": 'ProcessAbridged',
|
|
332
|
+
"identifier": 'Wood_Burning_Fireplace_500_03',
|
|
333
|
+
"display_name": 'Hearth',
|
|
334
|
+
"watts": 500, # watts consumed by the process
|
|
335
|
+
"schedule": "Fireplace Usage Schedule", # Schedule identifier
|
|
336
|
+
"fuel_type": 'OtherFuel1', # Text for the fuel type
|
|
337
|
+
"end_use_category": "Fireplaces", # Text for the end use category
|
|
338
|
+
"radiant_fraction": 0.4, # fraction of heat that is long wave radiant
|
|
339
|
+
"latent_fraction": 0, # fraction of heat that is latent
|
|
340
|
+
"lost_fraction": 0.5 # fraction of heat that is lost
|
|
341
|
+
}
|
|
342
|
+
"""
|
|
343
|
+
cat, rad_f, lat_f, lost_f = cls._extract_dict_props(data, 'ProcessAbridged')
|
|
344
|
+
try:
|
|
345
|
+
sched = schedule_dict[data['schedule']]
|
|
346
|
+
except KeyError as e:
|
|
347
|
+
raise ValueError('Failed to find {} in the schedule_dict.'.format(e))
|
|
348
|
+
new_obj = cls(data['identifier'], data['watts'], sched, data['fuel_type'],
|
|
349
|
+
cat, rad_f, lat_f, lost_f)
|
|
350
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
351
|
+
new_obj.display_name = data['display_name']
|
|
352
|
+
if 'user_data' in data and data['user_data'] is not None:
|
|
353
|
+
new_obj.user_data = data['user_data']
|
|
354
|
+
if 'properties' in data and data['properties'] is not None:
|
|
355
|
+
new_obj.properties._load_extension_attr_from_dict(data['properties'])
|
|
356
|
+
return new_obj
|
|
357
|
+
|
|
358
|
+
def to_idf(self, zone_identifier):
|
|
359
|
+
"""IDF string representation of Process object.
|
|
360
|
+
|
|
361
|
+
Note that this method only outputs a single string for the Process
|
|
362
|
+
object and, to write everything needed to describe the object into an IDF,
|
|
363
|
+
this object's schedule must also be written.
|
|
364
|
+
|
|
365
|
+
Args:
|
|
366
|
+
zone_identifier: Text for the zone identifier that the Process
|
|
367
|
+
object is assigned to.
|
|
368
|
+
|
|
369
|
+
.. code-block:: shell
|
|
370
|
+
|
|
371
|
+
OtherEquipment,
|
|
372
|
+
BASE-1 OthEq 1, !- Name
|
|
373
|
+
Propane, !- Fuel Use Type
|
|
374
|
+
BASE-1, !- Zone or ZoneList or Space or SpaceList Name
|
|
375
|
+
ALWAYSON, !- SCHEDULE Name
|
|
376
|
+
EquipmentLevel, !- Design Level calculation method
|
|
377
|
+
6766., !- Design Level {W}
|
|
378
|
+
, !- Power per Zone Floor Area {watts/m2}
|
|
379
|
+
, !- Power per Person {watts/person}
|
|
380
|
+
0, !- Fraction Latent
|
|
381
|
+
0.3, !- Fraction Radiant
|
|
382
|
+
0, !- Fraction Lost
|
|
383
|
+
1.2E-7, !- Carbon Dioxide Generation Rate
|
|
384
|
+
SubCategory1; !- End-Use Subcategory
|
|
385
|
+
"""
|
|
386
|
+
_idf_comments = (
|
|
387
|
+
'name', 'fuel type', 'zone name', 'schedule name', 'level method',
|
|
388
|
+
'power level {W}', 'power per floor area {W/m2}',
|
|
389
|
+
'power per person {W/ppl}', 'latent fraction', 'radiant fraction',
|
|
390
|
+
'lost fraction', 'co2 generation {m3/s-W', 'end use subcategory'
|
|
391
|
+
)
|
|
392
|
+
_idf_values = (
|
|
393
|
+
'{}..{}'.format(self.identifier, zone_identifier), self.fuel_type,
|
|
394
|
+
zone_identifier, self.schedule.identifier, 'EquipmentLevel', self.watts,
|
|
395
|
+
'', '', self.latent_fraction, self.radiant_fraction, self.lost_fraction,
|
|
396
|
+
'', self.end_use_category
|
|
397
|
+
)
|
|
398
|
+
return generate_idf_string('OtherEquipment', _idf_values, _idf_comments)
|
|
399
|
+
|
|
400
|
+
def to_dict(self, abridged=False):
|
|
401
|
+
"""Process dictionary representation.
|
|
402
|
+
|
|
403
|
+
Args:
|
|
404
|
+
abridged: Boolean to note whether the full dictionary describing the
|
|
405
|
+
object should be returned (False) or just an abridged version (True),
|
|
406
|
+
which only specifies the identifiers of schedules. (Default: False).
|
|
407
|
+
"""
|
|
408
|
+
base = {'type': 'Process'} if not abridged else {'type': 'ProcessAbridged'}
|
|
409
|
+
base['identifier'] = self.identifier
|
|
410
|
+
base['watts'] = self.watts
|
|
411
|
+
base['schedule'] = self.schedule.to_dict() if not \
|
|
412
|
+
abridged else self.schedule.identifier
|
|
413
|
+
base['fuel_type'] = self.fuel_type
|
|
414
|
+
base['end_use_category'] = self.end_use_category
|
|
415
|
+
base['radiant_fraction'] = self.radiant_fraction
|
|
416
|
+
base['radiant_fraction'] = self.radiant_fraction
|
|
417
|
+
base['latent_fraction'] = self.latent_fraction
|
|
418
|
+
base['lost_fraction'] = self.lost_fraction
|
|
419
|
+
if self._display_name is not None:
|
|
420
|
+
base['display_name'] = self.display_name
|
|
421
|
+
if self._user_data is not None:
|
|
422
|
+
base['user_data'] = self.user_data
|
|
423
|
+
prop_dict = self.properties.to_dict()
|
|
424
|
+
if prop_dict is not None:
|
|
425
|
+
base['properties'] = prop_dict
|
|
426
|
+
return base
|
|
427
|
+
|
|
428
|
+
def _check_fractions(self):
|
|
429
|
+
tot = (self._radiant_fraction, self._latent_fraction, self._lost_fraction)
|
|
430
|
+
assert sum(tot) <= 1 + 1e-9, 'Sum of process radiant_fraction, ' \
|
|
431
|
+
'latent_fraction and lost_fraction ({}) is greater than 1.'.format(sum(tot))
|
|
432
|
+
|
|
433
|
+
@staticmethod
|
|
434
|
+
def _extract_dict_props(data, expected_type):
|
|
435
|
+
"""Extract relevant properties from an equipment dictionary."""
|
|
436
|
+
assert data['type'] == expected_type, \
|
|
437
|
+
'Expected {} dictionary. Got {}.'.format(expected_type, data['type'])
|
|
438
|
+
category = data['end_use_category'] if 'end_use_category' in data else 'Process'
|
|
439
|
+
rad_fract = data['radiant_fraction'] if 'radiant_fraction' in data else 0
|
|
440
|
+
lat_fract = data['latent_fraction'] if 'latent_fraction' in data else 0
|
|
441
|
+
lost_fract = data['lost_fraction'] if 'lost_fraction' in data else 0
|
|
442
|
+
return category, rad_fract, lat_fract, lost_fract
|
|
443
|
+
|
|
444
|
+
def __key(self):
|
|
445
|
+
"""A tuple based on the object properties, useful for hashing."""
|
|
446
|
+
return (self.identifier, self.watts, hash(self.schedule), self.fuel_type,
|
|
447
|
+
self.end_use_category, self.radiant_fraction, self.latent_fraction,
|
|
448
|
+
self.lost_fraction)
|
|
449
|
+
|
|
450
|
+
def __hash__(self):
|
|
451
|
+
return hash(self.__key())
|
|
452
|
+
|
|
453
|
+
def __eq__(self, other):
|
|
454
|
+
return isinstance(other, Process) and self.__key() == other.__key()
|
|
455
|
+
|
|
456
|
+
def __ne__(self, other):
|
|
457
|
+
return not self.__eq__(other)
|
|
458
|
+
|
|
459
|
+
def __copy__(self):
|
|
460
|
+
new_obj = Process(
|
|
461
|
+
self.identifier, self.watts, self.schedule, self.fuel_type,
|
|
462
|
+
self.end_use_category, self.radiant_fraction, self.latent_fraction,
|
|
463
|
+
self.lost_fraction)
|
|
464
|
+
new_obj._display_name = self._display_name
|
|
465
|
+
new_obj._user_data = None if self._user_data is None else self._user_data.copy()
|
|
466
|
+
new_obj._properties._duplicate_extension_attr(self._properties)
|
|
467
|
+
return new_obj
|
|
468
|
+
|
|
469
|
+
def __repr__(self):
|
|
470
|
+
return 'Process: {} [{} W] [schedule: {}] [fuel: {}]'.format(
|
|
471
|
+
self.display_name, round(self.watts, 1), self.schedule.display_name,
|
|
472
|
+
self.fuel_type)
|