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,289 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Functions to generate an Airflow Network for a list of rooms."""
|
|
3
|
+
from __future__ import division
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
|
|
7
|
+
from .crack import AFNCrack
|
|
8
|
+
from .opening import VentilationOpening
|
|
9
|
+
from ._crack_data import CRACK_TEMPLATE_DATA
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _air_density_from_pressure(atmospheric_pressure=101325, air_temperature=20.0):
|
|
13
|
+
"""Calculate density of dry air using the ideal gas law from temperature and pressure.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
atmospheric_pressure: Atmospheric pressure in Pascals. (Default: 101325).
|
|
17
|
+
air_temperature: Air temperature in Celsius. (Default: 20.0).
|
|
18
|
+
Returns:
|
|
19
|
+
Air density at the given atmospheric pressure in kg/m3.
|
|
20
|
+
"""
|
|
21
|
+
r_specific = 287.058 # specific gas constant for dry air in J/kg/K
|
|
22
|
+
air_temperature += 273.15 # absolute temperature
|
|
23
|
+
return atmospheric_pressure / (r_specific * air_temperature)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _interior_afn(interior_face_groups, int_cracks, air_density=1.2041):
|
|
27
|
+
"""Mutate interior faces and subfaces to model airflow through cracks and openings.
|
|
28
|
+
|
|
29
|
+
This function creates an AFNCrack object with an air mass flow coefficient that
|
|
30
|
+
reflects the leakage characteristics of faces with different areas and types.
|
|
31
|
+
This requires multiplying the area-normalized air mass flow coefficients from the
|
|
32
|
+
reference crack data in int_cracks, by the wall area. This function assumes adjacent
|
|
33
|
+
faces share the same type and area properties so that the computed leakage parameters
|
|
34
|
+
are equivalent for each face.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
interior_face_groups: A tuple with four groups of interior faces types
|
|
38
|
+
|
|
39
|
+
- int_walls: List of interior Wall type Face objects.
|
|
40
|
+
|
|
41
|
+
- int_floorceilings: List of interior RoofCeiling and Floor type Face
|
|
42
|
+
objects.
|
|
43
|
+
|
|
44
|
+
- int_apertures: List of interior Aperture Face objects.
|
|
45
|
+
|
|
46
|
+
- int_doors: List of interior Door Face objects.
|
|
47
|
+
|
|
48
|
+
- int_air: List of interior Faces with AirBoundary face type.
|
|
49
|
+
|
|
50
|
+
int_cracks: A dictionary of air mass flow coefficient and exponent data
|
|
51
|
+
corresponding to the face types in the interior_face_groups. Face
|
|
52
|
+
data flow coefficients should be normalized by surface area, and closed
|
|
53
|
+
opening flow coefficients should be normalized by edge lengths, for example:
|
|
54
|
+
|
|
55
|
+
.. code-block:: python
|
|
56
|
+
|
|
57
|
+
{
|
|
58
|
+
"wall_flow_cof": 0.003, # wall flow coefficient
|
|
59
|
+
"wall_flow_exp": 0.75, # wall flow exponent
|
|
60
|
+
"floorceiling_flow_cof": 0.0009, # floorceiling flow coefficient
|
|
61
|
+
"floorceiling_flow_exp": 0.7, # floorceiling flow exponent
|
|
62
|
+
"window_flow_cof": 0.0014, # window flow coefficient
|
|
63
|
+
"window_flow_exp": 0.65, # window flow exponent
|
|
64
|
+
"door_flow_cof": 0.02, # door flow coefficient
|
|
65
|
+
"door_flow_exp": 0.6 # door flow exponent
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
air_density: Air density in kg/m3. (Default: 1.2041 represents
|
|
69
|
+
air density at a temperature of 20 C and 101325 Pa).
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
# simplify parameters
|
|
73
|
+
int_walls, int_floorceilings, int_apertures, int_doors, int_air = interior_face_groups
|
|
74
|
+
|
|
75
|
+
# add interior crack leakage components for opaque building Faces
|
|
76
|
+
for int_wall in int_walls:
|
|
77
|
+
opening_area = sum([aper.area for aper in int_wall.apertures])
|
|
78
|
+
opening_area += sum([door.area for door in int_wall.doors])
|
|
79
|
+
face_area = int_wall.area - opening_area
|
|
80
|
+
flow_cof = int_cracks['wall_flow_cof'] * face_area
|
|
81
|
+
flow_exp = int_cracks['wall_flow_exp']
|
|
82
|
+
int_wall.properties.energy.vent_crack = AFNCrack(flow_cof, flow_exp)
|
|
83
|
+
|
|
84
|
+
for int_floorceiling in int_floorceilings:
|
|
85
|
+
opening_area = sum([aper.area for aper in int_floorceiling.apertures])
|
|
86
|
+
face_area = int_floorceiling.area - opening_area
|
|
87
|
+
flow_cof = int_cracks['floorceiling_flow_cof'] * face_area
|
|
88
|
+
flow_exp = int_cracks['floorceiling_flow_exp']
|
|
89
|
+
int_floorceiling.properties.energy.vent_crack = AFNCrack(flow_cof, flow_exp)
|
|
90
|
+
|
|
91
|
+
# add interior crack leakage for air boundary Faces
|
|
92
|
+
for int_ab in int_air:
|
|
93
|
+
# derive (large) flow coefficient from the orifice equation with 0.65 discharge
|
|
94
|
+
flow_cof = 0.65 * int_ab.area * math.sqrt(air_density * 2)
|
|
95
|
+
flow_exp = 0.5 # always use 0.5 exponent for a large hole-shaped opening
|
|
96
|
+
int_ab.properties.energy.vent_crack = AFNCrack(flow_cof, flow_exp)
|
|
97
|
+
|
|
98
|
+
# add interior opening leakage components
|
|
99
|
+
for int_aperture in int_apertures:
|
|
100
|
+
if int_aperture.properties.energy.vent_opening is None:
|
|
101
|
+
int_aperture.is_operable = True
|
|
102
|
+
int_aperture.properties.energy.vent_opening = \
|
|
103
|
+
VentilationOpening(fraction_area_operable=0)
|
|
104
|
+
vent_opening = int_aperture.properties.energy.vent_opening
|
|
105
|
+
vent_opening.flow_coefficient_closed = int_cracks['window_flow_cof']
|
|
106
|
+
vent_opening.flow_exponent_closed = int_cracks['window_flow_exp']
|
|
107
|
+
|
|
108
|
+
for int_door in int_doors:
|
|
109
|
+
if int_door.properties.energy.vent_opening is None:
|
|
110
|
+
int_door.properties.energy.vent_opening = \
|
|
111
|
+
VentilationOpening(fraction_area_operable=0)
|
|
112
|
+
vent_opening = int_door.properties.energy.vent_opening
|
|
113
|
+
vent_opening.flow_coefficient_closed = int_cracks['door_flow_cof']
|
|
114
|
+
vent_opening.flow_exponent_closed = int_cracks['door_flow_exp']
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _exterior_afn(exterior_face_groups, ext_cracks):
|
|
118
|
+
"""Mutate exterior faces and subfaces to model airflow through cracks and openings.
|
|
119
|
+
|
|
120
|
+
This function creates an AFNCrack object with an air mass flow coefficient that
|
|
121
|
+
reflects the leakage characteristics of faces with different areas and types.
|
|
122
|
+
This requires multiplying the area-normalized air mass flow coefficients from the
|
|
123
|
+
reference crack data in ext_cracks, by the wall area.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
exterior_face_groups: A tuple with five groups of exterior envelope types
|
|
127
|
+
|
|
128
|
+
- ext_walls - A list of exterior Wall type Face objects.
|
|
129
|
+
|
|
130
|
+
- ext_roofs - A list of exterior RoofCeiling type Face objects.
|
|
131
|
+
|
|
132
|
+
- ext_floors - A list of exterior Floor type Face objects, like you
|
|
133
|
+
would find in a cantilevered Room.
|
|
134
|
+
|
|
135
|
+
- ext_apertures - A list of exterior Aperture Face objects.
|
|
136
|
+
|
|
137
|
+
- ext_doors - A list of exterior Door Face objects.
|
|
138
|
+
|
|
139
|
+
ext_cracks: A dictionary of air mass flow coefficient and exponent data
|
|
140
|
+
corresponding to the face types in the exterior_face_groups. Face
|
|
141
|
+
data flow coefficients should be normalized by surface area, and closed
|
|
142
|
+
opening flow coefficients should be normalized by edge lengths, for example:
|
|
143
|
+
|
|
144
|
+
.. code-block:: python
|
|
145
|
+
|
|
146
|
+
{
|
|
147
|
+
"wall_flow_cof": 0.003, # wall flow coefficient
|
|
148
|
+
"wall_flow_exp": 0.75, # wall flow exponent
|
|
149
|
+
"roof_flow_cof": 0.0009, # roof flow coefficient
|
|
150
|
+
"roof_flow_exp": 0.7, # roof flow exponent
|
|
151
|
+
"floor_flow_cof": 0.0009, # floor flow coefficient
|
|
152
|
+
"floor_flow_exp": 0.7, # floor flow exponent
|
|
153
|
+
"window_flow_cof": 0.0014, # window flow coefficient
|
|
154
|
+
"window_flow_exp": 0.65, # window flow exponent
|
|
155
|
+
"door_flow_cof": 0.02, # door flow coefficient
|
|
156
|
+
"door_flow_exp": 0.6 # door flow exponent
|
|
157
|
+
}
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
# simplify parameters
|
|
161
|
+
ext_walls, ext_roofs, ext_floors, ext_apertures, ext_doors = exterior_face_groups
|
|
162
|
+
|
|
163
|
+
# add exterior crack leakage components
|
|
164
|
+
for ext_wall in ext_walls:
|
|
165
|
+
opening_area = sum([aper.area for aper in ext_wall.apertures])
|
|
166
|
+
opening_area += sum([door.area for door in ext_wall.doors])
|
|
167
|
+
face_area = ext_wall.area - opening_area
|
|
168
|
+
flow_cof = ext_cracks['wall_flow_cof'] * face_area
|
|
169
|
+
flow_exp = ext_cracks['wall_flow_exp']
|
|
170
|
+
ext_wall.properties.energy.vent_crack = AFNCrack(flow_cof, flow_exp)
|
|
171
|
+
|
|
172
|
+
for ext_roof in ext_roofs:
|
|
173
|
+
opening_area = sum([aper.area for aper in ext_roof.apertures])
|
|
174
|
+
face_area = ext_roof.area - opening_area
|
|
175
|
+
flow_cof = ext_cracks['roof_flow_cof'] * face_area
|
|
176
|
+
flow_exp = ext_cracks['roof_flow_exp']
|
|
177
|
+
ext_roof.properties.energy.vent_crack = AFNCrack(flow_cof, flow_exp)
|
|
178
|
+
|
|
179
|
+
for ext_floor in ext_floors:
|
|
180
|
+
face_area = ext_floor.area
|
|
181
|
+
flow_cof = ext_cracks['floor_flow_cof'] * face_area
|
|
182
|
+
flow_exp = ext_cracks['floor_flow_exp']
|
|
183
|
+
ext_floor.properties.energy.vent_crack = AFNCrack(flow_cof, flow_exp)
|
|
184
|
+
|
|
185
|
+
# add exterior opening leakage components
|
|
186
|
+
for ext_aperture in ext_apertures:
|
|
187
|
+
if ext_aperture.properties.energy.vent_opening is None:
|
|
188
|
+
ext_aperture.is_operable = True
|
|
189
|
+
ext_aperture.properties.energy.vent_opening = \
|
|
190
|
+
VentilationOpening(fraction_area_operable=0)
|
|
191
|
+
vent_opening = ext_aperture.properties.energy.vent_opening
|
|
192
|
+
vent_opening.flow_coefficient_closed = ext_cracks['window_flow_cof']
|
|
193
|
+
vent_opening.flow_exponent_closed = ext_cracks['window_flow_exp']
|
|
194
|
+
|
|
195
|
+
for ext_door in ext_doors:
|
|
196
|
+
if ext_door.properties.energy.vent_opening is None:
|
|
197
|
+
ext_door.properties.energy.vent_opening = \
|
|
198
|
+
VentilationOpening(fraction_area_operable=0)
|
|
199
|
+
vent_opening = ext_door.properties.energy.vent_opening
|
|
200
|
+
vent_opening.flow_coefficient_closed = ext_cracks['door_flow_cof']
|
|
201
|
+
vent_opening.flow_exponent_closed = ext_cracks['door_flow_exp']
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def generate(rooms, leakage_type='Medium', use_room_infiltration=True,
|
|
205
|
+
atmospheric_pressure=101325, delta_pressure=4):
|
|
206
|
+
"""
|
|
207
|
+
Mutate a list of Honeybee Room objects to represent an EnergyPlus AirflowNetwork.
|
|
208
|
+
|
|
209
|
+
This function will compute leakage component parameters for the ventilation
|
|
210
|
+
cooling energy properties of Honeybee Room and Face objects to simulate an
|
|
211
|
+
EnergyPlus AirflowNetwork. The leakage flow coefficient and exponent values are
|
|
212
|
+
referenced from the DesignBuilder Cracks Template[1], which provides typical air
|
|
213
|
+
changes rates for different envelope tightness classifications for a range of
|
|
214
|
+
building types. Specifically this function references leakage values for an
|
|
215
|
+
'Excellent', 'Medium', and 'VeryPoor' classification of envelope tightness.
|
|
216
|
+
|
|
217
|
+
VentilationOpening objects will be added to Aperture and Door objects if not already
|
|
218
|
+
defined, with the fraction_area_operable set to 0. If already defined, only the
|
|
219
|
+
parameters defining leakage when the openings are closed will be overwritten.
|
|
220
|
+
AFNCrack objects will be added to all external and internal Face objects, and any
|
|
221
|
+
existing AFNCrack objects will be overwritten.
|
|
222
|
+
|
|
223
|
+
Note:
|
|
224
|
+
[1] DesignBuilder (6.1.6.008). DesignBuilder Software Ltd, 2000-2020.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
rooms: List of Honeybee Room objects that make up the Airflow Network. The
|
|
228
|
+
adjacencies of these rooms must be solved.
|
|
229
|
+
leakage_type: Text identifying the leakiness of the internal walls. This
|
|
230
|
+
will be used to determine the air mass flow rate parameters for cracks in
|
|
231
|
+
internal floors, ceilings and walls. (Default: ''Medium'').
|
|
232
|
+
Choose from the following:
|
|
233
|
+
|
|
234
|
+
* Excellent
|
|
235
|
+
* Medium
|
|
236
|
+
* VeryPoor
|
|
237
|
+
|
|
238
|
+
use_room_infiltration: Boolean value to specify how exterior leakage parameters
|
|
239
|
+
are computed. If True the exterior airflow leakage parameters will be derived
|
|
240
|
+
from the room infiltration rate specified in RoomEnergyProperties. This will
|
|
241
|
+
compute air leakage parameters for exterior cracks and opening edges that
|
|
242
|
+
produce a total air flow rate equivalent to the room infiltration rate, at
|
|
243
|
+
an envelope pressure difference of 4 Pa. However, the individual flow air
|
|
244
|
+
leakage parameters are not meant to be representative of real values, since
|
|
245
|
+
the infiltration flow rate is an average of the actual, variable surface
|
|
246
|
+
flow dynamics. If False, the airflow leakage parameters are selected from a
|
|
247
|
+
crack data template, corresponding to the provided leakage_type. Since these
|
|
248
|
+
leakage parameters reflect empirically obtained values for different surface
|
|
249
|
+
types, they will result in a more realistic simulation of air flow through
|
|
250
|
+
orifices and cracks. In both cases, interzone airflow leakage parameters are
|
|
251
|
+
referenced from the crack data template, corresponding to the provided
|
|
252
|
+
leakage_type.
|
|
253
|
+
atmospheric_pressure: Optional number to define the atmospheric pressure
|
|
254
|
+
measurement in Pascals used to calculate dry air density. (Default: 101325).
|
|
255
|
+
delta_pressure: Optional reference air pressure difference across the building
|
|
256
|
+
envelope orifice in Pascals. delta_pressure is used to calculate
|
|
257
|
+
infiltration crack flow coefficients if the use_room_infiltration argument
|
|
258
|
+
is True. See the exterior_afn_from_infiltration method in the
|
|
259
|
+
RoomEnergyProperties class for details on how to set this value if
|
|
260
|
+
attempting to replicate the room infiltration rate per exterior area.
|
|
261
|
+
Default 4 represents typical building pressures.
|
|
262
|
+
"""
|
|
263
|
+
# simplify parameters
|
|
264
|
+
if leakage_type == 'Excellent':
|
|
265
|
+
int_cracks = CRACK_TEMPLATE_DATA['internal_excellent_cracks']
|
|
266
|
+
ext_cracks = CRACK_TEMPLATE_DATA['external_excellent_cracks']
|
|
267
|
+
elif leakage_type == 'Medium':
|
|
268
|
+
int_cracks = CRACK_TEMPLATE_DATA['internal_medium_cracks']
|
|
269
|
+
ext_cracks = CRACK_TEMPLATE_DATA['external_medium_cracks']
|
|
270
|
+
elif leakage_type == 'VeryPoor':
|
|
271
|
+
int_cracks = CRACK_TEMPLATE_DATA['internal_verypoor_cracks']
|
|
272
|
+
ext_cracks = CRACK_TEMPLATE_DATA['external_verypoor_cracks']
|
|
273
|
+
else:
|
|
274
|
+
raise AssertionError('leakage_type must be "Excellent", "Medium", '
|
|
275
|
+
'or "VeryPoor". Got: {}.'.format(leakage_type))
|
|
276
|
+
|
|
277
|
+
# generate the airflow newtwork
|
|
278
|
+
for room in rooms:
|
|
279
|
+
# get grouped faces by type that experience air flow leakage
|
|
280
|
+
ext_faces, int_faces = room.properties.energy.envelope_components_by_type()
|
|
281
|
+
|
|
282
|
+
# mutate surfaces with AFN flow parameters
|
|
283
|
+
rho = _air_density_from_pressure(atmospheric_pressure)
|
|
284
|
+
if use_room_infiltration and room.properties.energy.infiltration is not None:
|
|
285
|
+
room.properties.energy.exterior_afn_from_infiltration_load(
|
|
286
|
+
ext_faces, air_density=rho, delta_pressure=delta_pressure)
|
|
287
|
+
else:
|
|
288
|
+
_exterior_afn(ext_faces, ext_cracks)
|
|
289
|
+
_interior_afn(int_faces, int_cracks, rho)
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Object to dictate setpoints and schedule for ventilative cooling."""
|
|
3
|
+
from __future__ import division
|
|
4
|
+
|
|
5
|
+
from ..schedule.dictutil import dict_to_schedule
|
|
6
|
+
from ..schedule.ruleset import ScheduleRuleset
|
|
7
|
+
from ..schedule.fixedinterval import ScheduleFixedInterval
|
|
8
|
+
from ..lib.schedules import always_on
|
|
9
|
+
|
|
10
|
+
from honeybee._lockable import lockable
|
|
11
|
+
from honeybee.typing import float_in_range
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@lockable
|
|
15
|
+
class VentilationControl(object):
|
|
16
|
+
"""Object to dictate setpoints and schedule for ventilative cooling.
|
|
17
|
+
|
|
18
|
+
Note the all of the default setpoints of this object are set to always perform
|
|
19
|
+
ventilative cooling such that users can individually decide which setpoints
|
|
20
|
+
are relevant to a given ventilation strategy.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
min_indoor_temperature: A number between -100 and 100 for the minimum
|
|
24
|
+
indoor temperature at which to ventilate in Celsius. Typically,
|
|
25
|
+
this variable is used to initiate ventilation. (Default: -100).
|
|
26
|
+
max_indoor_temperature: A number between -100 and 100 for the maximum
|
|
27
|
+
indoor temperature at which to ventilate in Celsius. This can be
|
|
28
|
+
used to set a maximum temperature at which point ventilation is
|
|
29
|
+
stopped and a cooling system is turned on. (Default: 100).
|
|
30
|
+
min_outdoor_temperature: A number between -100 and 100 for the minimum
|
|
31
|
+
outdoor temperature at which to ventilate in Celsius. This can be
|
|
32
|
+
used to ensure ventilative cooling doesn't happen during the winter
|
|
33
|
+
even if the Room is above the min_indoor_temperature. (Default: -100).
|
|
34
|
+
max_outdoor_temperature: A number between -100 and 100 for the maximum
|
|
35
|
+
outdoor temperature at which to ventilate in Celsius. This can be
|
|
36
|
+
used to set a limit for when it is considered too hot outside for
|
|
37
|
+
ventilative cooling. (Default: 100).
|
|
38
|
+
delta_temperature: A number between -100 and 100 for the temperature
|
|
39
|
+
differential in Celsius between indoor and outdoor below which
|
|
40
|
+
ventilation is shut off. This should usually be a positive number
|
|
41
|
+
so that ventilation only occurs when the outdoors is cooler than the
|
|
42
|
+
indoors. Negative numbers indicate how much hotter the outdoors can
|
|
43
|
+
be than the indoors before ventilation is stopped. (Default: -100).
|
|
44
|
+
schedule: An optional ScheduleRuleset or ScheduleFixedInterval for the
|
|
45
|
+
ventilation over the course of the year. Note that this is applied
|
|
46
|
+
on top of any setpoints. The type of this schedule should be On/Off
|
|
47
|
+
and values should be either 0 (no possibility of ventilation) or 1
|
|
48
|
+
(ventilation possible). (Default: "Always On")
|
|
49
|
+
|
|
50
|
+
Properties:
|
|
51
|
+
* min_indoor_temperature
|
|
52
|
+
* max_indoor_temperature
|
|
53
|
+
* min_outdoor_temperature
|
|
54
|
+
* max_outdoor_temperature
|
|
55
|
+
* delta_temperature
|
|
56
|
+
* schedule
|
|
57
|
+
"""
|
|
58
|
+
__slots__ = ('_min_indoor_temperature', '_max_indoor_temperature',
|
|
59
|
+
'_min_outdoor_temperature', '_max_outdoor_temperature',
|
|
60
|
+
'_delta_temperature', '_schedule', '_locked')
|
|
61
|
+
|
|
62
|
+
def __init__(self, min_indoor_temperature=-100, max_indoor_temperature=100,
|
|
63
|
+
min_outdoor_temperature=-100, max_outdoor_temperature=100,
|
|
64
|
+
delta_temperature=-100, schedule=always_on):
|
|
65
|
+
"""Initialize VentilationControl."""
|
|
66
|
+
self.min_indoor_temperature = min_indoor_temperature
|
|
67
|
+
self.max_indoor_temperature = max_indoor_temperature
|
|
68
|
+
self.min_outdoor_temperature = min_outdoor_temperature
|
|
69
|
+
self.max_outdoor_temperature = max_outdoor_temperature
|
|
70
|
+
self.delta_temperature = delta_temperature
|
|
71
|
+
self.schedule = schedule
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def min_indoor_temperature(self):
|
|
75
|
+
"""Get or set a number for the minimum indoor temperature for ventilation (C)."""
|
|
76
|
+
return self._min_indoor_temperature
|
|
77
|
+
|
|
78
|
+
@min_indoor_temperature.setter
|
|
79
|
+
def min_indoor_temperature(self, value):
|
|
80
|
+
self._min_indoor_temperature = \
|
|
81
|
+
float_in_range(value, -100.0, 100.0, 'min indoor temperature')
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def max_indoor_temperature(self):
|
|
85
|
+
"""Get or set a number for the maximum indoor temperature for ventilation (C)."""
|
|
86
|
+
return self._max_indoor_temperature
|
|
87
|
+
|
|
88
|
+
@max_indoor_temperature.setter
|
|
89
|
+
def max_indoor_temperature(self, value):
|
|
90
|
+
self._max_indoor_temperature = \
|
|
91
|
+
float_in_range(value, -100.0, 100.0, 'max indoor temperature')
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def min_outdoor_temperature(self):
|
|
95
|
+
"""Get or set a number for the minimum outdoor temperature for ventilation (C).
|
|
96
|
+
"""
|
|
97
|
+
return self._min_outdoor_temperature
|
|
98
|
+
|
|
99
|
+
@min_outdoor_temperature.setter
|
|
100
|
+
def min_outdoor_temperature(self, value):
|
|
101
|
+
self._min_outdoor_temperature = \
|
|
102
|
+
float_in_range(value, -100.0, 100.0, 'min outdoor temperature')
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def max_outdoor_temperature(self):
|
|
106
|
+
"""Get or set a number for the maximum outdoor temperature for ventilation (C).
|
|
107
|
+
"""
|
|
108
|
+
return self._max_outdoor_temperature
|
|
109
|
+
|
|
110
|
+
@max_outdoor_temperature.setter
|
|
111
|
+
def max_outdoor_temperature(self, value):
|
|
112
|
+
self._max_outdoor_temperature = \
|
|
113
|
+
float_in_range(value, -100.0, 100.0, 'max outdoor temperature')
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def delta_temperature(self):
|
|
117
|
+
"""Get or set the indoor/outdoor temperature difference for ventilation (C)."""
|
|
118
|
+
return self._delta_temperature
|
|
119
|
+
|
|
120
|
+
@delta_temperature.setter
|
|
121
|
+
def delta_temperature(self, value):
|
|
122
|
+
self._delta_temperature = \
|
|
123
|
+
float_in_range(value, -100.0, 100.0, 'delta temperature')
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def schedule(self):
|
|
127
|
+
"""Get or set an On/Off schedule for the ventilation.
|
|
128
|
+
|
|
129
|
+
Note that this is applied on top of any setpoints.
|
|
130
|
+
"""
|
|
131
|
+
return self._schedule
|
|
132
|
+
|
|
133
|
+
@schedule.setter
|
|
134
|
+
def schedule(self, value):
|
|
135
|
+
if value is not None:
|
|
136
|
+
assert isinstance(value, (ScheduleRuleset, ScheduleFixedInterval)), \
|
|
137
|
+
'Expected schedule for VentilationControl schedule. ' \
|
|
138
|
+
'Got {}.'.format(type(value))
|
|
139
|
+
if value.schedule_type_limit is not None:
|
|
140
|
+
assert value.schedule_type_limit.unit == 'fraction', \
|
|
141
|
+
'VentilationControl schedule should be fractional ' \
|
|
142
|
+
'[Dimensionless]. Got a schedule ' \
|
|
143
|
+
'of unit_type [{}].'.format(value.schedule_type_limit.unit_type)
|
|
144
|
+
value.lock() # lock editing in case schedule has multiple references
|
|
145
|
+
self._schedule = value
|
|
146
|
+
else:
|
|
147
|
+
self._schedule = always_on
|
|
148
|
+
|
|
149
|
+
@classmethod
|
|
150
|
+
def from_dict(cls, data):
|
|
151
|
+
"""Create a VentilationControl from a dictionary.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
data: A python dictionary in the following format
|
|
155
|
+
|
|
156
|
+
.. code-block:: python
|
|
157
|
+
|
|
158
|
+
{
|
|
159
|
+
"type": 'VentilationControl',
|
|
160
|
+
"min_indoor_temperature": 22,
|
|
161
|
+
"max_indoor_temperature": 26,
|
|
162
|
+
"min_outdoor_temperature": 12,
|
|
163
|
+
"max_outdoor_temperature": 32,
|
|
164
|
+
"delta_temperature": -4,
|
|
165
|
+
"schedule": {} # dictionary of a schedule
|
|
166
|
+
}
|
|
167
|
+
"""
|
|
168
|
+
assert data['type'] == 'VentilationControl', \
|
|
169
|
+
'Expected VentilationControl. Got {}.'.format(data['type'])
|
|
170
|
+
min_in, max_in, min_out, max_out, delta = cls._default_dict_values(data)
|
|
171
|
+
sch = dict_to_schedule(data['schedule']) if 'schedule' in data and \
|
|
172
|
+
data['schedule'] is not None else always_on
|
|
173
|
+
vent_control = cls(min_in, max_in, min_out, max_out, delta, sch)
|
|
174
|
+
return vent_control
|
|
175
|
+
|
|
176
|
+
@classmethod
|
|
177
|
+
def from_dict_abridged(cls, data, schedule_dict):
|
|
178
|
+
"""Create a VentilationControl from an abridged dictionary.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
data: A VentilationControlAbridged dictionary with the format below.
|
|
182
|
+
schedule_dict: A dictionary with schedule identifiers as keys and
|
|
183
|
+
honeybee schedule objects as values. These will be used to
|
|
184
|
+
assign the schedule to the VentilationControl object.
|
|
185
|
+
|
|
186
|
+
.. code-block:: python
|
|
187
|
+
|
|
188
|
+
{
|
|
189
|
+
"type": 'VentilationControlAbridged',
|
|
190
|
+
"min_indoor_temperature": 22,
|
|
191
|
+
"max_indoor_temperature": 26,
|
|
192
|
+
"min_outdoor_temperature": 12,
|
|
193
|
+
"max_outdoor_temperature": 32,
|
|
194
|
+
"delta_temperature": -4,
|
|
195
|
+
"schedule": "" # identifier of a schedule
|
|
196
|
+
}
|
|
197
|
+
"""
|
|
198
|
+
assert data['type'] == 'VentilationControlAbridged', \
|
|
199
|
+
'Expected VentilationControlAbridged. Got {}.'.format(data['type'])
|
|
200
|
+
min_in, max_in, min_out, max_out, delta = cls._default_dict_values(data)
|
|
201
|
+
sch = schedule_dict[data['schedule']] if \
|
|
202
|
+
'schedule' in data and data['schedule'] is not None else always_on
|
|
203
|
+
vent_control = cls(min_in, max_in, min_out, max_out, delta, sch)
|
|
204
|
+
return vent_control
|
|
205
|
+
|
|
206
|
+
def to_dict(self, abridged=False):
|
|
207
|
+
"""Ventilation Control dictionary representation."""
|
|
208
|
+
base = {'type': 'VentilationControl'} if not \
|
|
209
|
+
abridged else {'type': 'VentilationControlAbridged'}
|
|
210
|
+
base['min_indoor_temperature'] = self.min_indoor_temperature
|
|
211
|
+
base['max_indoor_temperature'] = self.max_indoor_temperature
|
|
212
|
+
base['min_outdoor_temperature'] = self.min_outdoor_temperature
|
|
213
|
+
base['max_outdoor_temperature'] = self.max_outdoor_temperature
|
|
214
|
+
base['delta_temperature'] = self.delta_temperature
|
|
215
|
+
if self.schedule is not always_on:
|
|
216
|
+
base['schedule'] = self.schedule.identifier if abridged \
|
|
217
|
+
else self.schedule.to_dict()
|
|
218
|
+
return base
|
|
219
|
+
|
|
220
|
+
def duplicate(self):
|
|
221
|
+
"""Get a copy of this object."""
|
|
222
|
+
return self.__copy__()
|
|
223
|
+
|
|
224
|
+
@staticmethod
|
|
225
|
+
def _default_dict_values(data):
|
|
226
|
+
"""Process dictionary values and include defaults for missing values."""
|
|
227
|
+
min_in = data['min_indoor_temperature'] if 'min_indoor_temperature' in data \
|
|
228
|
+
and data['min_indoor_temperature'] is not None else -100
|
|
229
|
+
max_in = data['max_indoor_temperature'] if 'max_indoor_temperature' in data \
|
|
230
|
+
and data['max_indoor_temperature'] is not None else 100
|
|
231
|
+
min_out = data['min_outdoor_temperature'] if 'min_outdoor_temperature' in data \
|
|
232
|
+
and data['min_outdoor_temperature'] is not None else -100
|
|
233
|
+
max_out = data['max_outdoor_temperature'] if 'max_outdoor_temperature' in data \
|
|
234
|
+
and data['max_outdoor_temperature'] is not None else 100
|
|
235
|
+
delta = data['delta_temperature'] if 'delta_temperature' in data \
|
|
236
|
+
and data['delta_temperature'] is not None else -100
|
|
237
|
+
return min_in, max_in, min_out, max_out, delta
|
|
238
|
+
|
|
239
|
+
def __copy__(self):
|
|
240
|
+
return VentilationControl(
|
|
241
|
+
self.min_indoor_temperature, self.max_indoor_temperature,
|
|
242
|
+
self.min_outdoor_temperature, self.max_outdoor_temperature,
|
|
243
|
+
self.delta_temperature, self.schedule)
|
|
244
|
+
|
|
245
|
+
def __key(self):
|
|
246
|
+
"""A tuple based on the object properties, useful for hashing."""
|
|
247
|
+
return (self.min_indoor_temperature, self.max_indoor_temperature,
|
|
248
|
+
self.min_outdoor_temperature, self.max_outdoor_temperature,
|
|
249
|
+
self.delta_temperature, hash(self._schedule))
|
|
250
|
+
|
|
251
|
+
def __hash__(self):
|
|
252
|
+
return hash(self.__key())
|
|
253
|
+
|
|
254
|
+
def __eq__(self, other):
|
|
255
|
+
return isinstance(other, VentilationControl) and self.__key() == other.__key()
|
|
256
|
+
|
|
257
|
+
def __ne__(self, other):
|
|
258
|
+
return not self.__eq__(other)
|
|
259
|
+
|
|
260
|
+
def ToString(self):
|
|
261
|
+
"""Overwrite .NET ToString."""
|
|
262
|
+
return self.__repr__()
|
|
263
|
+
|
|
264
|
+
def __repr__(self):
|
|
265
|
+
return 'VentilationControl, [min in: {}] [max in: {}] [min out: {}] ' \
|
|
266
|
+
'[max out: {}] [delta: {}]'.format(
|
|
267
|
+
self.min_indoor_temperature, self.max_indoor_temperature,
|
|
268
|
+
self.min_outdoor_temperature, self.max_outdoor_temperature,
|
|
269
|
+
self.delta_temperature)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Definition of surface crack for multizone airflow."""
|
|
3
|
+
from __future__ import division
|
|
4
|
+
|
|
5
|
+
from honeybee._lockable import lockable
|
|
6
|
+
from honeybee.typing import float_in_range, float_positive
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@lockable
|
|
10
|
+
class AFNCrack(object):
|
|
11
|
+
"""Airflow leakage through surface due to cracks or porous surface material.
|
|
12
|
+
|
|
13
|
+
Note that this whole class only has bearing on the simulation when the Model
|
|
14
|
+
that the AFNCrack is a part of has its ventilation_simulation_control set for
|
|
15
|
+
MultiZone air flow, thereby triggering the use of the AirflowNetwork.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
flow_coefficient: A number in kg/s-m at 1 Pa per meter of
|
|
19
|
+
crack length at the conditions defined in the ReferenceCrack condition;
|
|
20
|
+
required to run an AirflowNetwork simulation. Some common values for this
|
|
21
|
+
coefficient from the DesignBuilder Cracks template include the following:
|
|
22
|
+
|
|
23
|
+
* 0.00001 - Tight low-leakage external wall
|
|
24
|
+
* 0.001 - Tight, low-leakage internal wall
|
|
25
|
+
* 0.0004 - Poor, high-leakage external wall
|
|
26
|
+
* 0.019 - Poor, high-leakage internal wall
|
|
27
|
+
|
|
28
|
+
flow_exponent: An optional dimensionless number between 0.5 and 1 used
|
|
29
|
+
to calculate the crack mass flow rate; required to run an AirflowNetwork
|
|
30
|
+
simulation. This value represents the leak geometry impact on airflow, with
|
|
31
|
+
0.5 generally corresponding to turbulent orifice flow and 1 generally
|
|
32
|
+
corresponding to laminar flow. The default of 0.65 is representative of many
|
|
33
|
+
cases of wall and window leakage, used when the exponent cannot be measured.
|
|
34
|
+
(Default: 0.65).
|
|
35
|
+
|
|
36
|
+
Properties:
|
|
37
|
+
* flow_coefficient
|
|
38
|
+
* flow_exponent
|
|
39
|
+
"""
|
|
40
|
+
__slots__ = ('_flow_coefficient', '_flow_exponent', '_locked')
|
|
41
|
+
|
|
42
|
+
def __init__(self, flow_coefficient, flow_exponent=0.65):
|
|
43
|
+
"""Initialize AFNCrack."""
|
|
44
|
+
self.flow_coefficient = flow_coefficient
|
|
45
|
+
self.flow_exponent = flow_exponent
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def flow_coefficient(self):
|
|
49
|
+
"""Get or set the air mass flow coefficient defined at the reference crack."""
|
|
50
|
+
return self._flow_coefficient
|
|
51
|
+
|
|
52
|
+
@flow_coefficient.setter
|
|
53
|
+
def flow_coefficient(self, value):
|
|
54
|
+
self._flow_coefficient = float_positive(value, 'flow_coefficient')
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def flow_exponent(self):
|
|
58
|
+
"""Get or set the air mass flow exponent for the surface crack."""
|
|
59
|
+
return self._flow_exponent
|
|
60
|
+
|
|
61
|
+
@flow_exponent.setter
|
|
62
|
+
def flow_exponent(self, value):
|
|
63
|
+
self._flow_exponent = float_in_range(value, 0.5, 1.0, 'flow_exponent')
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def from_dict(cls, data):
|
|
67
|
+
"""Create a AFNCrack object from a dictionary.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
data: A AFNCrack dictionary following the format below.
|
|
71
|
+
|
|
72
|
+
.. code-block:: python
|
|
73
|
+
|
|
74
|
+
{
|
|
75
|
+
"type": "AFNCrack",
|
|
76
|
+
"flow_coefficient": 0.01 # coefficient at reference crack
|
|
77
|
+
"flow_exponent": 0.65 # exponent for the surface crack
|
|
78
|
+
}
|
|
79
|
+
"""
|
|
80
|
+
assert data['type'] == 'AFNCrack', \
|
|
81
|
+
'Expected AFNCrack dictionary. Got {}.'.format(data['type'])
|
|
82
|
+
|
|
83
|
+
assert 'flow_coefficient' in data, 'The flow_coefficient must be defined to ' \
|
|
84
|
+
'create a AFNCrack object.'
|
|
85
|
+
|
|
86
|
+
air_coeff = data['flow_coefficient']
|
|
87
|
+
air_exp = data['flow_exponent'] if 'flow_exponent' in data \
|
|
88
|
+
and data['flow_exponent'] is not None else 0.65
|
|
89
|
+
|
|
90
|
+
return cls(air_coeff, air_exp)
|
|
91
|
+
|
|
92
|
+
def to_dict(self):
|
|
93
|
+
"""AFNCrack dictionary representation."""
|
|
94
|
+
base = {'type': 'AFNCrack'}
|
|
95
|
+
base['flow_coefficient'] = self.flow_coefficient
|
|
96
|
+
base['flow_exponent'] = self.flow_exponent
|
|
97
|
+
return base
|
|
98
|
+
|
|
99
|
+
def duplicate(self):
|
|
100
|
+
"""Get a copy of this object."""
|
|
101
|
+
return self.__copy__()
|
|
102
|
+
|
|
103
|
+
def __copy__(self):
|
|
104
|
+
return AFNCrack(
|
|
105
|
+
self.flow_coefficient, self.flow_exponent)
|
|
106
|
+
|
|
107
|
+
def __key(self):
|
|
108
|
+
"""A tuple based on the object properties, useful for hashing."""
|
|
109
|
+
return (self.flow_coefficient, self.flow_exponent)
|
|
110
|
+
|
|
111
|
+
def __hash__(self):
|
|
112
|
+
return hash(self.__key())
|
|
113
|
+
|
|
114
|
+
def __eq__(self, other):
|
|
115
|
+
return isinstance(other, AFNCrack) and self.__key() == other.__key()
|
|
116
|
+
|
|
117
|
+
def __ne__(self, other):
|
|
118
|
+
return not self.__eq__(other)
|
|
119
|
+
|
|
120
|
+
def ToString(self):
|
|
121
|
+
"""Overwrite .NET ToString."""
|
|
122
|
+
return self.__repr__()
|
|
123
|
+
|
|
124
|
+
def __repr__(self):
|
|
125
|
+
return 'AFNCrack: [coefficient: {}] [exponent: {}]'.format(
|
|
126
|
+
self.flow_coefficient, self.flow_exponent)
|