Skip to content

Commit

Permalink
fix(building): Ensure plenum constructions survive serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
chriswmackey committed Jan 29, 2025
1 parent a66eff2 commit b7b96ec
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 3 deletions.
30 changes: 29 additions & 1 deletion dragonfly_energy/properties/building.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,14 @@ def from_dict(cls, data, host):
if 'construction_set' in data and data['construction_set'] is not None:
new_prop.construction_set = \
ConstructionSet.from_dict(data['construction_set'])
if 'ceiling_plenum_construction' in data and \
data['ceiling_plenum_construction'] is not None:
new_prop.ceiling_plenum_construction = \
OpaqueConstruction.from_dict(data['ceiling_plenum_construction'])
if 'floor_plenum_construction' in data and \
data['floor_plenum_construction'] is not None:
new_prop.ceiling_plenum_construction = \
OpaqueConstruction.from_dict(data['floor_plenum_construction'])
if 'des_cooling_load' in data and data['des_cooling_load'] is not None:
new_prop.des_cooling_load = \
HourlyContinuousCollection.from_dict(data['des_cooling_load'])
Expand All @@ -463,18 +471,28 @@ def from_dict(cls, data, host):
HourlyContinuousCollection.from_dict(data['des_hot_water_load'])
return new_prop

def apply_properties_from_dict(self, abridged_data, construction_sets):
def apply_properties_from_dict(self, abridged_data, construction_sets, constructions):
"""Apply properties from a BuildingEnergyPropertiesAbridged dictionary.
Args:
abridged_data: A BuildingEnergyPropertiesAbridged dictionary (typically
coming from a Model).
construction_sets: A dictionary of ConstructionSets with identifiers
of the sets as keys, which will be used to re-assign construction_sets.
constructions: A dictionary with construction identifiers as keys
and honeybee construction objects as values.
"""
if 'construction_set' in abridged_data and \
abridged_data['construction_set'] is not None:
self.construction_set = construction_sets[abridged_data['construction_set']]
if 'ceiling_plenum_construction' in abridged_data and \
abridged_data['ceiling_plenum_construction'] is not None:
self.ceiling_plenum_construction = \
constructions[abridged_data['ceiling_plenum_construction']]
if 'floor_plenum_construction' in abridged_data and \
abridged_data['floor_plenum_construction'] is not None:
self.floor_plenum_construction = \
constructions[abridged_data['floor_plenum_construction']]
if 'des_cooling_load' in abridged_data and \
abridged_data['des_cooling_load'] is not None:
self.des_cooling_load = \
Expand Down Expand Up @@ -540,6 +558,14 @@ def to_dict(self, abridged=False):
base['energy']['construction_set'] = \
self._construction_set.identifier if abridged else \
self._construction_set.to_dict()
if self._ceiling_plenum_construction is not None:
base['energy']['ceiling_plenum_construction'] = \
self._ceiling_plenum_construction.identifier if abridged else \
self._ceiling_plenum_construction.to_dict()
if self._floor_plenum_construction is not None:
base['energy']['floor_plenum_construction'] = \
self._floor_plenum_construction.identifier if abridged else \
self._floor_plenum_construction.to_dict()
if self._des_cooling_load is not None:
base['energy']['des_cooling_load'] = self._des_cooling_load.to_dict()
if self._des_heating_load is not None:
Expand Down Expand Up @@ -596,6 +622,8 @@ def duplicate(self, new_host=None):
"""
_host = new_host or self._host
new_prop = BuildingEnergyProperties(_host, self._construction_set)
new_prop._ceiling_plenum_construction = self._ceiling_plenum_construction
new_prop._floor_plenum_construction = self._floor_plenum_construction
new_prop._des_cooling_load = self._des_cooling_load
new_prop._des_heating_load = self._des_heating_load
new_prop._des_hot_water_load = self._des_hot_water_load
Expand Down
13 changes: 11 additions & 2 deletions dragonfly_energy/properties/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ def constructions(self):
def face_constructions(self):
"""Get a list of all unique constructions assigned to Faces, Apertures and Doors.
These objects only exist under the Building.room_3ds property
These objects only exist under the Building.room_3ds property and in
the Building's ceiling_plenum_construction and floor_plenum_construction.
"""
constructions = []
for bldg in self.host.buildings:
Expand All @@ -103,6 +104,14 @@ def face_constructions(self):
self._check_and_add_obj_construction(ap, constructions)
for dr in face.doors:
self._check_and_add_obj_construction(dr, constructions)
constr = bldg.properties.energy._ceiling_plenum_construction
if constr is not None:
if not self._instance_in_array(constr, constructions):
constructions.append(constr)
constr = bldg.properties.energy._floor_plenum_construction
if constr is not None:
if not self._instance_in_array(constr, constructions):
constructions.append(constr)
return list(set(constructions))

@property
Expand Down Expand Up @@ -450,7 +459,7 @@ def apply_properties_from_dict(self, data):
for bldg, b_dict in zip(self.host.buildings, building_e_dicts):
if b_dict is not None:
bldg.properties.energy.apply_properties_from_dict(
b_dict, construction_sets)
b_dict, construction_sets, constructions)
if bldg.has_room_3ds and b_dict is not None and 'room_3ds' in b_dict and \
b_dict['room_3ds'] is not None:
room_e_dicts, face_e_dicts, shd_e_dicts, ap_e_dicts, dr_e_dicts = \
Expand Down
49 changes: 49 additions & 0 deletions tests/model_extend_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,55 @@ def test_to_from_dict():
assert new_model.context_shades[0].properties.energy.transmittance_schedule == tree_trans


def test_to_from_dict_plenum_construction():
"""Test the Model to_dict and from_dict method with plenum constructions."""
# simple 10 x 10 rooms
pts1 = (Point3D(0, 0, 0), Point3D(10, 0, 0), Point3D(10, 10, 0), Point3D(0, 10, 0))
pts2 = (Point3D(10, 0, 0), Point3D(20, 0, 0), Point3D(20, 10, 0), Point3D(10, 10, 0))

# Two rooms with different floor heights
room2d_full = Room2D(
'R1-full', floor_geometry=Face3D(pts1), floor_to_ceiling_height=4,
is_ground_contact=True, is_top_exposed=True)
room2d_plenum = Room2D(
'R2-plenum', floor_geometry=Face3D(pts2), floor_to_ceiling_height=4,
is_ground_contact=True, is_top_exposed=True)
room2d_plenum.ceiling_plenum_depth = 0.5
room2d_plenum.floor_plenum_depth = 0.5

story = Story('S1', [room2d_full, room2d_plenum])
story.solve_room_2d_adjacency(0.01)
story.set_outdoor_window_parameters(SimpleWindowRatio(0.4))
story.multiplier = 4
building = Building('Office_Building_1234', [story])

concrete = EnergyMaterial('Concrete', 0.15, 2.31, 2322, 832, 'MediumRough',
0.95, 0.75, 0.8)
gypsum = EnergyMaterial('Gypsum', 0.0127, 0.16, 784.9, 830, 'MediumRough',
0.93, 0.6, 0.65)
ceil_constr = OpaqueConstruction('Gypsum Ceiling', [gypsum])
floor_constr = OpaqueConstruction('Concrete Floor', [concrete])
building.properties.energy.ceiling_plenum_construction = ceil_constr
building.properties.energy.floor_plenum_construction = floor_constr

plenum_model = building.to_honeybee(tolerance=0.01)
plenum_rooms = plenum_model.rooms
assert len(plenum_rooms) == 4
plenum = plenum_rooms[0]
#print(plenum[-1].properties.energy.construction)
assert plenum[-1].properties.energy.construction == floor_constr
plenum = plenum_rooms[-1]
assert plenum[0].properties.energy.construction == ceil_constr

model = Model('NewDevelopment', [building])
model_dict = model.to_dict()
new_model = Model.from_dict(model_dict)
assert model_dict == new_model.to_dict()
new_building = new_model.buildings[0]
assert new_building.properties.energy.ceiling_plenum_construction == ceil_constr
assert new_building.properties.energy.floor_plenum_construction == floor_constr


def test_to_honeybee():
"""Test the Model to_honeybee method."""
pts_1 = (Point3D(0, 0, 3), Point3D(10, 0, 3), Point3D(10, 10, 3), Point3D(0, 10, 3))
Expand Down

0 comments on commit b7b96ec

Please sign in to comment.