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.
Files changed (162) hide show
  1. honeybee_energy/__init__.py +24 -0
  2. honeybee_energy/__main__.py +4 -0
  3. honeybee_energy/_extend_honeybee.py +145 -0
  4. honeybee_energy/altnumber.py +21 -0
  5. honeybee_energy/baseline/__init__.py +2 -0
  6. honeybee_energy/baseline/create.py +608 -0
  7. honeybee_energy/baseline/data/__init__.py +1 -0
  8. honeybee_energy/baseline/data/constructions.csv +64 -0
  9. honeybee_energy/baseline/data/fen_ratios.csv +15 -0
  10. honeybee_energy/baseline/data/lpd_building.csv +21 -0
  11. honeybee_energy/baseline/data/pci_2016.csv +22 -0
  12. honeybee_energy/baseline/data/pci_2019.csv +22 -0
  13. honeybee_energy/baseline/data/pci_2022.csv +22 -0
  14. honeybee_energy/baseline/data/shw.csv +21 -0
  15. honeybee_energy/baseline/pci.py +512 -0
  16. honeybee_energy/baseline/result.py +371 -0
  17. honeybee_energy/boundarycondition.py +128 -0
  18. honeybee_energy/cli/__init__.py +69 -0
  19. honeybee_energy/cli/baseline.py +475 -0
  20. honeybee_energy/cli/edit.py +327 -0
  21. honeybee_energy/cli/lib.py +1154 -0
  22. honeybee_energy/cli/result.py +810 -0
  23. honeybee_energy/cli/setconfig.py +124 -0
  24. honeybee_energy/cli/settings.py +569 -0
  25. honeybee_energy/cli/simulate.py +380 -0
  26. honeybee_energy/cli/translate.py +1714 -0
  27. honeybee_energy/cli/validate.py +224 -0
  28. honeybee_energy/config.json +11 -0
  29. honeybee_energy/config.py +842 -0
  30. honeybee_energy/construction/__init__.py +1 -0
  31. honeybee_energy/construction/_base.py +374 -0
  32. honeybee_energy/construction/air.py +325 -0
  33. honeybee_energy/construction/dictutil.py +89 -0
  34. honeybee_energy/construction/dynamic.py +607 -0
  35. honeybee_energy/construction/opaque.py +460 -0
  36. honeybee_energy/construction/shade.py +319 -0
  37. honeybee_energy/construction/window.py +1096 -0
  38. honeybee_energy/construction/windowshade.py +847 -0
  39. honeybee_energy/constructionset.py +1655 -0
  40. honeybee_energy/dictutil.py +56 -0
  41. honeybee_energy/generator/__init__.py +5 -0
  42. honeybee_energy/generator/loadcenter.py +204 -0
  43. honeybee_energy/generator/pv.py +535 -0
  44. honeybee_energy/hvac/__init__.py +21 -0
  45. honeybee_energy/hvac/_base.py +124 -0
  46. honeybee_energy/hvac/_template.py +270 -0
  47. honeybee_energy/hvac/allair/__init__.py +22 -0
  48. honeybee_energy/hvac/allair/_base.py +349 -0
  49. honeybee_energy/hvac/allair/furnace.py +168 -0
  50. honeybee_energy/hvac/allair/psz.py +131 -0
  51. honeybee_energy/hvac/allair/ptac.py +163 -0
  52. honeybee_energy/hvac/allair/pvav.py +109 -0
  53. honeybee_energy/hvac/allair/vav.py +128 -0
  54. honeybee_energy/hvac/detailed.py +337 -0
  55. honeybee_energy/hvac/doas/__init__.py +28 -0
  56. honeybee_energy/hvac/doas/_base.py +345 -0
  57. honeybee_energy/hvac/doas/fcu.py +127 -0
  58. honeybee_energy/hvac/doas/radiant.py +329 -0
  59. honeybee_energy/hvac/doas/vrf.py +81 -0
  60. honeybee_energy/hvac/doas/wshp.py +91 -0
  61. honeybee_energy/hvac/heatcool/__init__.py +23 -0
  62. honeybee_energy/hvac/heatcool/_base.py +177 -0
  63. honeybee_energy/hvac/heatcool/baseboard.py +61 -0
  64. honeybee_energy/hvac/heatcool/evapcool.py +72 -0
  65. honeybee_energy/hvac/heatcool/fcu.py +92 -0
  66. honeybee_energy/hvac/heatcool/gasunit.py +53 -0
  67. honeybee_energy/hvac/heatcool/radiant.py +269 -0
  68. honeybee_energy/hvac/heatcool/residential.py +77 -0
  69. honeybee_energy/hvac/heatcool/vrf.py +54 -0
  70. honeybee_energy/hvac/heatcool/windowac.py +70 -0
  71. honeybee_energy/hvac/heatcool/wshp.py +62 -0
  72. honeybee_energy/hvac/idealair.py +699 -0
  73. honeybee_energy/internalmass.py +310 -0
  74. honeybee_energy/lib/__init__.py +1 -0
  75. honeybee_energy/lib/_loadconstructions.py +194 -0
  76. honeybee_energy/lib/_loadconstructionsets.py +117 -0
  77. honeybee_energy/lib/_loadmaterials.py +83 -0
  78. honeybee_energy/lib/_loadprogramtypes.py +125 -0
  79. honeybee_energy/lib/_loadschedules.py +87 -0
  80. honeybee_energy/lib/_loadtypelimits.py +64 -0
  81. honeybee_energy/lib/constructions.py +207 -0
  82. honeybee_energy/lib/constructionsets.py +95 -0
  83. honeybee_energy/lib/materials.py +67 -0
  84. honeybee_energy/lib/programtypes.py +125 -0
  85. honeybee_energy/lib/schedules.py +61 -0
  86. honeybee_energy/lib/scheduletypelimits.py +31 -0
  87. honeybee_energy/load/__init__.py +1 -0
  88. honeybee_energy/load/_base.py +190 -0
  89. honeybee_energy/load/daylight.py +397 -0
  90. honeybee_energy/load/dictutil.py +47 -0
  91. honeybee_energy/load/equipment.py +771 -0
  92. honeybee_energy/load/hotwater.py +543 -0
  93. honeybee_energy/load/infiltration.py +460 -0
  94. honeybee_energy/load/lighting.py +480 -0
  95. honeybee_energy/load/people.py +497 -0
  96. honeybee_energy/load/process.py +472 -0
  97. honeybee_energy/load/setpoint.py +816 -0
  98. honeybee_energy/load/ventilation.py +550 -0
  99. honeybee_energy/material/__init__.py +1 -0
  100. honeybee_energy/material/_base.py +166 -0
  101. honeybee_energy/material/dictutil.py +59 -0
  102. honeybee_energy/material/frame.py +367 -0
  103. honeybee_energy/material/gas.py +1087 -0
  104. honeybee_energy/material/glazing.py +854 -0
  105. honeybee_energy/material/opaque.py +1351 -0
  106. honeybee_energy/material/shade.py +1360 -0
  107. honeybee_energy/measure.py +472 -0
  108. honeybee_energy/programtype.py +723 -0
  109. honeybee_energy/properties/__init__.py +1 -0
  110. honeybee_energy/properties/aperture.py +333 -0
  111. honeybee_energy/properties/door.py +342 -0
  112. honeybee_energy/properties/extension.py +244 -0
  113. honeybee_energy/properties/face.py +274 -0
  114. honeybee_energy/properties/model.py +2640 -0
  115. honeybee_energy/properties/room.py +1747 -0
  116. honeybee_energy/properties/shade.py +314 -0
  117. honeybee_energy/properties/shademesh.py +262 -0
  118. honeybee_energy/reader.py +48 -0
  119. honeybee_energy/result/__init__.py +1 -0
  120. honeybee_energy/result/colorobj.py +648 -0
  121. honeybee_energy/result/emissions.py +290 -0
  122. honeybee_energy/result/err.py +101 -0
  123. honeybee_energy/result/eui.py +100 -0
  124. honeybee_energy/result/generation.py +160 -0
  125. honeybee_energy/result/loadbalance.py +890 -0
  126. honeybee_energy/result/match.py +202 -0
  127. honeybee_energy/result/osw.py +90 -0
  128. honeybee_energy/result/rdd.py +59 -0
  129. honeybee_energy/result/zsz.py +190 -0
  130. honeybee_energy/run.py +1577 -0
  131. honeybee_energy/schedule/__init__.py +1 -0
  132. honeybee_energy/schedule/day.py +626 -0
  133. honeybee_energy/schedule/dictutil.py +59 -0
  134. honeybee_energy/schedule/fixedinterval.py +1012 -0
  135. honeybee_energy/schedule/rule.py +619 -0
  136. honeybee_energy/schedule/ruleset.py +1867 -0
  137. honeybee_energy/schedule/typelimit.py +310 -0
  138. honeybee_energy/shw.py +315 -0
  139. honeybee_energy/simulation/__init__.py +1 -0
  140. honeybee_energy/simulation/control.py +214 -0
  141. honeybee_energy/simulation/daylightsaving.py +185 -0
  142. honeybee_energy/simulation/dictutil.py +51 -0
  143. honeybee_energy/simulation/output.py +646 -0
  144. honeybee_energy/simulation/parameter.py +606 -0
  145. honeybee_energy/simulation/runperiod.py +443 -0
  146. honeybee_energy/simulation/shadowcalculation.py +295 -0
  147. honeybee_energy/simulation/sizing.py +546 -0
  148. honeybee_energy/ventcool/__init__.py +5 -0
  149. honeybee_energy/ventcool/_crack_data.py +91 -0
  150. honeybee_energy/ventcool/afn.py +289 -0
  151. honeybee_energy/ventcool/control.py +269 -0
  152. honeybee_energy/ventcool/crack.py +126 -0
  153. honeybee_energy/ventcool/fan.py +493 -0
  154. honeybee_energy/ventcool/opening.py +365 -0
  155. honeybee_energy/ventcool/simulation.py +314 -0
  156. honeybee_energy/writer.py +1078 -0
  157. honeybee_energy-1.116.106.dist-info/METADATA +113 -0
  158. honeybee_energy-1.116.106.dist-info/RECORD +162 -0
  159. honeybee_energy-1.116.106.dist-info/WHEEL +5 -0
  160. honeybee_energy-1.116.106.dist-info/entry_points.txt +2 -0
  161. honeybee_energy-1.116.106.dist-info/licenses/LICENSE +661 -0
  162. honeybee_energy-1.116.106.dist-info/top_level.txt +1 -0
@@ -0,0 +1,314 @@
1
+ # coding=utf-8
2
+ """Shade Energy Properties."""
3
+ from honeybee.typing import clean_rad_string
4
+ from honeybee.checkdup import is_equivalent
5
+
6
+ from ..construction.shade import ShadeConstruction
7
+ from ..schedule.ruleset import ScheduleRuleset
8
+ from ..schedule.fixedinterval import ScheduleFixedInterval
9
+ from ..generator.pv import PVProperties
10
+
11
+ from ..lib.constructions import generic_context
12
+ from ..lib.constructionsets import generic_construction_set
13
+
14
+
15
+ class ShadeEnergyProperties(object):
16
+ """Energy Properties for Honeybee Shade.
17
+
18
+ Args:
19
+ host: A honeybee_core Shade object that hosts these properties.
20
+ construction: An optional ShadeConstruction object to set the reflectance
21
+ and specularity of the Shade. The default is set by a ConstructionSet
22
+ if the shade is the parent to an object. Otherwise, if it is an
23
+ orphaned shade, the default is a completely diffuse construction
24
+ with 0.2 visible and solar reflectance.
25
+ transmittance_schedule: An optional schedule to set the transmittance
26
+ of the shade, which can vary throughout the day or year. Default
27
+ is None for a completely opaque object.
28
+ pv_properties: An optional PVProperties object to specify photovoltaic
29
+ behavior of the Shade. If None, the Shade will have no Photovoltaic
30
+ properties. Note that the normal of the Shade is important in
31
+ determining the performance of the shade as a PV geometry.
32
+
33
+ Properties:
34
+ * host
35
+ * construction
36
+ * transmittance_schedule
37
+ * pv_properties
38
+ * is_construction_set_on_object
39
+ """
40
+
41
+ __slots__ = ('_host', '_construction', '_transmittance_schedule', '_pv_properties')
42
+
43
+ def __init__(self, host, construction=None, transmittance_schedule=None,
44
+ pv_properties=None):
45
+ """Initialize Shade energy properties."""
46
+ self._host = host
47
+ self.construction = construction
48
+ self.transmittance_schedule = transmittance_schedule
49
+ self.pv_properties = pv_properties
50
+
51
+ @property
52
+ def host(self):
53
+ """Get the Shade object hosting these properties."""
54
+ return self._host
55
+
56
+ @property
57
+ def construction(self):
58
+ """Get or set a ShadeConstruction for the shade.
59
+
60
+ If the construction is not set on the shade-level, then it will be assigned
61
+ based on the ConstructionSet assigned to the parent Room. If the parent Room's
62
+ ConstructionSet has no construction for the Shade type, it will be assigned
63
+ using the honeybee default generic ConstructionSet. If there is no parent
64
+ Room, it will be the generic context construction.
65
+ """
66
+ if self._construction: # set by user
67
+ return self._construction
68
+ elif not self._host.has_parent:
69
+ return generic_context if self._host.is_detached else \
70
+ generic_construction_set.shade_construction
71
+ else:
72
+ c_set = self._parent_construction_set(self._host.parent)
73
+ if c_set is None:
74
+ c_set = generic_construction_set
75
+ return c_set.shade_construction
76
+
77
+ @construction.setter
78
+ def construction(self, value):
79
+ if value is not None:
80
+ assert isinstance(value, ShadeConstruction), \
81
+ 'Expected ShadeConstruction. Got {}.'.format(type(value))
82
+ value.lock() # lock editing in case construction has multiple references
83
+ self._construction = value
84
+
85
+ @property
86
+ def transmittance_schedule(self):
87
+ """Get or set the transmittance schedule of the shade."""
88
+ return self._transmittance_schedule
89
+
90
+ @transmittance_schedule.setter
91
+ def transmittance_schedule(self, value):
92
+ if value is not None:
93
+ assert isinstance(value, (ScheduleRuleset, ScheduleFixedInterval)), \
94
+ 'Expected schedule for shade transmittance schedule. ' \
95
+ 'Got {}.'.format(type(value))
96
+ if value.schedule_type_limit is not None:
97
+ assert value.schedule_type_limit.unit == 'fraction', 'Transmittance ' \
98
+ 'schedule should be fractional [Dimensionless]. Got a schedule ' \
99
+ 'of unit_type [{}].'.format(value.schedule_type_limit.unit_type)
100
+ value.lock() # lock editing in case schedule has multiple references
101
+ self._transmittance_schedule = value
102
+
103
+ @property
104
+ def pv_properties(self):
105
+ """Get or set a PVProperties object for photovoltaic behavior of the Shade."""
106
+ return self._pv_properties
107
+
108
+ @pv_properties.setter
109
+ def pv_properties(self, value):
110
+ if value is not None:
111
+ assert isinstance(value, PVProperties), \
112
+ 'Expected PVProperties. Got {}.'.format(type(value))
113
+ value.lock() # lock editing in case construction has multiple references
114
+ self._pv_properties = value
115
+
116
+ @property
117
+ def is_construction_set_on_object(self):
118
+ """Boolean noting if construction is assigned on the level of this Shade.
119
+
120
+ This is opposed to having the construction assigned by a ConstructionSet.
121
+ """
122
+ return self._construction is not None
123
+
124
+ def reset_construction_to_set(self):
125
+ """Reset the construction and transmittance schedule of this Shade to default.
126
+
127
+ This means that the Shade's construction will be assigned by a ConstructionSet.
128
+ """
129
+ self._construction = None
130
+ self._transmittance_schedule = None
131
+
132
+ def radiance_modifier_solar(self):
133
+ """Get a Radiance modifier that combines the construction and transmittance.
134
+
135
+ Note that only the first value from the transmittance schedule will be used
136
+ to create the Trans modifier and so this method is really only intended for
137
+ cases of constant transmittance schedules. If there is no transmittance
138
+ schedule, a plastic material will be returned.
139
+ """
140
+ return self._radiance_modifier(self.construction.solar_reflectance)
141
+
142
+ def radiance_modifier_visible(self):
143
+ """Get a Radiance modifier that combines the construction and transmittance.
144
+
145
+ Note that only the first value from the transmittance schedule will be used
146
+ to create the Trans modifier and so this method is really only intended for
147
+ cases of constant transmittance schedules. If there is no transmittance
148
+ schedule, a plastic material will be returned.
149
+ """
150
+ return self._radiance_modifier(self.construction.visible_reflectance)
151
+
152
+ @classmethod
153
+ def from_dict(cls, data, host):
154
+ """Create ShadeEnergyProperties from a dictionary.
155
+
156
+ Note that the dictionary must be a non-abridged version for this
157
+ classmethod to work.
158
+
159
+ Args:
160
+ data: A dictionary representation of ShadeEnergyProperties with the
161
+ format below.
162
+ host: A Shade object that hosts these properties.
163
+
164
+ .. code-block:: python
165
+
166
+ {
167
+ "type": 'ShadeEnergyProperties',
168
+ "construction": {}, # A ShadeConstruction dictionary
169
+ "transmittance_schedule": {}, # A transmittance schedule dictionary
170
+ "pv_properties": {} # A PVProperties dictionary
171
+ }
172
+ """
173
+ assert data['type'] == 'ShadeEnergyProperties', \
174
+ 'Expected ShadeEnergyProperties. Got {}.'.format(data['type'])
175
+
176
+ new_prop = cls(host)
177
+ if 'construction' in data and data['construction'] is not None:
178
+ new_prop.construction = ShadeConstruction.from_dict(data['construction'])
179
+ if 'transmittance_schedule' in data and \
180
+ data['transmittance_schedule'] is not None:
181
+ sch_dict = data['transmittance_schedule']
182
+ if sch_dict['type'] == 'ScheduleRuleset':
183
+ new_prop.transmittance_schedule = \
184
+ ScheduleRuleset.from_dict(data['transmittance_schedule'])
185
+ elif sch_dict['type'] == 'ScheduleFixedInterval':
186
+ new_prop.transmittance_schedule = \
187
+ ScheduleFixedInterval.from_dict(data['transmittance_schedule'])
188
+ else:
189
+ raise ValueError(
190
+ 'Expected non-abridged Schedule dictionary for Shade '
191
+ 'transmittance_schedule. Got {}.'.format(sch_dict['type']))
192
+ if 'pv_properties' in data and data['pv_properties'] is not None:
193
+ new_prop.pv_properties = PVProperties.from_dict(data['pv_properties'])
194
+ return new_prop
195
+
196
+ def apply_properties_from_dict(self, abridged_data, constructions, schedules):
197
+ """Apply properties from a ShadeEnergyPropertiesAbridged dictionary.
198
+
199
+ Args:
200
+ abridged_data: A ShadeEnergyPropertiesAbridged dictionary (typically
201
+ coming from a Model).
202
+ constructions: A dictionary of constructions with constructions identifiers
203
+ as keys, which will be used to re-assign constructions.
204
+ schedules: A dictionary of schedules with schedule identifiers as keys,
205
+ which will be used to re-assign schedules.
206
+ """
207
+ if 'construction' in abridged_data and abridged_data['construction'] is not None:
208
+ try:
209
+ self.construction = constructions[abridged_data['construction']]
210
+ except KeyError:
211
+ raise ValueError('Shade construction "{}" was not found in '
212
+ 'constructions.'.format(abridged_data['construction']))
213
+ if 'transmittance_schedule' in abridged_data and \
214
+ abridged_data['transmittance_schedule'] is not None:
215
+ self.transmittance_schedule = \
216
+ schedules[abridged_data['transmittance_schedule']]
217
+ if 'pv_properties' in abridged_data and \
218
+ abridged_data['pv_properties'] is not None:
219
+ self.pv_properties = PVProperties.from_dict(abridged_data['pv_properties'])
220
+
221
+ def to_dict(self, abridged=False):
222
+ """Return energy properties as a dictionary.
223
+
224
+ Args:
225
+ abridged: Boolean to note whether the full dictionary describing the
226
+ object should be returned (False) or just an abridged version (True).
227
+ Default: False.
228
+ """
229
+ base = {'energy': {}}
230
+ base['energy']['type'] = 'ShadeEnergyProperties' if not \
231
+ abridged else 'ShadeEnergyPropertiesAbridged'
232
+ if self._construction is not None:
233
+ base['energy']['construction'] = \
234
+ self._construction.identifier if abridged else \
235
+ self._construction.to_dict()
236
+ if self.transmittance_schedule is not None:
237
+ base['energy']['transmittance_schedule'] = \
238
+ self.transmittance_schedule.identifier if abridged else \
239
+ self.transmittance_schedule.to_dict()
240
+ if self.pv_properties is not None:
241
+ base['energy']['pv_properties'] = self.pv_properties.to_dict()
242
+ return base
243
+
244
+ def duplicate(self, new_host=None):
245
+ """Get a copy of this object.
246
+
247
+ Args:
248
+ new_host: A new Shade object that hosts these properties.
249
+ If None, the properties will be duplicated with the same host.
250
+ """
251
+ _host = new_host or self._host
252
+ return ShadeEnergyProperties(
253
+ _host, self._construction, self._transmittance_schedule, self._pv_properties)
254
+
255
+ def is_equivalent(self, other):
256
+ """Check to see if these energy properties are equivalent to another object.
257
+
258
+ This will only be True if all properties match (except for the host) and
259
+ will otherwise be False.
260
+ """
261
+ if not is_equivalent(self._construction, other._construction):
262
+ return False
263
+ if not is_equivalent(
264
+ self._transmittance_schedule, other._transmittance_schedule):
265
+ return False
266
+ if not is_equivalent(self._pv_properties, other._pv_properties):
267
+ return False
268
+ return True
269
+
270
+ def _radiance_modifier(self, ref):
271
+ """Get a Radiance modifier that respects the transmittance schedule.
272
+
273
+ Args:
274
+ ref: The reflectance to be used in the modifier.
275
+ """
276
+ # check to be sure that the honeybee-radiance installed
277
+ try:
278
+ from honeybee_radiance.modifier.material import Trans
279
+ except ImportError as e:
280
+ raise ImportError('honeybee_radiance library must be installed to use '
281
+ 'Shade radiance_modifier methods. {}'.format(e))
282
+
283
+ # create the modifier from the properties
284
+ if self.transmittance_schedule is None:
285
+ return self.construction._to_radiance(ref)
286
+ else:
287
+ mod_id = '{}_mod'.format(clean_rad_string(self.host.identifier))
288
+ if isinstance(self.transmittance_schedule, ScheduleRuleset):
289
+ trans = self.transmittance_schedule.default_day_schedule.values[0]
290
+ else:
291
+ trans = self.transmittance_schedule.values[0]
292
+ avg_ref = (1 - trans) * ref
293
+ return Trans.from_average_properties(
294
+ mod_id, average_reflectance=avg_ref, average_transmittance=trans,
295
+ is_specular=self.construction.is_specular, is_diffusing=False)
296
+
297
+ @staticmethod
298
+ def _parent_construction_set(host_parent):
299
+ """Recursively search through host parents to find a ConstructionSet."""
300
+ if hasattr(host_parent.properties.energy, 'construction_set'):
301
+ # we found the room with the construction set
302
+ return host_parent.properties.energy.construction_set
303
+ elif host_parent.has_parent:
304
+ # we found an aperture or face that could have a room with a construction set
305
+ return ShadeEnergyProperties._parent_construction_set(host_parent.parent)
306
+ else:
307
+ # there is no parent room
308
+ return None
309
+
310
+ def ToString(self):
311
+ return self.__repr__()
312
+
313
+ def __repr__(self):
314
+ return 'Shade Energy Properties: [host: {}]'.format(self.host.display_name)
@@ -0,0 +1,262 @@
1
+ # coding=utf-8
2
+ """Shade Energy Properties."""
3
+ from honeybee.typing import clean_rad_string
4
+ from honeybee.checkdup import is_equivalent
5
+
6
+ from ..construction.shade import ShadeConstruction
7
+ from ..schedule.ruleset import ScheduleRuleset
8
+ from ..schedule.fixedinterval import ScheduleFixedInterval
9
+
10
+ from ..lib.constructions import generic_context
11
+ from ..lib.constructionsets import generic_construction_set
12
+
13
+
14
+ class ShadeMeshEnergyProperties(object):
15
+ """Energy Properties for Honeybee ShadeMesh.
16
+
17
+ Args:
18
+ host: A honeybee_core ShadeMesh object that hosts these properties.
19
+ construction: An optional ShadeConstruction object to set the reflectance
20
+ and specularity of the Shade. If None, it will be a generic context
21
+ construction that is completely diffuse with 0.2 visible and solar
22
+ reflectance. Unless it is building attached, in which case it will be
23
+ set by the default generic ConstructionSet.
24
+ transmittance_schedule: An optional schedule to set the transmittance
25
+ of the shade, which can vary throughout the day or year. Default
26
+ is None for a completely opaque object.
27
+
28
+ Properties:
29
+ * host
30
+ * construction
31
+ * transmittance_schedule
32
+ * is_construction_set_on_object
33
+ """
34
+
35
+ __slots__ = ('_host', '_construction', '_transmittance_schedule')
36
+
37
+ def __init__(self, host, construction=None, transmittance_schedule=None):
38
+ """Initialize ShadeMesh energy properties."""
39
+ self._host = host
40
+ self.construction = construction
41
+ self.transmittance_schedule = transmittance_schedule
42
+
43
+ @property
44
+ def host(self):
45
+ """Get the ShadeMesh object hosting these properties."""
46
+ return self._host
47
+
48
+ @property
49
+ def construction(self):
50
+ """Get or set a ShadeConstruction for the shade mesh object.
51
+
52
+ If the construction is not set on the shade-level, then it will be the
53
+ generic context construction or the generic exterior shade construction
54
+ if it is not detached.
55
+ """
56
+ if self._construction: # set by user
57
+ return self._construction
58
+ return generic_context if self._host.is_detached else \
59
+ generic_construction_set.shade_construction
60
+
61
+ @construction.setter
62
+ def construction(self, value):
63
+ if value is not None:
64
+ assert isinstance(value, ShadeConstruction), \
65
+ 'Expected ShadeConstruction. Got {}.'.format(type(value))
66
+ value.lock() # lock editing in case construction has multiple references
67
+ self._construction = value
68
+
69
+ @property
70
+ def transmittance_schedule(self):
71
+ """Get or set the transmittance schedule of the shade."""
72
+ return self._transmittance_schedule
73
+
74
+ @transmittance_schedule.setter
75
+ def transmittance_schedule(self, value):
76
+ if value is not None:
77
+ assert isinstance(value, (ScheduleRuleset, ScheduleFixedInterval)), \
78
+ 'Expected schedule for shade mesh transmittance schedule. ' \
79
+ 'Got {}.'.format(type(value))
80
+ if value.schedule_type_limit is not None:
81
+ assert value.schedule_type_limit.unit == 'fraction', 'Transmittance ' \
82
+ 'schedule should be fractional [Dimensionless]. Got a schedule ' \
83
+ 'of unit_type [{}].'.format(value.schedule_type_limit.unit_type)
84
+ value.lock() # lock editing in case schedule has multiple references
85
+ self._transmittance_schedule = value
86
+
87
+ @property
88
+ def is_construction_set_on_object(self):
89
+ """Boolean noting if construction is assigned on the level of this Shade.
90
+
91
+ This is opposed to having the construction assigned by a ConstructionSet.
92
+ """
93
+ return self._construction is not None
94
+
95
+ def reset_construction_to_set(self):
96
+ """Reset the construction and transmittance schedule of this Shade to default.
97
+
98
+ This means that the Shade's construction will be assigned by a ConstructionSet.
99
+ """
100
+ self._construction = None
101
+ self._transmittance_schedule = None
102
+
103
+ def radiance_modifier_solar(self):
104
+ """Get a Radiance modifier that combines the construction and transmittance.
105
+
106
+ Note that only the first value from the transmittance schedule will be used
107
+ to create the Trans modifier and so this method is really only intended for
108
+ cases of constant transmittance schedules. If there is no transmittance
109
+ schedule, a plastic material will be returned.
110
+ """
111
+ return self._radiance_modifier(self.construction.solar_reflectance)
112
+
113
+ def radiance_modifier_visible(self):
114
+ """Get a Radiance modifier that combines the construction and transmittance.
115
+
116
+ Note that only the first value from the transmittance schedule will be used
117
+ to create the Trans modifier and so this method is really only intended for
118
+ cases of constant transmittance schedules. If there is no transmittance
119
+ schedule, a plastic material will be returned.
120
+ """
121
+ return self._radiance_modifier(self.construction.visible_reflectance)
122
+
123
+ @classmethod
124
+ def from_dict(cls, data, host):
125
+ """Create ShadeMeshEnergyProperties from a dictionary.
126
+
127
+ Note that the dictionary must be a non-abridged version for this
128
+ classmethod to work.
129
+
130
+ Args:
131
+ data: A dictionary representation of ShadeMeshEnergyProperties with the
132
+ format below.
133
+ host: A Shade object that hosts these properties.
134
+
135
+ .. code-block:: python
136
+
137
+ {
138
+ "type": 'ShadeMeshEnergyProperties',
139
+ "construction": {}, # A ShadeConstruction dictionary
140
+ "transmittance_schedule": {} # A transmittance schedule dictionary
141
+ }
142
+ """
143
+ assert data['type'] == 'ShadeMeshEnergyProperties', \
144
+ 'Expected ShadeMeshEnergyProperties. Got {}.'.format(data['type'])
145
+
146
+ new_prop = cls(host)
147
+ if 'construction' in data and data['construction'] is not None:
148
+ new_prop.construction = ShadeConstruction.from_dict(data['construction'])
149
+ if 'transmittance_schedule' in data and \
150
+ data['transmittance_schedule'] is not None:
151
+ sch_dict = data['transmittance_schedule']
152
+ if sch_dict['type'] == 'ScheduleRuleset':
153
+ new_prop.transmittance_schedule = \
154
+ ScheduleRuleset.from_dict(data['transmittance_schedule'])
155
+ elif sch_dict['type'] == 'ScheduleFixedInterval':
156
+ new_prop.transmittance_schedule = \
157
+ ScheduleFixedInterval.from_dict(data['transmittance_schedule'])
158
+ else:
159
+ raise ValueError(
160
+ 'Expected non-abridged Schedule dictionary for Shade '
161
+ 'transmittance_schedule. Got {}.'.format(sch_dict['type']))
162
+ return new_prop
163
+
164
+ def apply_properties_from_dict(self, abridged_data, constructions, schedules):
165
+ """Apply properties from a ShadeMeshEnergyPropertiesAbridged dictionary.
166
+
167
+ Args:
168
+ abridged_data: A ShadeMeshEnergyPropertiesAbridged dictionary (typically
169
+ coming from a Model).
170
+ constructions: A dictionary of constructions with constructions identifiers
171
+ as keys, which will be used to re-assign constructions.
172
+ schedules: A dictionary of schedules with schedule identifiers as keys,
173
+ which will be used to re-assign schedules.
174
+ """
175
+ if 'construction' in abridged_data and abridged_data['construction'] is not None:
176
+ try:
177
+ self.construction = constructions[abridged_data['construction']]
178
+ except KeyError:
179
+ raise ValueError('Shade construction "{}" was not found in '
180
+ 'constructions.'.format(abridged_data['construction']))
181
+ if 'transmittance_schedule' in abridged_data and \
182
+ abridged_data['transmittance_schedule'] is not None:
183
+ self.transmittance_schedule = \
184
+ schedules[abridged_data['transmittance_schedule']]
185
+
186
+ def to_dict(self, abridged=False):
187
+ """Return energy properties as a dictionary.
188
+
189
+ Args:
190
+ abridged: Boolean to note whether the full dictionary describing the
191
+ object should be returned (False) or just an abridged version (True).
192
+ Default: False.
193
+ """
194
+ base = {'energy': {}}
195
+ base['energy']['type'] = 'ShadeMeshEnergyProperties' if not \
196
+ abridged else 'ShadeMeshEnergyPropertiesAbridged'
197
+ if self._construction is not None:
198
+ base['energy']['construction'] = \
199
+ self._construction.identifier if abridged else \
200
+ self._construction.to_dict()
201
+ if self.transmittance_schedule is not None:
202
+ base['energy']['transmittance_schedule'] = \
203
+ self.transmittance_schedule.identifier if abridged else \
204
+ self.transmittance_schedule.to_dict()
205
+ return base
206
+
207
+ def duplicate(self, new_host=None):
208
+ """Get a copy of this object.
209
+
210
+ Args:
211
+ new_host: A new Shade object that hosts these properties.
212
+ If None, the properties will be duplicated with the same host.
213
+ """
214
+ _host = new_host or self._host
215
+ return ShadeMeshEnergyProperties(
216
+ _host, self._construction, self._transmittance_schedule)
217
+
218
+ def is_equivalent(self, other):
219
+ """Check to see if these energy properties are equivalent to another object.
220
+
221
+ This will only be True if all properties match (except for the host) and
222
+ will otherwise be False.
223
+ """
224
+ if not is_equivalent(self._construction, other._construction):
225
+ return False
226
+ if not is_equivalent(
227
+ self._transmittance_schedule, other._transmittance_schedule):
228
+ return False
229
+ return True
230
+
231
+ def _radiance_modifier(self, ref):
232
+ """Get a Radiance modifier that respects the transmittance schedule.
233
+
234
+ Args:
235
+ ref: The reflectance to be used in the modifier.
236
+ """
237
+ # check to be sure that the honeybee-radiance installed
238
+ try:
239
+ from honeybee_radiance.modifier.material import Trans
240
+ except ImportError as e:
241
+ raise ImportError('honeybee_radiance library must be installed to use '
242
+ 'Shade radiance_modifier methods. {}'.format(e))
243
+
244
+ # create the modifier from the properties
245
+ if self.transmittance_schedule is None:
246
+ return self.construction._to_radiance(ref)
247
+ else:
248
+ mod_id = '{}_mod'.format(clean_rad_string(self.host.identifier))
249
+ if isinstance(self.transmittance_schedule, ScheduleRuleset):
250
+ trans = self.transmittance_schedule.default_day_schedule.values[0]
251
+ else:
252
+ trans = self.transmittance_schedule.values[0]
253
+ avg_ref = (1 - trans) * ref
254
+ return Trans.from_average_properties(
255
+ mod_id, average_reflectance=avg_ref, average_transmittance=trans,
256
+ is_specular=self.construction.is_specular, is_diffusing=False)
257
+
258
+ def ToString(self):
259
+ return self.__repr__()
260
+
261
+ def __repr__(self):
262
+ return 'ShadeMesh Energy Properties: [host: {}]'.format(self.host.display_name)
@@ -0,0 +1,48 @@
1
+ """Methods to read from idf."""
2
+ import re
3
+ import os
4
+
5
+
6
+ def clean_idf_file_contents(idf_file):
7
+ """Get the contents of an IDF file without any commented lines.
8
+
9
+ These comment lines might interfere with regex parsing if they are present.
10
+
11
+ Args:
12
+ idf_file: A path to an IDF file containing objects to be parsed.
13
+
14
+ Returns:
15
+ A single string for the clean IDF file contents.
16
+ """
17
+ assert os.path.isfile(idf_file), 'Cannot find an idf file at {}'.format(idf_file)
18
+ file_lines = []
19
+ with open(idf_file, 'r') as ep_file:
20
+ for line in ep_file:
21
+ if not line.startswith('!'):
22
+ file_lines.append(line)
23
+ return ''.join(file_lines)
24
+
25
+
26
+ def parse_idf_string(idf_string, expected_type=None):
27
+ """Parse an EnergyPlus string of a single object into a list of values.
28
+
29
+ Args:
30
+ idf_string: An IDF string for a single EnergyPlus object.
31
+ expected_type: Text representing the expected start of the IDF object.
32
+ (ie. WindowMaterial:Glazing). If None, no type check will be performed.
33
+
34
+ Returns:
35
+ ep_fields -- A list of strings with each item in the list as a separate field.
36
+ Note that this list does NOT include the string for the start of the IDF
37
+ object. (ie. WindowMaterial:Glazing)
38
+ """
39
+ idf_string = idf_string.strip()
40
+ if expected_type is not None:
41
+ assert idf_string.startswith(expected_type), 'Expected EnergyPlus {} ' \
42
+ 'but received a different object: {}'.format(expected_type, idf_string)
43
+ idf_strings = idf_string.split(';')
44
+ assert len(idf_strings) == 2, 'Received more than one object in idf_string.'
45
+ idf_string = re.sub(r'!.*\n', '', idf_strings[0])
46
+ ep_fields = [e_str.strip() for e_str in idf_string.split(',')]
47
+ ep_fields.pop(0) # remove the EnergyPlus object name
48
+ return ep_fields
@@ -0,0 +1 @@
1
+ """honeybee-energy simulation settings."""