dragonfly-doe2 0.11.3__py2.py3-none-any.whl → 0.12.1__py2.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.
@@ -1,44 +0,0 @@
1
- from dataclasses import dataclass
2
- from enum import Enum
3
- from typing import Union
4
-
5
- from honeybee_energy.construction.window import WindowConstruction
6
- from honeybee_energy.material.glazing import EnergyWindowMaterialGlazing, \
7
- EnergyWindowMaterialSimpleGlazSys
8
-
9
- from honeybee_energy.construction.window import WindowConstruction
10
-
11
- from .utils import short_name, unit_convertor
12
-
13
-
14
- @dataclass
15
- class GlassType:
16
- """ Doe2 glass type, (window construction) """
17
- name: str
18
- shading_coef: float
19
- glass_cond: float
20
-
21
- @classmethod
22
- def from_hb_window_constr(cls, window_constr: WindowConstruction):
23
- simple_window_con = window_constr.to_simple_construction()
24
- simple_window_mat = simple_window_con.materials[0]
25
-
26
- shading_coef = simple_window_mat.shgc / 0.87
27
-
28
- glass_cond = unit_convertor(
29
- [simple_window_mat.u_factor], 'Btu/h-ft2-F', 'W/m2-K')
30
-
31
- name = simple_window_con.identifier
32
- name = short_name(name, 32)
33
-
34
- return cls(name=name, shading_coef=shading_coef, glass_cond=glass_cond)
35
-
36
- def to_inp(self) -> str:
37
- return f'"{self.name}" = GLASS-TYPE\n' \
38
- f' TYPE = SHADING-COEF\n' \
39
- f' SHADING-COEF = {self.shading_coef}\n' \
40
- f' GLASS-CONDUCT = {self.glass_cond}\n' \
41
- f' ..'
42
-
43
- def __repr__(self):
44
- return self.to_inp()
@@ -1,96 +0,0 @@
1
- from dragonfly.story import Story as DFStory
2
- from dragonfly.room2d import Room2D as DFRoom
3
- from .utils import short_name
4
- from dataclasses import dataclass
5
- from typing import List
6
-
7
- # TODO: I don't like the disconnect between this MO and the 'floor_space'
8
- # TODO: Classes, on refactor; need more OOP for sure, this 'lesser oopy'
9
- # TODO: be getting confusing and there is obvious shared atrib/props
10
- # TODO: that should be linked to prevent breakage, possibly from doe objs
11
- # TODO: instead of df objs? as a temp means?
12
-
13
-
14
- @dataclass
15
- class Zone:
16
- """A doe2 'Zone' object from dragonfly Room2D.
17
- Args:
18
- name: room display name
19
- heating_setpoint: heating setpoint temperature (*F) eQuest default of 72*F if no
20
- setpoint found in DF room2D program
21
- cooling_setpoint: cooling setpoint temperature (*F) eQuest default of 75*F if no
22
- setpoint found in DF room2D program
23
- Init method(s):
24
- 1. from_room(room: DFRoom)-> doe_zone:
25
- """
26
- name: str
27
- heating_setpoint: float
28
- cooling_setpoint: float
29
-
30
- @classmethod
31
- def from_room(cls, room: DFRoom):
32
- if not isinstance(room, DFRoom):
33
- raise ValueError(
34
- f'Unsupported type: {type(room)}\n'
35
- 'Expected dragonfly.room2d.Room2D'
36
- )
37
-
38
- name = room.display_name
39
- if room.properties.energy.is_conditioned:
40
- heating_setpoint = room.properties.energy.program_type.setpoint.heating_setpoint
41
- cooling_setpoint = room.properties.energy.program_type.setpoint.cooling_setpoint
42
- else:
43
- heating_setpoint = 72
44
- cooling_setpoint = 75
45
-
46
- return cls(name=name, heating_setpoint=heating_setpoint,
47
- cooling_setpoint=cooling_setpoint)
48
-
49
- def to_inp(self):
50
- inp_str = f'"{self.name} Zn" = ZONE\n ' \
51
- 'TYPE = UNCONDITIONED\n ' \
52
- f'DESIGN-HEAT-T = {self.heating_setpoint}\n ' \
53
- f'DESIGN-COOL-T = {self.cooling_setpoint}\n ' \
54
- 'SIZING-OPTION = ADJUST-LOADS\n ' \
55
- f'SPACE = "{self.name}"\n ..\n'
56
- return inp_str
57
-
58
- def __repr__(self) -> str:
59
- return self.to_inp()
60
-
61
-
62
- @dataclass
63
- class HVACSystem:
64
- """Placeholder HVAC system class, returns each floor as a doe2,
65
- HVAC system, with rooms as zones.
66
- Args:
67
- name: story display name
68
- zones: list of doe2.hvac.Zone objects serviced by the system
69
- Init method(s):
70
- 1. from_story(story: DFStory) -> doe2_system:
71
- """
72
- name: str
73
- zones: List[Zone]
74
-
75
- @classmethod
76
- def from_story(cls, story: DFStory):
77
- if not isinstance(story, DFStory):
78
- raise ValueError(
79
- f'Unsupported type: {type(story)}\n'
80
- 'Expected dragonfly.story.Story'
81
- )
82
- name = story.display_name
83
- zones = [Zone.from_room(room) for room in story.room_2ds]
84
- return cls(name=name, zones=zones)
85
-
86
- def to_inp(self):
87
- sys_str = f'"{self.name}flr_Sys (SUM)" = SYSTEM\n' \
88
- ' TYPE = SUM\n' \
89
- ' HEAT-SOURCE = NONE\n' \
90
- ' SYSTEM-REPORTS = NO\n ..\n'
91
- zones_str = '\n'.join(zone.to_inp() for zone in self.zones)
92
- inp_str = '\n'.join([sys_str, zones_str])
93
- return inp_str
94
-
95
- def __repr__(self):
96
- return self.to_inp()
@@ -1,84 +0,0 @@
1
- from dataclasses import dataclass
2
- from enum import Enum
3
- from typing import Union
4
-
5
- from honeybee_energy.material.opaque import EnergyMaterial, EnergyMaterialNoMass
6
- from .utils import short_name, unit_convertor
7
-
8
-
9
- class MaterialType(Enum):
10
- """Doe2 material types."""
11
- mass = 'PROPERTIES'
12
- no_mass = 'RESISTANCE'
13
-
14
-
15
- @dataclass
16
- class NoMassMaterial:
17
- name: str
18
- resistance: float
19
-
20
- @classmethod
21
- def from_hb_material(cls, material: EnergyMaterialNoMass):
22
- resistance = unit_convertor([material.r_value], 'h-ft2-F/Btu', 'm2-K/W')
23
- return cls(short_name(material.display_name, 32), resistance)
24
-
25
- def to_inp(self):
26
- return f'"{self.name}" = MATERIAL\n' \
27
- f' TYPE = {MaterialType.no_mass.value}\n' \
28
- f' RESISTANCE = {self.resistance}\n' \
29
- ' ..'
30
-
31
-
32
- @dataclass
33
- class MassMaterial:
34
-
35
- name: str
36
- thickness: float
37
- conductivity: str
38
- density: float
39
- specific_heat: float
40
-
41
- @classmethod
42
- def from_hb_material(cls, material: EnergyMaterial):
43
- name = short_name(material.display_name, 32)
44
- thickness = unit_convertor([material.thickness], 'ft', 'm')
45
- conductivity = unit_convertor([material.conductivity], 'Btu/h-ft2', 'W/m2')
46
- density = round(material.density / 16.018, 3)
47
- specific_heat = unit_convertor([material.specific_heat], 'Btu/lb', 'J/kg')
48
- return cls(
49
- name, thickness, conductivity, density, specific_heat
50
- )
51
-
52
- def to_inp(self):
53
- return f'"{self.name}" = MATERIAL\n' \
54
- f' TYPE = {MaterialType.mass.value}\n' \
55
- f' THICKNESS = {self.thickness}\n' \
56
- f' CONDUCTIVITY = {self.conductivity}\n' \
57
- f' DENSITY = {self.density}\n' \
58
- f' SPECIFIC-HEAT = {self.specific_heat}\n' \
59
- ' ..'
60
-
61
-
62
- @dataclass
63
- class Material:
64
- """Do2 Material object.
65
-
66
- refer to:
67
- assets/DOE22Vol2-Dictionary_48r.pdf pg: 97
68
- """
69
- material: Union[NoMassMaterial, MassMaterial]
70
-
71
- @classmethod
72
- def from_hb_material(cls, material: Union[EnergyMaterial, EnergyMaterialNoMass]):
73
- if isinstance(material, EnergyMaterial):
74
- return MassMaterial.from_hb_material(material)
75
- elif isinstance(material, EnergyMaterialNoMass):
76
- return NoMassMaterial.from_hb_material(material)
77
- else:
78
- raise ValueError(f'{type(material)} type is not supported for materials.')
79
-
80
- def to_inp(self) -> str:
81
- return self.material.to_inp()
82
-
83
- def __repr__(self):
84
- return self.to_inp()
@@ -1,276 +0,0 @@
1
- from typing import List
2
-
3
- from dragonfly.model import Model as DFModel
4
- from dragonfly.story import Story as DFStory
5
- from dragonfly.room2d import Room2D as DFRoom
6
-
7
- from ladybug.analysisperiod import AnalysisPeriod
8
-
9
- from honeybee_energy.construction.window import WindowConstruction
10
- from honeybee_energy.lib.constructionsets import generic_construction_set
11
-
12
- from .polygon import Polygon
13
- from .compliance import ComplianceData
14
- from .sitebldg import SiteBldgData
15
- from .title import Title
16
- from .run_period import RunPeriod
17
- from .construction import Construction, ConstructionCollection
18
- from .floor_space import Floor
19
- from .glass_types import GlassType
20
- from .shades import Doe2ShadeCollection
21
- from .hvac import HVACSystem
22
-
23
- from . import blocks as fb
24
-
25
-
26
- class Model:
27
- """A DOE *.inp Model File Object."""
28
-
29
- def __init__(self, title, run_period=None, compliance_data=None,
30
- site_building_data=None, polygons=None, constructions=None, floors=None,
31
- glass_types=None, context_shades=None, hvac_system_zone=None) -> None:
32
- self.title = title
33
- self.run_period = run_period
34
- self.compliance_data = compliance_data
35
- self.site_bldg_data = site_building_data
36
- self.polygons = polygons
37
- self.constructions = constructions
38
- self.floors = floors
39
- self.glass_types = glass_types
40
- self.context_shades = context_shades
41
- self.hvac_system_zone = hvac_system_zone
42
-
43
- @classmethod
44
- def from_df_model(cls, df_model: DFModel, run_period=None):
45
- # Make model windows rectangular to be INP friendly
46
- df_model.to_rectangular_windows()
47
-
48
- # Check model units, ensure units in feet
49
- df_model.convert_to_units(units='Feet')
50
- df_model.properties.energy.construction_sets.append(generic_construction_set)
51
-
52
- polygons = []
53
- flr_spc = []
54
- window_constructions = []
55
- context_shades = []
56
- hvac_system_zone = []
57
-
58
- window_constructions.append(
59
- generic_construction_set.aperture_set.window_construction)
60
-
61
- for con_set in df_model.properties.energy.construction_sets:
62
- window_constructions.append(con_set.aperture_set.window_construction)
63
-
64
- # purge duplicate window constructions
65
- window_constructions = list(set(window_constructions))
66
-
67
- for building in df_model.buildings:
68
- for story in building.all_stories():
69
- # enforce a recompute of floor to floor height
70
- if story.floor_to_floor_height == 0:
71
- story.floor_to_floor_height = None
72
-
73
- story.solve_room_2d_adjacency(df_model.tolerance, intersect=True)
74
-
75
- hvac_system_zone.append(HVACSystem.from_story(story))
76
-
77
- flr_spc.append(Floor.from_story(story))
78
- polygons.append(Polygon.from_story(story))
79
- for room in story:
80
- polygons.append(Polygon.from_room(room))
81
-
82
- df_envelope_constrs = []
83
- for con in generic_construction_set.wall_set.constructions:
84
- df_envelope_constrs.append(con)
85
- for con in generic_construction_set.floor_set.constructions:
86
- df_envelope_constrs.append(con)
87
- for con in generic_construction_set.roof_ceiling_set:
88
- df_envelope_constrs.append(con)
89
- # TODO: This messy MO takes the un-needed door constructions out of the equation
90
- # TODO: Make more elegant when implements "to thin, make u-val"
91
- for construction_set in df_model.properties.energy.construction_sets:
92
- for con in construction_set.wall_set.constructions:
93
- df_envelope_constrs.append(con)
94
- for con in generic_construction_set.wall_set.constructions:
95
- df_envelope_constrs.append(con)
96
- for con in construction_set.floor_set.constructions:
97
- df_envelope_constrs.append(con)
98
- for con in construction_set.roof_ceiling_set:
99
- df_envelope_constrs.append(con)
100
-
101
- constructions = ConstructionCollection.from_hb_constructions(
102
- df_envelope_constrs)
103
-
104
- glass_types = [GlassType.from_hb_window_constr(
105
- w_con) for w_con in window_constructions]
106
-
107
- shade_objs = df_model.context_shades
108
- context_shades.append(Doe2ShadeCollection.from_df_context_shades(shade_objs))
109
-
110
- return cls(
111
- df_model.display_name, run_period, polygons=polygons,
112
- constructions=constructions, floors=flr_spc, glass_types=glass_types,
113
- context_shades=context_shades, hvac_system_zone=hvac_system_zone)
114
-
115
- @classmethod
116
- def from_dfjson(cls, dfjson_file, run_period=None):
117
- model = DFModel.from_dfjson(dfjson_file)
118
- return cls.from_df_model(model, run_period)
119
-
120
- @property
121
- def _header(self):
122
- """File header.
123
-
124
- NOTE: The header is currently read-only
125
- """
126
- return '\n'.join([fb.top_level, fb.abort_diag])
127
-
128
- @property
129
- def title(self):
130
- return self._title
131
-
132
- @title.setter
133
- def title(self, value):
134
- self._title = Title(value)
135
- # update the title in complinace data
136
- try:
137
- self.compliance_data.proj_name = value
138
- except AttributeError:
139
- # this happens on initiation since compliance data is not set yet
140
- # we can ignore it
141
- pass
142
-
143
- @property
144
- def run_period(self):
145
- """Model run period."""
146
- return self._run_period
147
-
148
- @run_period.setter
149
- def run_period(self, value: AnalysisPeriod):
150
- self._run_period = RunPeriod.from_analysis_period(value)
151
-
152
- @property
153
- def compliance_data(self):
154
- """Model DOE2 Compliance Data"""
155
- return self._compliance_data
156
-
157
- @compliance_data.setter
158
- def compliance_data(self, value):
159
- if not value:
160
- value = ComplianceData()
161
- # make sure the project name is set to model title
162
- value.proj_name = self.title.title
163
- self._compliance_data = value
164
-
165
- @property
166
- def site_bldg_data(self):
167
- return self._site_bldg_data
168
-
169
- @site_bldg_data.setter
170
- def site_bldg_data(self, value):
171
- if not value:
172
- value = SiteBldgData()
173
- self._site_bldg_data = value
174
-
175
- @property
176
- def polygons(self) -> List[Polygon]:
177
- return self._polygons
178
-
179
- @polygons.setter
180
- def polygons(self, value):
181
- self._polygons = value
182
-
183
- @property
184
- def constructions(self) -> ConstructionCollection:
185
- return self._constructions
186
-
187
- @constructions.setter
188
- def constructions(self, value):
189
- self._constructions = value
190
-
191
- @property
192
- def glass_types(self):
193
- return self._glass_types
194
-
195
- @glass_types.setter
196
- def glass_types(self, value):
197
- self._glass_types = value
198
-
199
- @property
200
- def context_shades(self):
201
- return self._context_shades
202
-
203
- @context_shades.setter
204
- def context_shades(self, value):
205
- self._context_shades = value
206
-
207
- @property
208
- def hvac_system_zone(self):
209
- return self._hvac_system_zone
210
-
211
- @hvac_system_zone.setter
212
- def hvac_system_zone(self, value):
213
- self._hvac_system_zone = value
214
-
215
- def to_inp(self):
216
-
217
- data = [
218
- self._header,
219
- fb.global_params,
220
- fb.ttrpddh, self.title.to_inp(), self.run_period.to_inp(),
221
- fb.comply,
222
- self.compliance_data.to_inp(),
223
- self.site_bldg_data.to_inp(),
224
- self.constructions.to_inp(),
225
- fb.glzCode,
226
- '\n'.join(gt.to_inp() for gt in self.glass_types),
227
- fb.polygons,
228
- '\n'.join(pl.to_inp() for pl in self.polygons),
229
- fb.wallParams,
230
- '\n'.join(shd.to_inp() for shd in self.context_shades),
231
- fb.miscCost,
232
- fb.perfCurve,
233
- fb.floorNspace,
234
- '\n'.join(flr.to_inp() for flr in self.floors),
235
- fb.elecFuelMeter,
236
- fb.elec_meter,
237
- fb.fuel_meter,
238
- fb.master_meter,
239
- fb.hvac_circ_loop,
240
- fb.pumps,
241
- fb.heat_exch,
242
- fb.circ_loop,
243
- fb.chiller_objs,
244
- fb.boiler_objs,
245
- fb.dwh,
246
- fb.heat_reject,
247
- fb.tower_free,
248
- fb.pvmod,
249
- fb.elecgen,
250
- fb.thermal_store,
251
- fb.ground_loop_hx,
252
- fb.comp_dhw_res,
253
- fb.steam_cld_mtr,
254
- fb.steam_mtr,
255
- fb.chill_meter,
256
- fb.hvac_sys_zone,
257
- '\n'.join(hv_sys.to_inp() for hv_sys in self.hvac_system_zone),
258
- fb.misc_meter_hvac,
259
- fb.equip_controls,
260
- fb.load_manage,
261
- fb.big_util_rate,
262
- fb.ratchets,
263
- fb.block_charge,
264
- fb.small_util_rate,
265
- fb.output_reporting,
266
- fb.loads_non_hrly,
267
- fb.sys_non_hrly,
268
- fb.plant_non_hrly,
269
- fb.econ_non_hrly,
270
- fb.hourly_rep,
271
- fb.the_end
272
- ]
273
- return '\n\n'.join(data)
274
-
275
- def __repr__(self) -> str:
276
- return 'Doe2 Model:\n%s' % self.title.to_inp()
@@ -1,59 +0,0 @@
1
- """ Templates for 'Block Inputs' that are of relative
2
- Redundance between rooms and story objects
3
- """
4
- from dragonfly.room2d import Room2D
5
- from dragonfly.story import Story
6
- from .utils import short_name, lower_left_properties
7
-
8
-
9
- class Polygon(object):
10
- "A Doe2 Polygon."
11
-
12
- def __init__(self, name, vertices):
13
- self.name = name
14
- self.vertice = vertices
15
-
16
- @classmethod
17
- def from_room(cls, room: Room2D, tolerace=0.01):
18
- """
19
- Note: Shouldn't we ensure the points are in 2D. I'm not sure how it works.
20
- #TF: ooohhhhhhhhhh good catch!! Though is there not already built into DF something
21
- of the sort for room.floor_geom? was operating off the *assumption* that obj.prop
22
- would be good to go as is? or am I misunderstanding the specifics in which should
23
- do check: raise exception if issue?
24
- """
25
- room.remove_duplicate_vertices()
26
- # TODO: on refactor, need to minimize the disconnect between the poly and 'space' room
27
- vertices = lower_left_properties(room)[0]
28
- return cls(room.display_name, vertices)
29
-
30
- @classmethod
31
- def from_story(cls, story: Story, tolerance=0.01):
32
- """
33
- Note: I'm not sure if this is correct - shouldn't we create a polygon per face?
34
- This is based on the initial code by Trevor so I didn't change it.
35
- """
36
- geo = story.footprint(tolerance=tolerance)[0]
37
- #
38
- b_pts = geo.boundary
39
- # remove duplicate vertices if any
40
- new_bound = []
41
- b_pts = b_pts[1:] + (b_pts[0],)
42
- for i, vert in enumerate(b_pts):
43
- if not vert.is_equivalent(b_pts[i - 1], tolerance):
44
- new_bound.append(b_pts[i - 1])
45
- return cls(story.display_name, new_bound)
46
-
47
- def to_inp(self) -> str:
48
- """Return Room Polygons block input"""
49
- vertices_template = ' V%d\t\t= ( %f, %f )'.replace('\t', ' ')
50
- vertices = '\n'.join([
51
- vertices_template % (i + 1, ver.x, ver.y)
52
- for i, ver in enumerate(self.vertice)
53
- ])
54
- return f'"{self.name} Plg" = POLYGON\n' \
55
- f'{vertices}\n' + \
56
- ' ..'
57
-
58
- def __repr__(self):
59
- return self.to_inp()
@@ -1,41 +0,0 @@
1
- from dataclasses import dataclass
2
- from ladybug.analysisperiod import AnalysisPeriod
3
-
4
-
5
- @dataclass
6
- class RunPeriod:
7
-
8
- begin_month: int = 1
9
- begin_day: int = 1
10
- begin_year: int = 2021
11
- end_month: int = 12
12
- end_day: int = 31
13
- end_year: int = 2021
14
-
15
- @classmethod
16
- def from_analysis_period(cls, analysis_period: AnalysisPeriod = None):
17
- analysis_period = analysis_period or AnalysisPeriod()
18
- cls_ = cls()
19
- cls_.begin_month = analysis_period.st_month
20
- cls_.begin_day = analysis_period.st_day
21
- cls_.end_month = analysis_period.end_month
22
- cls_.end_day = analysis_period.end_month
23
-
24
- return cls_
25
-
26
- def to_inp(self) -> str:
27
- """Return run period as an inp string."""
28
- # standard holidays should be exposed.
29
- return '"Entire Year" = RUN-PERIOD-PD\n ' \
30
- 'BEGIN-MONTH = 1\n' \
31
- ' BEGIN-DAY = 1\n' \
32
- ' BEGIN-YEAR = 2021\n' \
33
- ' END-MONTH = 12\n' \
34
- ' END-DAY = 31\n' \
35
- ' END-YEAR = 2021\n' \
36
- ' ..\n\n' \
37
- '"Standard US Holidays" = HOLIDAYS\n ' \
38
- 'LIBRARY-ENTRY "US"\n ..'
39
-
40
- def __repr__(self) -> str:
41
- return self.to_inp()