from typing import List
from dragonfly.model import Model as DFModel
from dragonfly.story import Story as DFStory
from dragonfly.room2d import Room2D as DFRoom
from ladybug.analysisperiod import AnalysisPeriod
from honeybee_energy.construction.window import WindowConstruction
from honeybee_energy.lib.constructionsets import generic_construction_set
from .polygon import Polygon
from .compliance import ComplianceData
from .sitebldg import SiteBldgData
from .title import Title
from .run_period import RunPeriod
from .construction import Construction, ConstructionCollection
from .floor_space import Floor
from .glass_types import GlassType
from .shades import Doe2ShadeCollection
from .hvac import HVACSystem
from . import blocks as fb
[docs]class Model:
"""A DOE *.inp Model File Object."""
def __init__(self, title, run_period=None, compliance_data=None,
site_building_data=None, polygons=None, constructions=None, floors=None,
glass_types=None, context_shades=None, hvac_system_zone=None) -> None:
self.title = title
self.run_period = run_period
self.compliance_data = compliance_data
self.site_bldg_data = site_building_data
self.polygons = polygons
self.constructions = constructions
self.floors = floors
self.glass_types = glass_types
self.context_shades = context_shades
self.hvac_system_zone = hvac_system_zone
[docs] @classmethod
def from_df_model(cls, df_model: DFModel, run_period=None):
# Make model windows rectangular to be INP friendly
df_model.to_rectangular_windows()
# Check model units, ensure units in feet
df_model.convert_to_units(units='Feet')
df_model.properties.energy.construction_sets.append(generic_construction_set)
polygons = []
flr_spc = []
window_constructions = []
context_shades = []
hvac_system_zone = []
window_constructions.append(
generic_construction_set.aperture_set.window_construction)
for con_set in df_model.properties.energy.construction_sets:
window_constructions.append(con_set.aperture_set.window_construction)
# purge duplicate window constructions
window_constructions = list(set(window_constructions))
for building in df_model.buildings:
for story in building.all_stories():
# enforce a recompute of floor to floor height
if story.floor_to_floor_height == 0:
story.floor_to_floor_height = None
story.solve_room_2d_adjacency(df_model.tolerance, intersect=True)
hvac_system_zone.append(HVACSystem.from_story(story))
flr_spc.append(Floor.from_story(story))
polygons.append(Polygon.from_story(story))
for room in story:
polygons.append(Polygon.from_room(room))
df_envelope_constrs = []
for con in generic_construction_set.wall_set.constructions:
df_envelope_constrs.append(con)
for con in generic_construction_set.floor_set.constructions:
df_envelope_constrs.append(con)
for con in generic_construction_set.roof_ceiling_set:
df_envelope_constrs.append(con)
# TODO: This messy MO takes the un-needed door constructions out of the equation
# TODO: Make more elegant when implements "to thin, make u-val"
for construction_set in df_model.properties.energy.construction_sets:
for con in construction_set.wall_set.constructions:
df_envelope_constrs.append(con)
for con in generic_construction_set.wall_set.constructions:
df_envelope_constrs.append(con)
for con in construction_set.floor_set.constructions:
df_envelope_constrs.append(con)
for con in construction_set.roof_ceiling_set:
df_envelope_constrs.append(con)
constructions = ConstructionCollection.from_hb_constructions(
df_envelope_constrs)
glass_types = [GlassType.from_hb_window_constr(
w_con) for w_con in window_constructions]
shade_objs = df_model.context_shades
context_shades.append(Doe2ShadeCollection.from_df_context_shades(shade_objs))
return cls(
df_model.display_name, run_period, polygons=polygons,
constructions=constructions, floors=flr_spc, glass_types=glass_types,
context_shades=context_shades, hvac_system_zone=hvac_system_zone)
[docs] @classmethod
def from_dfjson(cls, dfjson_file, run_period=None):
model = DFModel.from_dfjson(dfjson_file)
return cls.from_df_model(model, run_period)
@property
def _header(self):
"""File header.
NOTE: The header is currently read-only
"""
return '\n'.join([fb.top_level, fb.abort_diag])
@property
def title(self):
return self._title
@title.setter
def title(self, value):
self._title = Title(value)
# update the title in complinace data
try:
self.compliance_data.proj_name = value
except AttributeError:
# this happens on initiation since compliance data is not set yet
# we can ignore it
pass
@property
def run_period(self):
"""Model run period."""
return self._run_period
@run_period.setter
def run_period(self, value: AnalysisPeriod):
self._run_period = RunPeriod.from_analysis_period(value)
@property
def compliance_data(self):
"""Model DOE2 Compliance Data"""
return self._compliance_data
@compliance_data.setter
def compliance_data(self, value):
if not value:
value = ComplianceData()
# make sure the project name is set to model title
value.proj_name = self.title.title
self._compliance_data = value
@property
def site_bldg_data(self):
return self._site_bldg_data
@site_bldg_data.setter
def site_bldg_data(self, value):
if not value:
value = SiteBldgData()
self._site_bldg_data = value
@property
def polygons(self) -> List[Polygon]:
return self._polygons
@polygons.setter
def polygons(self, value):
self._polygons = value
@property
def constructions(self) -> ConstructionCollection:
return self._constructions
@constructions.setter
def constructions(self, value):
self._constructions = value
@property
def glass_types(self):
return self._glass_types
@glass_types.setter
def glass_types(self, value):
self._glass_types = value
@property
def context_shades(self):
return self._context_shades
@context_shades.setter
def context_shades(self, value):
self._context_shades = value
@property
def hvac_system_zone(self):
return self._hvac_system_zone
@hvac_system_zone.setter
def hvac_system_zone(self, value):
self._hvac_system_zone = value
[docs] def to_inp(self):
data = [
self._header,
fb.global_params,
fb.ttrpddh, self.title.to_inp(), self.run_period.to_inp(),
fb.comply,
self.compliance_data.to_inp(),
self.site_bldg_data.to_inp(),
self.constructions.to_inp(),
fb.glzCode,
'\n'.join(gt.to_inp() for gt in self.glass_types),
fb.polygons,
'\n'.join(pl.to_inp() for pl in self.polygons),
fb.wallParams,
'\n'.join(shd.to_inp() for shd in self.context_shades),
fb.miscCost,
fb.perfCurve,
fb.floorNspace,
'\n'.join(flr.to_inp() for flr in self.floors),
fb.elecFuelMeter,
fb.elec_meter,
fb.fuel_meter,
fb.master_meter,
fb.hvac_circ_loop,
fb.pumps,
fb.heat_exch,
fb.circ_loop,
fb.chiller_objs,
fb.boiler_objs,
fb.dwh,
fb.heat_reject,
fb.tower_free,
fb.pvmod,
fb.elecgen,
fb.thermal_store,
fb.ground_loop_hx,
fb.comp_dhw_res,
fb.steam_cld_mtr,
fb.steam_mtr,
fb.chill_meter,
fb.hvac_sys_zone,
'\n'.join(hv_sys.to_inp() for hv_sys in self.hvac_system_zone),
fb.misc_meter_hvac,
fb.equip_controls,
fb.load_manage,
fb.big_util_rate,
fb.ratchets,
fb.block_charge,
fb.small_util_rate,
fb.output_reporting,
fb.loads_non_hrly,
fb.sys_non_hrly,
fb.plant_non_hrly,
fb.econ_non_hrly,
fb.hourly_rep,
fb.the_end
]
return '\n\n'.join(data)
def __repr__(self) -> str:
return 'Doe2 Model:\n%s' % self.title.to_inp()