honeybee-energy 1.116.106__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- honeybee_energy/__init__.py +24 -0
- honeybee_energy/__main__.py +4 -0
- honeybee_energy/_extend_honeybee.py +145 -0
- honeybee_energy/altnumber.py +21 -0
- honeybee_energy/baseline/__init__.py +2 -0
- honeybee_energy/baseline/create.py +608 -0
- honeybee_energy/baseline/data/__init__.py +1 -0
- honeybee_energy/baseline/data/constructions.csv +64 -0
- honeybee_energy/baseline/data/fen_ratios.csv +15 -0
- honeybee_energy/baseline/data/lpd_building.csv +21 -0
- honeybee_energy/baseline/data/pci_2016.csv +22 -0
- honeybee_energy/baseline/data/pci_2019.csv +22 -0
- honeybee_energy/baseline/data/pci_2022.csv +22 -0
- honeybee_energy/baseline/data/shw.csv +21 -0
- honeybee_energy/baseline/pci.py +512 -0
- honeybee_energy/baseline/result.py +371 -0
- honeybee_energy/boundarycondition.py +128 -0
- honeybee_energy/cli/__init__.py +69 -0
- honeybee_energy/cli/baseline.py +475 -0
- honeybee_energy/cli/edit.py +327 -0
- honeybee_energy/cli/lib.py +1154 -0
- honeybee_energy/cli/result.py +810 -0
- honeybee_energy/cli/setconfig.py +124 -0
- honeybee_energy/cli/settings.py +569 -0
- honeybee_energy/cli/simulate.py +380 -0
- honeybee_energy/cli/translate.py +1714 -0
- honeybee_energy/cli/validate.py +224 -0
- honeybee_energy/config.json +11 -0
- honeybee_energy/config.py +842 -0
- honeybee_energy/construction/__init__.py +1 -0
- honeybee_energy/construction/_base.py +374 -0
- honeybee_energy/construction/air.py +325 -0
- honeybee_energy/construction/dictutil.py +89 -0
- honeybee_energy/construction/dynamic.py +607 -0
- honeybee_energy/construction/opaque.py +460 -0
- honeybee_energy/construction/shade.py +319 -0
- honeybee_energy/construction/window.py +1096 -0
- honeybee_energy/construction/windowshade.py +847 -0
- honeybee_energy/constructionset.py +1655 -0
- honeybee_energy/dictutil.py +56 -0
- honeybee_energy/generator/__init__.py +5 -0
- honeybee_energy/generator/loadcenter.py +204 -0
- honeybee_energy/generator/pv.py +535 -0
- honeybee_energy/hvac/__init__.py +21 -0
- honeybee_energy/hvac/_base.py +124 -0
- honeybee_energy/hvac/_template.py +270 -0
- honeybee_energy/hvac/allair/__init__.py +22 -0
- honeybee_energy/hvac/allair/_base.py +349 -0
- honeybee_energy/hvac/allair/furnace.py +168 -0
- honeybee_energy/hvac/allair/psz.py +131 -0
- honeybee_energy/hvac/allair/ptac.py +163 -0
- honeybee_energy/hvac/allair/pvav.py +109 -0
- honeybee_energy/hvac/allair/vav.py +128 -0
- honeybee_energy/hvac/detailed.py +337 -0
- honeybee_energy/hvac/doas/__init__.py +28 -0
- honeybee_energy/hvac/doas/_base.py +345 -0
- honeybee_energy/hvac/doas/fcu.py +127 -0
- honeybee_energy/hvac/doas/radiant.py +329 -0
- honeybee_energy/hvac/doas/vrf.py +81 -0
- honeybee_energy/hvac/doas/wshp.py +91 -0
- honeybee_energy/hvac/heatcool/__init__.py +23 -0
- honeybee_energy/hvac/heatcool/_base.py +177 -0
- honeybee_energy/hvac/heatcool/baseboard.py +61 -0
- honeybee_energy/hvac/heatcool/evapcool.py +72 -0
- honeybee_energy/hvac/heatcool/fcu.py +92 -0
- honeybee_energy/hvac/heatcool/gasunit.py +53 -0
- honeybee_energy/hvac/heatcool/radiant.py +269 -0
- honeybee_energy/hvac/heatcool/residential.py +77 -0
- honeybee_energy/hvac/heatcool/vrf.py +54 -0
- honeybee_energy/hvac/heatcool/windowac.py +70 -0
- honeybee_energy/hvac/heatcool/wshp.py +62 -0
- honeybee_energy/hvac/idealair.py +699 -0
- honeybee_energy/internalmass.py +310 -0
- honeybee_energy/lib/__init__.py +1 -0
- honeybee_energy/lib/_loadconstructions.py +194 -0
- honeybee_energy/lib/_loadconstructionsets.py +117 -0
- honeybee_energy/lib/_loadmaterials.py +83 -0
- honeybee_energy/lib/_loadprogramtypes.py +125 -0
- honeybee_energy/lib/_loadschedules.py +87 -0
- honeybee_energy/lib/_loadtypelimits.py +64 -0
- honeybee_energy/lib/constructions.py +207 -0
- honeybee_energy/lib/constructionsets.py +95 -0
- honeybee_energy/lib/materials.py +67 -0
- honeybee_energy/lib/programtypes.py +125 -0
- honeybee_energy/lib/schedules.py +61 -0
- honeybee_energy/lib/scheduletypelimits.py +31 -0
- honeybee_energy/load/__init__.py +1 -0
- honeybee_energy/load/_base.py +190 -0
- honeybee_energy/load/daylight.py +397 -0
- honeybee_energy/load/dictutil.py +47 -0
- honeybee_energy/load/equipment.py +771 -0
- honeybee_energy/load/hotwater.py +543 -0
- honeybee_energy/load/infiltration.py +460 -0
- honeybee_energy/load/lighting.py +480 -0
- honeybee_energy/load/people.py +497 -0
- honeybee_energy/load/process.py +472 -0
- honeybee_energy/load/setpoint.py +816 -0
- honeybee_energy/load/ventilation.py +550 -0
- honeybee_energy/material/__init__.py +1 -0
- honeybee_energy/material/_base.py +166 -0
- honeybee_energy/material/dictutil.py +59 -0
- honeybee_energy/material/frame.py +367 -0
- honeybee_energy/material/gas.py +1087 -0
- honeybee_energy/material/glazing.py +854 -0
- honeybee_energy/material/opaque.py +1351 -0
- honeybee_energy/material/shade.py +1360 -0
- honeybee_energy/measure.py +472 -0
- honeybee_energy/programtype.py +723 -0
- honeybee_energy/properties/__init__.py +1 -0
- honeybee_energy/properties/aperture.py +333 -0
- honeybee_energy/properties/door.py +342 -0
- honeybee_energy/properties/extension.py +244 -0
- honeybee_energy/properties/face.py +274 -0
- honeybee_energy/properties/model.py +2640 -0
- honeybee_energy/properties/room.py +1747 -0
- honeybee_energy/properties/shade.py +314 -0
- honeybee_energy/properties/shademesh.py +262 -0
- honeybee_energy/reader.py +48 -0
- honeybee_energy/result/__init__.py +1 -0
- honeybee_energy/result/colorobj.py +648 -0
- honeybee_energy/result/emissions.py +290 -0
- honeybee_energy/result/err.py +101 -0
- honeybee_energy/result/eui.py +100 -0
- honeybee_energy/result/generation.py +160 -0
- honeybee_energy/result/loadbalance.py +890 -0
- honeybee_energy/result/match.py +202 -0
- honeybee_energy/result/osw.py +90 -0
- honeybee_energy/result/rdd.py +59 -0
- honeybee_energy/result/zsz.py +190 -0
- honeybee_energy/run.py +1577 -0
- honeybee_energy/schedule/__init__.py +1 -0
- honeybee_energy/schedule/day.py +626 -0
- honeybee_energy/schedule/dictutil.py +59 -0
- honeybee_energy/schedule/fixedinterval.py +1012 -0
- honeybee_energy/schedule/rule.py +619 -0
- honeybee_energy/schedule/ruleset.py +1867 -0
- honeybee_energy/schedule/typelimit.py +310 -0
- honeybee_energy/shw.py +315 -0
- honeybee_energy/simulation/__init__.py +1 -0
- honeybee_energy/simulation/control.py +214 -0
- honeybee_energy/simulation/daylightsaving.py +185 -0
- honeybee_energy/simulation/dictutil.py +51 -0
- honeybee_energy/simulation/output.py +646 -0
- honeybee_energy/simulation/parameter.py +606 -0
- honeybee_energy/simulation/runperiod.py +443 -0
- honeybee_energy/simulation/shadowcalculation.py +295 -0
- honeybee_energy/simulation/sizing.py +546 -0
- honeybee_energy/ventcool/__init__.py +5 -0
- honeybee_energy/ventcool/_crack_data.py +91 -0
- honeybee_energy/ventcool/afn.py +289 -0
- honeybee_energy/ventcool/control.py +269 -0
- honeybee_energy/ventcool/crack.py +126 -0
- honeybee_energy/ventcool/fan.py +493 -0
- honeybee_energy/ventcool/opening.py +365 -0
- honeybee_energy/ventcool/simulation.py +314 -0
- honeybee_energy/writer.py +1078 -0
- honeybee_energy-1.116.106.dist-info/METADATA +113 -0
- honeybee_energy-1.116.106.dist-info/RECORD +162 -0
- honeybee_energy-1.116.106.dist-info/WHEEL +5 -0
- honeybee_energy-1.116.106.dist-info/entry_points.txt +2 -0
- honeybee_energy-1.116.106.dist-info/licenses/LICENSE +661 -0
- honeybee_energy-1.116.106.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Room internal mass, including construction and surface area."""
|
|
3
|
+
from __future__ import division
|
|
4
|
+
|
|
5
|
+
from honeybee._lockable import lockable
|
|
6
|
+
from honeybee.typing import valid_ep_string, float_positive
|
|
7
|
+
from honeybee.units import conversion_factor_to_meters
|
|
8
|
+
|
|
9
|
+
from .construction.opaque import OpaqueConstruction
|
|
10
|
+
from .material.opaque import EnergyMaterialVegetation
|
|
11
|
+
from .reader import parse_idf_string
|
|
12
|
+
from .writer import generate_idf_string
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@lockable
|
|
16
|
+
class InternalMass(object):
|
|
17
|
+
"""Room internal mass, including construction and surface area.
|
|
18
|
+
|
|
19
|
+
Note that internal masses assigned this way cannot "see" solar radiation that
|
|
20
|
+
may potentially hit them and, as such, caution should be taken when using this
|
|
21
|
+
component with internal mass objects that are not always in shade. Masses are
|
|
22
|
+
factored into the the thermal calculations of the Room by undergoing heat
|
|
23
|
+
transfer with the indoor air.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
identifier: Text string for a unique InternalMass 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
|
+
construction: An OpaqueConstruction object that represents the material
|
|
30
|
+
that the internal thermal mass is composed of.
|
|
31
|
+
area: A number representing the surface area of the internal mass that
|
|
32
|
+
is exposed to the Room air. This value should always be in square
|
|
33
|
+
meters regardless of what units system the parent model is a part of.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
Properties:
|
|
37
|
+
* identifier
|
|
38
|
+
* display_name
|
|
39
|
+
* construction
|
|
40
|
+
* area
|
|
41
|
+
* user_data
|
|
42
|
+
"""
|
|
43
|
+
__slots__ = ('_identifier', '_display_name', '_construction', '_area',
|
|
44
|
+
'_locked', '_user_data')
|
|
45
|
+
|
|
46
|
+
def __init__(self, identifier, construction, area):
|
|
47
|
+
self._locked = False # unlocked by default
|
|
48
|
+
self.identifier = identifier
|
|
49
|
+
self._display_name = None
|
|
50
|
+
self.construction = construction
|
|
51
|
+
self.area = area
|
|
52
|
+
self._user_data = None
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def identifier(self):
|
|
56
|
+
"""Get or set the text string for object identifier."""
|
|
57
|
+
return self._identifier
|
|
58
|
+
|
|
59
|
+
@identifier.setter
|
|
60
|
+
def identifier(self, identifier):
|
|
61
|
+
self._identifier = valid_ep_string(identifier)
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def display_name(self):
|
|
65
|
+
"""Get or set a string for the object name without any character restrictions.
|
|
66
|
+
|
|
67
|
+
If not set, this will be equal to the identifier.
|
|
68
|
+
"""
|
|
69
|
+
if self._display_name is None:
|
|
70
|
+
return self._identifier
|
|
71
|
+
return self._display_name
|
|
72
|
+
|
|
73
|
+
@display_name.setter
|
|
74
|
+
def display_name(self, value):
|
|
75
|
+
if value is not None:
|
|
76
|
+
try:
|
|
77
|
+
value = str(value)
|
|
78
|
+
except UnicodeEncodeError: # Python 2 machine lacking the character set
|
|
79
|
+
pass # keep it as unicode
|
|
80
|
+
self._display_name = value
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def construction(self):
|
|
84
|
+
"""Get or set a Construction for the material the internal mass is composed of.
|
|
85
|
+
"""
|
|
86
|
+
return self._construction
|
|
87
|
+
|
|
88
|
+
@construction.setter
|
|
89
|
+
def construction(self, value):
|
|
90
|
+
assert isinstance(value, OpaqueConstruction), \
|
|
91
|
+
'Expected Opaque Construction for InternalMass. Got {}'.format(type(value))
|
|
92
|
+
assert not isinstance(value.materials[0], EnergyMaterialVegetation), \
|
|
93
|
+
'InternalMass constructions cannot contain vegetation materials'
|
|
94
|
+
value.lock() # lock editing in case construction has multiple references
|
|
95
|
+
self._construction = value
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def area(self):
|
|
99
|
+
"""Get or set a number for the surface area of the mass exposed to the Room air.
|
|
100
|
+
"""
|
|
101
|
+
return self._area
|
|
102
|
+
|
|
103
|
+
@area.setter
|
|
104
|
+
def area(self, value):
|
|
105
|
+
self._area = float_positive(value, 'internal mass area')
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def user_data(self):
|
|
109
|
+
"""Get or set an optional dictionary for additional meta data for this object.
|
|
110
|
+
|
|
111
|
+
This will be None until it has been set. All keys and values of this
|
|
112
|
+
dictionary should be of a standard Python type to ensure correct
|
|
113
|
+
serialization of the object to/from JSON (eg. str, float, int, list, dict)
|
|
114
|
+
"""
|
|
115
|
+
if self._user_data is not None:
|
|
116
|
+
return self._user_data
|
|
117
|
+
|
|
118
|
+
@user_data.setter
|
|
119
|
+
def user_data(self, value):
|
|
120
|
+
if value is not None:
|
|
121
|
+
assert isinstance(value, dict), 'Expected dictionary for honeybee_energy' \
|
|
122
|
+
'object user_data. Got {}.'.format(type(value))
|
|
123
|
+
self._user_data = value
|
|
124
|
+
|
|
125
|
+
@classmethod
|
|
126
|
+
def from_geometry(cls, identifier, construction, geometry, units='Meters'):
|
|
127
|
+
"""Create an InternalMass object from a list of geometries.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
identifier: Text string for a unique InternalMass ID. Must be < 100
|
|
131
|
+
characters and not contain any EnergyPlus special characters. This
|
|
132
|
+
will be used to identify the object across a model and in the
|
|
133
|
+
exported IDF.
|
|
134
|
+
construction: An OpaqueConstruction object that represents the material
|
|
135
|
+
that the internal thermal mass is composed of.
|
|
136
|
+
geometry: An array of Face3D representing the exposed surface of the
|
|
137
|
+
internal mass. Note that these Face3D are assumed to be one-sided
|
|
138
|
+
so, if they are meant to represent a 2-sided object, the Face3D
|
|
139
|
+
should be duplicated and offset.
|
|
140
|
+
units: Text for the units system of the geometry. Choose from the following:
|
|
141
|
+
|
|
142
|
+
* Meters
|
|
143
|
+
* Millimeters
|
|
144
|
+
* Feet
|
|
145
|
+
* Inches
|
|
146
|
+
* Centimeters
|
|
147
|
+
"""
|
|
148
|
+
area = sum(geo.area for geo in geometry) * conversion_factor_to_meters(units)
|
|
149
|
+
return cls(identifier, construction, area)
|
|
150
|
+
|
|
151
|
+
@classmethod
|
|
152
|
+
def from_idf(cls, idf_string, construction_dict):
|
|
153
|
+
"""Create an InternalMass object from an EnergyPlus IDF text string.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
idf_string: A text string fully describing an EnergyPlus InternalMass
|
|
157
|
+
definition.
|
|
158
|
+
construction_dict: A dictionary with construction identifiers as keys
|
|
159
|
+
and honeybee construction objects as values. This will be used
|
|
160
|
+
to assign the construction to the InternalMass object.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
An InternalMass object loaded from the idf_string.
|
|
164
|
+
"""
|
|
165
|
+
ep_strs = parse_idf_string(idf_string, 'InternalMass,')
|
|
166
|
+
obj_id = ep_strs[0].split('..')[0]
|
|
167
|
+
return cls(obj_id, construction_dict[ep_strs[1]], ep_strs[4])
|
|
168
|
+
|
|
169
|
+
@classmethod
|
|
170
|
+
def from_dict(cls, data):
|
|
171
|
+
"""Create an InternalMass object from a dictionary.
|
|
172
|
+
|
|
173
|
+
Note that the dictionary must be a non-abridged version for this
|
|
174
|
+
classmethod to work.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
data: An InternalMass dictionary in following the format below.
|
|
178
|
+
|
|
179
|
+
.. code-block:: python
|
|
180
|
+
|
|
181
|
+
{
|
|
182
|
+
"type": 'InternalMass',
|
|
183
|
+
"identifier": 'Kitchen_Table_Wood_050',
|
|
184
|
+
"display_name": 'Kitchen Table',
|
|
185
|
+
"construction": {}, # OpaqueConstruction definition
|
|
186
|
+
"area": 5 # surface area of internal mass in square meters
|
|
187
|
+
}
|
|
188
|
+
"""
|
|
189
|
+
assert data['type'] == 'InternalMass', \
|
|
190
|
+
'Expected InternalMass dictionary. Got {}.'.format(data['type'])
|
|
191
|
+
constr = OpaqueConstruction.from_dict(data['construction'])
|
|
192
|
+
new_obj = cls(data['identifier'], constr, data['area'])
|
|
193
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
194
|
+
new_obj.display_name = data['display_name']
|
|
195
|
+
if 'user_data' in data and data['user_data'] is not None:
|
|
196
|
+
new_obj.user_data = data['user_data']
|
|
197
|
+
return new_obj
|
|
198
|
+
|
|
199
|
+
@classmethod
|
|
200
|
+
def from_dict_abridged(cls, data, construction_dict):
|
|
201
|
+
"""Create a InternalMass from an abridged dictionary.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
data: An InternalMassAbridged dictionary.
|
|
205
|
+
construction_dict: A dictionary with construction identifiers as keys
|
|
206
|
+
and honeybee construction objects as values. This will be used
|
|
207
|
+
to assign the construction to the InternalMass object.
|
|
208
|
+
|
|
209
|
+
.. code-block:: python
|
|
210
|
+
|
|
211
|
+
{
|
|
212
|
+
"type": 'InternalMassAbridged',
|
|
213
|
+
"identifier": 'Kitchen_Table_Wood_050',
|
|
214
|
+
"display_name": 'Kitchen Table',
|
|
215
|
+
"construction": 'Hardwood_050' # OpaqueConstruction identifier
|
|
216
|
+
"area": 5 # surface area of internal mass in square meters
|
|
217
|
+
}
|
|
218
|
+
"""
|
|
219
|
+
assert data['type'] == 'InternalMassAbridged', \
|
|
220
|
+
'Expected InternalMassAbridged dictionary. Got {}.'.format(data['type'])
|
|
221
|
+
new_obj = cls(
|
|
222
|
+
data['identifier'], construction_dict[data['construction']], data['area'])
|
|
223
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
224
|
+
new_obj.display_name = data['display_name']
|
|
225
|
+
if 'user_data' in data and data['user_data'] is not None:
|
|
226
|
+
new_obj.user_data = data['user_data']
|
|
227
|
+
return new_obj
|
|
228
|
+
|
|
229
|
+
def to_idf(self, room_identifier, is_zone=True):
|
|
230
|
+
"""IDF string representation of InternalMass object.
|
|
231
|
+
|
|
232
|
+
Note that this method only outputs a single string for the InternalMass
|
|
233
|
+
object and, to write everything needed to describe the object into an IDF,
|
|
234
|
+
this object's construction must also be written.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
room_identifier: Text for the Room identifier that the InternalMass
|
|
238
|
+
object is assigned to.
|
|
239
|
+
is_zone: Boolean for whether the room_identifier refers to a Zone
|
|
240
|
+
object or a Space object. (Default: True).
|
|
241
|
+
|
|
242
|
+
.. code-block:: shell
|
|
243
|
+
|
|
244
|
+
InternalMass,
|
|
245
|
+
Zn002:IntM001, !- Surface Name
|
|
246
|
+
INTERIOR, !- Construction Name
|
|
247
|
+
DORM ROOMS AND COMMON AREAS, !- Zone or ZoneList Name
|
|
248
|
+
, !- Space or SpaceList Name
|
|
249
|
+
408.7734; !- Total area exposed to Zone {m2}
|
|
250
|
+
"""
|
|
251
|
+
int_m_id = '{}..{}'.format(self.identifier, room_identifier)
|
|
252
|
+
values = [int_m_id, self.construction.identifier]
|
|
253
|
+
if is_zone:
|
|
254
|
+
values.extend([room_identifier, '', self.area])
|
|
255
|
+
else:
|
|
256
|
+
values.extend(['', room_identifier, self.area])
|
|
257
|
+
comments = ('name', 'construction name', 'zone name', 'space name',
|
|
258
|
+
'surface area')
|
|
259
|
+
return generate_idf_string('InternalMass', values, comments)
|
|
260
|
+
|
|
261
|
+
def to_dict(self, abridged=False):
|
|
262
|
+
"""InternalMass dictionary representation.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
abridged: Boolean to note whether the full dictionary describing the
|
|
266
|
+
object should be returned (False) or just an abridged version
|
|
267
|
+
(True), which only specifies the identifiers of the
|
|
268
|
+
construction. (Default: False).
|
|
269
|
+
"""
|
|
270
|
+
base = {'type': 'InternalMass'} if not abridged \
|
|
271
|
+
else {'type': 'InternalMassAbridged'}
|
|
272
|
+
base['identifier'] = self.identifier
|
|
273
|
+
base['construction'] = self.construction.to_dict() if not \
|
|
274
|
+
abridged else self.construction.identifier
|
|
275
|
+
base['area'] = self.area
|
|
276
|
+
if self._display_name is not None:
|
|
277
|
+
base['display_name'] = self.display_name
|
|
278
|
+
if self._user_data is not None:
|
|
279
|
+
base['user_data'] = self.user_data
|
|
280
|
+
return base
|
|
281
|
+
|
|
282
|
+
def duplicate(self):
|
|
283
|
+
"""Get a copy of this object."""
|
|
284
|
+
return self.__copy__()
|
|
285
|
+
|
|
286
|
+
def __copy__(self):
|
|
287
|
+
new_obj = InternalMass(self.identifier, self.construction, self.area)
|
|
288
|
+
new_obj._display_name = self._display_name
|
|
289
|
+
new_obj._user_data = None if self._user_data is None else self._user_data.copy()
|
|
290
|
+
return new_obj
|
|
291
|
+
|
|
292
|
+
def __key(self):
|
|
293
|
+
"""A tuple based on the object properties, useful for hashing."""
|
|
294
|
+
return (self.identifier, hash(self.construction), self.area)
|
|
295
|
+
|
|
296
|
+
def __hash__(self):
|
|
297
|
+
return hash(self.__key())
|
|
298
|
+
|
|
299
|
+
def __eq__(self, other):
|
|
300
|
+
return isinstance(other, InternalMass) and self.__key() == other.__key()
|
|
301
|
+
|
|
302
|
+
def __ne__(self, other):
|
|
303
|
+
return not self.__eq__(other)
|
|
304
|
+
|
|
305
|
+
def ToString(self):
|
|
306
|
+
"""Overwrite .NET ToString."""
|
|
307
|
+
return self.__repr__()
|
|
308
|
+
|
|
309
|
+
def __repr__(self):
|
|
310
|
+
return 'InternalMass: {}'.format(self.display_name)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Library of schedules, constructions, and other template objects."""
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""Load all materials and constructions from the IDF libraries."""
|
|
2
|
+
from honeybee_energy.config import folders
|
|
3
|
+
from honeybee_energy.construction.opaque import OpaqueConstruction
|
|
4
|
+
from honeybee_energy.construction.window import WindowConstruction
|
|
5
|
+
from honeybee_energy.construction.windowshade import WindowConstructionShade
|
|
6
|
+
from honeybee_energy.construction.dynamic import WindowConstructionDynamic
|
|
7
|
+
from honeybee_energy.construction.air import AirBoundaryConstruction
|
|
8
|
+
from honeybee_energy.construction.dictutil import dict_abridged_to_construction, \
|
|
9
|
+
dict_to_construction
|
|
10
|
+
|
|
11
|
+
from ._loadmaterials import _opaque_materials, _window_materials, _default_mats
|
|
12
|
+
from ._loadschedules import _schedules
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
import json
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# dictionary of all materials loaded from JSON
|
|
19
|
+
_all_materials = _opaque_materials.copy() # start with opaque materials
|
|
20
|
+
_all_materials.update(_window_materials) # add window constructions
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# empty dictionaries to hold idf-loaded materials and constructions
|
|
24
|
+
_opaque_constructions = {}
|
|
25
|
+
_window_constructions = {}
|
|
26
|
+
_shade_constructions = {}
|
|
27
|
+
|
|
28
|
+
# groups useful for construction classification
|
|
29
|
+
_opa_types = (OpaqueConstruction, AirBoundaryConstruction)
|
|
30
|
+
_win_types = (WindowConstruction, WindowConstructionShade, WindowConstructionDynamic)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# first load the honeybee defaults
|
|
34
|
+
with open(folders.defaults_file) as json_file:
|
|
35
|
+
default_data = json.load(json_file)['constructions']
|
|
36
|
+
for con_dict in default_data:
|
|
37
|
+
constr = dict_abridged_to_construction(con_dict, _all_materials, _schedules, False)
|
|
38
|
+
constr.lock()
|
|
39
|
+
if isinstance(constr, _opa_types):
|
|
40
|
+
_opaque_constructions[con_dict['identifier']] = constr
|
|
41
|
+
elif isinstance(constr, _win_types):
|
|
42
|
+
_window_constructions[con_dict['identifier']] = constr
|
|
43
|
+
else: # it's a shade construction
|
|
44
|
+
_shade_constructions[con_dict['identifier']] = constr
|
|
45
|
+
_default_constrs = set(
|
|
46
|
+
list(_opaque_constructions.keys()) + list(_window_constructions.keys()) +
|
|
47
|
+
list(_shade_constructions.keys()))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# then load honeybee extension data into a dictionary but don't make the objects yet
|
|
51
|
+
_opaque_constr_standards_dict = {}
|
|
52
|
+
_window_constr_standards_dict = {}
|
|
53
|
+
_shade_constr_standards_dict = {}
|
|
54
|
+
|
|
55
|
+
for ext_folder in folders.standards_extension_folders:
|
|
56
|
+
_data_dir = os.path.join(ext_folder, 'constructions')
|
|
57
|
+
_opaque_dir = os.path.join(_data_dir, 'opaque_construction.json')
|
|
58
|
+
if os.path.isfile(_opaque_dir):
|
|
59
|
+
with open(_opaque_dir, 'r') as f:
|
|
60
|
+
_opaque_constr_standards_dict.update(json.load(f))
|
|
61
|
+
_window_dir = os.path.join(_data_dir, 'window_construction.json')
|
|
62
|
+
if os.path.isfile(_window_dir):
|
|
63
|
+
with open(_window_dir, 'r') as f:
|
|
64
|
+
_window_constr_standards_dict.update(json.load(f))
|
|
65
|
+
_shade_dir = os.path.join(_data_dir, 'shade_construction.json')
|
|
66
|
+
if os.path.isfile(_shade_dir):
|
|
67
|
+
with open(_shade_dir, 'r') as f:
|
|
68
|
+
_shade_constr_standards_dict.update(json.load(f))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# then load materials and constructions from the user-supplied files
|
|
72
|
+
def lock_and_check_material(mat):
|
|
73
|
+
"""Lock a material and check that it's not overwriting a default."""
|
|
74
|
+
mat.lock()
|
|
75
|
+
assert mat.identifier not in _default_mats, 'Cannot overwrite ' \
|
|
76
|
+
'default material "{}".'.format(mat.identifier)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def lock_and_check_construction(constr):
|
|
80
|
+
"""Lock a construction and check that it's not overwriting a default."""
|
|
81
|
+
constr.lock()
|
|
82
|
+
assert constr.identifier not in _default_constrs, 'Cannot overwrite ' \
|
|
83
|
+
'default construction "{}".'.format(constr.identifier)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def load_construction_object(
|
|
87
|
+
con_dict, load_mats, load_sch, opaque_cons, window_cons, shade_cons,
|
|
88
|
+
misc_mats, misc_sch):
|
|
89
|
+
"""Load a construction object from a dictionary and add it to the library dict."""
|
|
90
|
+
try:
|
|
91
|
+
constr = dict_abridged_to_construction(con_dict, load_mats, load_sch, False)
|
|
92
|
+
if constr is None:
|
|
93
|
+
constr = dict_to_construction(con_dict, False)
|
|
94
|
+
try:
|
|
95
|
+
misc_mats.extend(constr.materials)
|
|
96
|
+
if constr.has_frame:
|
|
97
|
+
misc_mats.append(constr.frame)
|
|
98
|
+
if constr.has_shade:
|
|
99
|
+
if constr.is_switchable_glazing:
|
|
100
|
+
misc_mats.append(constr.switched_glass_material)
|
|
101
|
+
except AttributeError: # construction without materials
|
|
102
|
+
pass
|
|
103
|
+
if isinstance(constr, (WindowConstructionShade, WindowConstructionDynamic)):
|
|
104
|
+
if constr.schedule is not None:
|
|
105
|
+
misc_sch.append(constr.schedule)
|
|
106
|
+
elif isinstance(constr, AirBoundaryConstruction):
|
|
107
|
+
if constr.air_mixing_schedule is not None:
|
|
108
|
+
misc_sch.append(constr.air_mixing_schedule)
|
|
109
|
+
if constr is not None:
|
|
110
|
+
lock_and_check_construction(constr)
|
|
111
|
+
if isinstance(constr, _opa_types):
|
|
112
|
+
opaque_cons[con_dict['identifier']] = constr
|
|
113
|
+
elif isinstance(constr, _win_types):
|
|
114
|
+
window_cons[con_dict['identifier']] = constr
|
|
115
|
+
else: # it's a shade construction
|
|
116
|
+
shade_cons[con_dict['identifier']] = constr
|
|
117
|
+
except (TypeError, KeyError, ValueError):
|
|
118
|
+
try: # see if the construction set is built with constructions in standards
|
|
119
|
+
import honeybee_energy.lib.materials as _m
|
|
120
|
+
if 'materials' in con_dict:
|
|
121
|
+
if con_dict['type'] == 'OpaqueConstructionAbridged':
|
|
122
|
+
for mat in con_dict['materials']:
|
|
123
|
+
load_mats[mat] = _m.opaque_material_by_identifier(mat)
|
|
124
|
+
constr = dict_abridged_to_construction(
|
|
125
|
+
con_dict, load_mats, load_sch, False)
|
|
126
|
+
opaque_cons[con_dict['identifier']] = constr
|
|
127
|
+
elif con_dict['type'] == 'WindowConstructionAbridged':
|
|
128
|
+
for mat in con_dict['materials']:
|
|
129
|
+
load_mats[mat] = _m.window_material_by_identifier(mat)
|
|
130
|
+
constr = dict_abridged_to_construction(
|
|
131
|
+
con_dict, load_mats, load_sch, False)
|
|
132
|
+
window_cons[con_dict['identifier']] = constr
|
|
133
|
+
except Exception:
|
|
134
|
+
pass # not a Honeybee Construction JSON; possibly a comment
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def load_constructions_from_folder(
|
|
138
|
+
construction_lib_folder, loaded_materials, loaded_schedules):
|
|
139
|
+
"""Load all of the construction objects from a construction standards folder.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
construction_lib_folder: Path to a constructions sub-folder within a
|
|
143
|
+
honeybee standards folder.
|
|
144
|
+
loaded_materials: A dictionary of materials that have already been loaded
|
|
145
|
+
from the library.
|
|
146
|
+
loaded_schedules: A dictionary of materials that have already been loaded
|
|
147
|
+
from the library.
|
|
148
|
+
"""
|
|
149
|
+
opaque_mats, window_mats = {}, {}
|
|
150
|
+
opaque_cons, window_cons, shade_cons = {}, {}, {}
|
|
151
|
+
misc_mats, misc_sch = [], []
|
|
152
|
+
for f in os.listdir(construction_lib_folder):
|
|
153
|
+
f_path = os.path.join(construction_lib_folder, f)
|
|
154
|
+
if os.path.isfile(f_path):
|
|
155
|
+
if f_path.endswith('.idf'):
|
|
156
|
+
constructions, materials = \
|
|
157
|
+
OpaqueConstruction.extract_all_from_idf_file(f_path)
|
|
158
|
+
for mat in materials:
|
|
159
|
+
lock_and_check_material(mat)
|
|
160
|
+
opaque_mats[mat.identifier] = mat
|
|
161
|
+
for cnstr in constructions:
|
|
162
|
+
lock_and_check_construction(cnstr)
|
|
163
|
+
opaque_cons[cnstr.identifier] = cnstr
|
|
164
|
+
constructions, materials = \
|
|
165
|
+
WindowConstruction.extract_all_from_idf_file(f_path)
|
|
166
|
+
for mat in materials:
|
|
167
|
+
lock_and_check_material(mat)
|
|
168
|
+
window_mats[mat.identifier] = mat
|
|
169
|
+
for cnstr in constructions:
|
|
170
|
+
lock_and_check_construction(cnstr)
|
|
171
|
+
window_cons[cnstr.identifier] = cnstr
|
|
172
|
+
if f_path.endswith('.json'):
|
|
173
|
+
with open(f_path) as json_file:
|
|
174
|
+
data = json.load(json_file)
|
|
175
|
+
if 'type' in data: # single object
|
|
176
|
+
load_construction_object(
|
|
177
|
+
data, loaded_materials, loaded_schedules,
|
|
178
|
+
opaque_cons, window_cons, shade_cons, misc_mats, misc_sch)
|
|
179
|
+
else: # a collection of several objects
|
|
180
|
+
for constr_identifier in data:
|
|
181
|
+
load_construction_object(
|
|
182
|
+
data[constr_identifier], loaded_materials, loaded_schedules,
|
|
183
|
+
opaque_cons, window_cons, shade_cons, misc_mats, misc_sch)
|
|
184
|
+
return opaque_cons, window_cons, shade_cons, opaque_mats, window_mats, \
|
|
185
|
+
misc_mats, misc_sch
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
opaque_c, window_c, shade_c, opaque_m, window_m, misc_m, misc_s = \
|
|
189
|
+
load_constructions_from_folder(folders.construction_lib, _all_materials, _schedules)
|
|
190
|
+
_opaque_materials.update(opaque_m)
|
|
191
|
+
_window_materials.update(window_m)
|
|
192
|
+
_opaque_constructions.update(opaque_c)
|
|
193
|
+
_window_constructions.update(window_c)
|
|
194
|
+
_shade_constructions.update(shade_c)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Load all construction sets from the JSON libraries."""
|
|
2
|
+
from honeybee_energy.config import folders
|
|
3
|
+
from honeybee_energy.constructionset import ConstructionSet
|
|
4
|
+
|
|
5
|
+
from ._loadconstructions import _opaque_constructions, _window_constructions, \
|
|
6
|
+
_shade_constructions
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import json
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# make a dictionary of all constructions loaded from JSON
|
|
13
|
+
_all_constructions = _opaque_constructions.copy() # start with opaque constructions
|
|
14
|
+
_all_constructions.update(_window_constructions) # add window constructions
|
|
15
|
+
_all_constructions.update(_shade_constructions) # add shade constructions
|
|
16
|
+
|
|
17
|
+
# empty dictionary to hold loaded construction sets
|
|
18
|
+
_construction_sets = {}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# first load the honeybee defaults
|
|
22
|
+
with open(folders.defaults_file) as json_file:
|
|
23
|
+
default_data = json.load(json_file)['construction_sets']
|
|
24
|
+
for cset_dict in default_data:
|
|
25
|
+
constructionset = ConstructionSet.from_dict_abridged(cset_dict, _all_constructions)
|
|
26
|
+
constructionset.lock()
|
|
27
|
+
_construction_sets[cset_dict['identifier']] = constructionset
|
|
28
|
+
_default_sets = set(list(_construction_sets.keys()))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# then load honeybee extension data into a dictionary but don't make the objects yet
|
|
32
|
+
_construction_set_standards_dict = {}
|
|
33
|
+
|
|
34
|
+
for ext_folder in folders.standards_extension_folders:
|
|
35
|
+
_data_dir = os.path.join(ext_folder, 'constructionsets')
|
|
36
|
+
for _c_set_json in os.listdir(_data_dir):
|
|
37
|
+
if _c_set_json.endswith('.json'):
|
|
38
|
+
_c_set_dir = os.path.join(_data_dir, _c_set_json)
|
|
39
|
+
with open(_c_set_dir, 'r') as f:
|
|
40
|
+
_construction_set_standards_dict.update(json.load(f))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# then load construction sets from the user-supplied files
|
|
44
|
+
def load_construction_set_object(cset_dict, load_cons, con_sets, misc_cons):
|
|
45
|
+
"""Load a construction set object from a dictionary and add it to the lib dict."""
|
|
46
|
+
try:
|
|
47
|
+
if cset_dict['type'] == 'ConstructionSetAbridged':
|
|
48
|
+
cset = ConstructionSet.from_dict_abridged(cset_dict, load_cons)
|
|
49
|
+
else:
|
|
50
|
+
cset = ConstructionSet.from_dict(cset_dict)
|
|
51
|
+
misc_cons.extend(cset.modified_constructions)
|
|
52
|
+
cset.lock()
|
|
53
|
+
assert cset_dict['identifier'] not in _default_sets, 'Cannot overwrite ' \
|
|
54
|
+
'default construction set "{}".'.format(cset_dict['identifier'])
|
|
55
|
+
con_sets[cset_dict['identifier']] = cset
|
|
56
|
+
except Exception:
|
|
57
|
+
try: # see if the construction set is built with constructions in standards
|
|
58
|
+
import honeybee_energy.lib.constructions as _c
|
|
59
|
+
for key in cset_dict:
|
|
60
|
+
if isinstance(cset_dict[key], dict):
|
|
61
|
+
sub_dict = cset_dict[key]
|
|
62
|
+
for sub_key in sub_dict:
|
|
63
|
+
if sub_key == 'type' or sub_key in load_cons:
|
|
64
|
+
continue
|
|
65
|
+
if sub_dict[sub_key] is not None and \
|
|
66
|
+
sub_dict[sub_key] not in load_cons:
|
|
67
|
+
try:
|
|
68
|
+
load_cons[sub_dict[sub_key]] = \
|
|
69
|
+
_c.opaque_construction_by_identifier(
|
|
70
|
+
sub_dict[sub_key])
|
|
71
|
+
except ValueError:
|
|
72
|
+
load_cons[sub_dict[sub_key]] = \
|
|
73
|
+
_c.window_construction_by_identifier(
|
|
74
|
+
sub_dict[sub_key])
|
|
75
|
+
elif key == 'shade_construction' and cset_dict[key] is not None \
|
|
76
|
+
and cset_dict[key] not in load_cons:
|
|
77
|
+
load_cons[cset_dict[key]] = \
|
|
78
|
+
_c.shade_construction_by_identifier(cset_dict[key])
|
|
79
|
+
elif key == 'air_boundary_construction' \
|
|
80
|
+
and cset_dict[key] is not None \
|
|
81
|
+
and cset_dict[key] not in load_cons:
|
|
82
|
+
load_cons[cset_dict[key]] = \
|
|
83
|
+
_c.opaque_construction_by_identifier(cset_dict[key])
|
|
84
|
+
con_sets[cset_dict['identifier']] = \
|
|
85
|
+
ConstructionSet.from_dict_abridged(cset_dict, load_cons)
|
|
86
|
+
except Exception:
|
|
87
|
+
pass # not a Honeybee ConstructionSet JSON; possibly a comment
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def load_constructionsets_from_folder(constructionset_lib_folder, loaded_constructions):
|
|
91
|
+
"""Load all of the ConstructionSet objects from a constructionset standards folder.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
constructionset_lib_folder: Path to a constructionsets sub-folder within a
|
|
95
|
+
honeybee standards folder.
|
|
96
|
+
loaded_constructions: A dictionary of constructions that have already
|
|
97
|
+
been loaded from the library.
|
|
98
|
+
"""
|
|
99
|
+
con_sets, misc_cons = {}, []
|
|
100
|
+
for f in os.listdir(constructionset_lib_folder):
|
|
101
|
+
f_path = os.path.join(constructionset_lib_folder, f)
|
|
102
|
+
if os.path.isfile(f_path) and f_path.endswith('.json'):
|
|
103
|
+
with open(f_path, 'r') as json_file:
|
|
104
|
+
c_dict = json.load(json_file)
|
|
105
|
+
if 'type' in c_dict: # single object
|
|
106
|
+
load_construction_set_object(
|
|
107
|
+
c_dict, loaded_constructions, con_sets, misc_cons)
|
|
108
|
+
else: # a collection of several objects
|
|
109
|
+
for c_id in c_dict:
|
|
110
|
+
load_construction_set_object(
|
|
111
|
+
c_dict[c_id], loaded_constructions, con_sets, misc_cons)
|
|
112
|
+
return con_sets, misc_cons
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
loaded_sets, misc_c = \
|
|
116
|
+
load_constructionsets_from_folder(folders.constructionset_lib, _all_constructions)
|
|
117
|
+
_construction_sets.update(loaded_sets)
|