Skip to content

Commit

Permalink
simplify implementation with additional properties
Browse files Browse the repository at this point in the history
  • Loading branch information
yzhou601 committed Oct 4, 2024
1 parent 37aac01 commit db9794d
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 63 deletions.
15 changes: 7 additions & 8 deletions HPXMLtoOpenStudio/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,12 @@ def run(model, runner, user_arguments)

# Create OpenStudio unit model(s)
hpxml_osm_map = {}
common_surface_id_map = {}
hpxml.buildings.each do |hpxml_bldg|
# Create the model for this single unit
# If we're running a whole SFA/MF building, all the unit models will be merged later
if hpxml.buildings.size > 1
unit_model = OpenStudio::Model::Model.new
create_unit_model(hpxml, hpxml_bldg, runner, unit_model, epw_path, weather, hpxml_sch_map[hpxml_bldg], common_surface_id_map)
create_unit_model(hpxml, hpxml_bldg, runner, unit_model, epw_path, weather, hpxml_sch_map[hpxml_bldg])
hpxml_osm_map[hpxml_bldg] = unit_model
else
create_unit_model(hpxml, hpxml_bldg, runner, model, epw_path, weather, hpxml_sch_map[hpxml_bldg], nil)
Expand All @@ -144,7 +143,7 @@ def run(model, runner, user_arguments)

# Merge unit models into final model
if hpxml.buildings.size > 1
Model.merge_unit_models(model, hpxml_osm_map, common_surface_id_map)
Model.merge_unit_models(model, hpxml_osm_map)
end

# Create EnergyPlus outputs
Expand Down Expand Up @@ -315,7 +314,7 @@ def process_defaults_schedules_emissions_files(runner, weather, hpxml, args)
# @param weather [WeatherFile] Weather object containing EPW information
# @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files
# @return [nil]
def create_unit_model(hpxml, hpxml_bldg, runner, model, epw_path, weather, schedules_file, common_surface_id_map)
def create_unit_model(hpxml, hpxml_bldg, runner, model, epw_path, weather, schedules_file)
init(model, hpxml_bldg, hpxml.header)
SimControls.apply(model, hpxml.header)
Location.apply(model, weather, hpxml_bldg, hpxml.header, epw_path)
Expand All @@ -327,10 +326,10 @@ def create_unit_model(hpxml, hpxml_bldg, runner, model, epw_path, weather, sched

# Geometry & Enclosure
Geometry.apply_roofs(runner, model, spaces, hpxml_bldg, hpxml.header)
Geometry.apply_walls(runner, model, spaces, hpxml_bldg, hpxml.header, common_surface_id_map)
Geometry.apply_rim_joists(runner, model, spaces, hpxml_bldg, common_surface_id_map)
Geometry.apply_floors(runner, model, spaces, hpxml_bldg, hpxml.header, common_surface_id_map)
Geometry.apply_foundation_walls_slabs(runner, model, spaces, weather, hpxml_bldg, hpxml.header, schedules_file, common_surface_id_map)
Geometry.apply_walls(runner, model, spaces, hpxml_bldg, hpxml.header)
Geometry.apply_rim_joists(runner, model, spaces, hpxml_bldg)
Geometry.apply_floors(runner, model, spaces, hpxml_bldg, hpxml.header)
Geometry.apply_foundation_walls_slabs(runner, model, spaces, weather, hpxml_bldg, hpxml.header, schedules_file)
Geometry.apply_windows(model, spaces, hpxml_bldg, hpxml.header)
Geometry.apply_doors(model, spaces, hpxml_bldg)
Geometry.apply_skylights(model, spaces, hpxml_bldg, hpxml.header)
Expand Down
10 changes: 5 additions & 5 deletions HPXMLtoOpenStudio/measure.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<schema_version>3.1</schema_version>
<name>hpxm_lto_openstudio</name>
<uid>b1543b30-9465-45ff-ba04-1d1f85e763bc</uid>
<version_id>d81e4aaa-3c8f-450e-84f9-b2aab461ebb2</version_id>
<version_modified>2024-10-04T21:15:24Z</version_modified>
<version_id>467dc276-ddaf-4852-abb2-79d9c697e97b</version_id>
<version_modified>2024-10-04T22:49:09Z</version_modified>
<xml_checksum>D8922A73</xml_checksum>
<class_name>HPXMLtoOpenStudio</class_name>
<display_name>HPXML to OpenStudio Translator</display_name>
Expand Down Expand Up @@ -183,7 +183,7 @@
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>1D9A5E79</checksum>
<checksum>0E8701A3</checksum>
</file>
<file>
<filename>airflow.rb</filename>
Expand Down Expand Up @@ -345,7 +345,7 @@
<filename>geometry.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>83A8258E</checksum>
<checksum>909F2101</checksum>
</file>
<file>
<filename>hotwater_appliances.rb</filename>
Expand Down Expand Up @@ -447,7 +447,7 @@
<filename>model.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>46B2B024</checksum>
<checksum>B1054535</checksum>
</file>
<file>
<filename>output.rb</filename>
Expand Down
37 changes: 14 additions & 23 deletions HPXMLtoOpenStudio/resources/geometry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,8 @@ def self.apply_roofs(runner, model, spaces, hpxml_bldg, hpxml_header)
# @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects
# @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit
# @param hpxml_header [HPXML::Header] HPXML Header object (one per HPXML file)
# @param common_surface_id_map [Hash] map of HPXML id and OpenStudio surface handle
# @return [nil]
def self.apply_walls(runner, model, spaces, hpxml_bldg, hpxml_header, common_surface_id_map)
def self.apply_walls(runner, model, spaces, hpxml_bldg, hpxml_header)
default_azimuths = Defaults.get_azimuths(hpxml_bldg)
_walls_top, foundation_top = get_foundation_and_walls_top(hpxml_bldg)

Expand Down Expand Up @@ -172,7 +171,7 @@ def self.apply_walls(runner, model, spaces, hpxml_bldg, hpxml_header, common_sur
end
surface.setSurfaceType(EPlus::SurfaceTypeWall)
set_surface_interior(model, spaces, surface, wall, hpxml_bldg)
set_surface_exterior(model, spaces, surface, wall, hpxml_bldg, common_surface_id_map)
set_surface_exterior(model, spaces, surface, wall, hpxml_bldg)
if wall.is_interior
surface.setSunExposure(EPlus::SurfaceSunExposureNo)
surface.setWindExposure(EPlus::SurfaceWindExposureNo)
Expand Down Expand Up @@ -215,9 +214,8 @@ def self.apply_walls(runner, model, spaces, hpxml_bldg, hpxml_header, common_sur
# @param model [OpenStudio::Model::Model] OpenStudio Model object
# @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects
# @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit
# @param common_surface_id_map [Hash] map of HPXML id and OpenStudio surface handle
# @return [nil]
def self.apply_rim_joists(runner, model, spaces, hpxml_bldg, common_surface_id_map)
def self.apply_rim_joists(runner, model, spaces, hpxml_bldg)
default_azimuths = Defaults.get_azimuths(hpxml_bldg)
_walls_top, foundation_top = get_foundation_and_walls_top(hpxml_bldg)

Expand Down Expand Up @@ -253,7 +251,7 @@ def self.apply_rim_joists(runner, model, spaces, hpxml_bldg, common_surface_id_m
end
surface.setSurfaceType(EPlus::SurfaceTypeWall)
set_surface_interior(model, spaces, surface, rim_joist, hpxml_bldg)
set_surface_exterior(model, spaces, surface, rim_joist, hpxml_bldg, common_surface_id_map)
set_surface_exterior(model, spaces, surface, rim_joist, hpxml_bldg)
if rim_joist.is_interior
surface.setSunExposure(EPlus::SurfaceSunExposureNo)
surface.setWindExposure(EPlus::SurfaceWindExposureNo)
Expand Down Expand Up @@ -299,9 +297,8 @@ def self.apply_rim_joists(runner, model, spaces, hpxml_bldg, common_surface_id_m
# @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects
# @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit
# @param hpxml_header [HPXML::Header] HPXML Header object (one per HPXML file)
# @param common_surface_id_map [Hash] map of HPXML id and OpenStudio surface handle
# @return [nil]
def self.apply_floors(runner, model, spaces, hpxml_bldg, hpxml_header, common_surface_id_map)
def self.apply_floors(runner, model, spaces, hpxml_bldg, hpxml_header)
default_azimuths = Defaults.get_azimuths(hpxml_bldg)
walls_top, foundation_top = get_foundation_and_walls_top(hpxml_bldg)

Expand All @@ -328,7 +325,7 @@ def self.apply_floors(runner, model, spaces, hpxml_bldg, hpxml_header, common_su
end
surface.additionalProperties.setFeature('Tilt', 0.0)
set_surface_interior(model, spaces, surface, floor, hpxml_bldg)
set_surface_exterior(model, spaces, surface, floor, hpxml_bldg, common_surface_id_map)
set_surface_exterior(model, spaces, surface, floor, hpxml_bldg)
surface.setName(floor.id)
if floor.is_interior
surface.setSunExposure(EPlus::SurfaceSunExposureNo)
Expand Down Expand Up @@ -393,9 +390,8 @@ def self.apply_floors(runner, model, spaces, hpxml_bldg, hpxml_header, common_su
# @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit
# @param hpxml_header [HPXML::Header] HPXML Header object (one per HPXML file)
# @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files
# @param common_surface_id_map [Hash] map of HPXML id and OpenStudio surface handle
# @return [nil]
def self.apply_foundation_walls_slabs(runner, model, spaces, weather, hpxml_bldg, hpxml_header, schedules_file, common_surface_id_map)
def self.apply_foundation_walls_slabs(runner, model, spaces, weather, hpxml_bldg, hpxml_header, schedules_file)
default_azimuths = Defaults.get_azimuths(hpxml_bldg)

foundation_types = hpxml_bldg.slabs.map { |s| s.interior_adjacent_to }.uniq
Expand Down Expand Up @@ -474,7 +470,7 @@ def self.apply_foundation_walls_slabs(runner, model, spaces, weather, hpxml_bldg
surface.setName(fnd_wall.id)
surface.setSurfaceType(EPlus::SurfaceTypeWall)
set_surface_interior(model, spaces, surface, fnd_wall, hpxml_bldg)
set_surface_exterior(model, spaces, surface, fnd_wall, hpxml_bldg, common_surface_id_map)
set_surface_exterior(model, spaces, surface, fnd_wall, hpxml_bldg)
surface.setSunExposure(EPlus::SurfaceSunExposureNo)
surface.setWindExposure(EPlus::SurfaceWindExposureNo)

Expand Down Expand Up @@ -548,7 +544,7 @@ def self.apply_foundation_wall(runner, model, spaces, hpxml_bldg, foundation_wal
surface.setName(foundation_wall.id)
surface.setSurfaceType(EPlus::SurfaceTypeWall)
set_surface_interior(model, spaces, surface, foundation_wall, hpxml_bldg)
set_surface_exterior(model, spaces, surface, foundation_wall, hpxml_bldg, nil)
set_surface_exterior(model, spaces, surface, foundation_wall, hpxml_bldg)

assembly_r = foundation_wall.insulation_assembly_r_value
mat_int_finish = Material.InteriorFinishMaterial(foundation_wall.interior_finish_type, foundation_wall.interior_finish_thickness)
Expand Down Expand Up @@ -938,7 +934,7 @@ def self.apply_skylights(model, spaces, hpxml_bldg, hpxml_header)
surface.setName("surface #{skylight.id} shaft")
surface.setSurfaceType(EPlus::SurfaceTypeWall)
set_surface_interior(model, spaces, surface, skylight.floor, hpxml_bldg)
set_surface_exterior(model, spaces, surface, skylight.floor, hpxml_bldg, nil)
set_surface_exterior(model, spaces, surface, skylight.floor, hpxml_bldg)
surface.setSunExposure(EPlus::SurfaceSunExposureNo)
surface.setWindExposure(EPlus::SurfaceWindExposureNo)

Expand Down Expand Up @@ -1723,17 +1719,12 @@ def self.set_surface_interior(model, spaces, surface, hpxml_surface, hpxml_bldg)
# @param surface [OpenStudio::Model::Surface] an OpenStudio::Model::Surface object
# @param hpxml_surface [HPXML::Wall or HPXML::Roof or HPXML::RimJoist or HPXML::FoundationWall or HPXML::Slab] any HPXML surface
# @return [nil]
def self.set_surface_exterior(model, spaces, surface, hpxml_surface, hpxml_bldg, common_surface_id_map)
def self.set_surface_exterior(model, spaces, surface, hpxml_surface, hpxml_bldg)
exterior_adjacent_to = hpxml_surface.exterior_adjacent_to
is_adiabatic = hpxml_surface.is_adiabatic
if not hpxml_surface.sameas_id.nil?
if common_surface_id_map.nil?
fail "unexpected surface sameas attribute assigned: #{surface.sameas_id}."
else
# Store surface id and OS surface object mapping, process later
common_surface_id_map[hpxml_surface.id] = surface.handle
return
end
surface.additionalProperties.setFeature('HPXMLID', hpxml_surface.id)
surface.additionalProperties.setFeature('HPXMLSameasID', hpxml_surface.sameas_id)
end
if [HPXML::LocationOutside, HPXML::LocationManufacturedHomeUnderBelly].include? exterior_adjacent_to
surface.setOutsideBoundaryCondition(EPlus::BoundaryConditionOutdoors)
Expand Down Expand Up @@ -1766,7 +1757,7 @@ def self.set_subsurface_exterior(surface, spaces, model, hpxml_surface, hpxml_bl
if hpxml_surface.exterior_adjacent_to == HPXML::LocationGround
surface.setOutsideBoundaryCondition(EPlus::BoundaryConditionOutdoors)
else
set_surface_exterior(model, spaces, surface, hpxml_surface, hpxml_bldg, nil)
set_surface_exterior(model, spaces, surface, hpxml_surface, hpxml_bldg)
end
end

Expand Down
37 changes: 10 additions & 27 deletions HPXMLtoOpenStudio/resources/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -718,10 +718,8 @@ def self.reset(model, runner)
# Then bulk add all modified objects to the main OpenStudio Model object.
#
# @param model [OpenStudio::Model::Model] OpenStudio Model object
# @param hpxml_osm_map [Hash] Map of HPXML::Building objects => OpenStudio Model objects for each dwelling unit
# @param common_surface_id_map [Hash] map of HPXML id and OpenStudio surface handle (within OpenStudio Model objects for each dwelling unit)
# @return [nil]
def self.merge_unit_models(model, hpxml_osm_map, common_surface_id_map)
def self.merge_unit_models(model, hpxml_osm_map)
# Map of OpenStudio IDD objects => OSM class names
unique_object_map = { 'OS:ConvergenceLimits' => 'ConvergenceLimits',
'OS:Foundation:Kiva:Settings' => 'FoundationKivaSettings',
Expand Down Expand Up @@ -779,32 +777,15 @@ def self.merge_unit_models(model, hpxml_osm_map, common_surface_id_map)
end
end

unit_surface_to_obj_index_map = {} # map of unit model surface handle to whole building model object index
unit_model_map = {} # map of OS surface handle to OS adjacent surface handle (at unit model workspace)
hpxml_osm_map.each_with_index do |(hpxml_bldg, unit_model), unit_number|
hpxml_osm_map.values.each_with_index do |unit_model, unit_number|
Geometry.shift_surfaces(unit_model, unit_number)
prefix_object_names(unit_model, unit_number)
hpxml_bldg.surfaces.each do |surface|
next if surface.sameas_id.nil?
# Should be stored in the map, store the unit model object mapping
next unless common_surface_id_map.keys.include? surface.id
next unless common_surface_id_map.keys.include? surface.sameas_id

current_surface_handle = common_surface_id_map[surface.id]
adjacent_surface_handle = common_surface_id_map[surface.sameas_id]
unit_model_map[current_surface_handle] = adjacent_surface_handle
end

# Handle remaining (non-unique) objects now
unit_model.objects.each do |obj|
next if unit_number > 0 && obj.to_Building.is_initialized
next if unique_handles_to_skip.include? obj.handle.to_s

unit_model_obj_index = unit_model_objects.size
if common_surface_id_map.values.include? obj.handle
unit_surface_to_obj_index_map[obj.handle] = unit_model_obj_index
end

unit_model_objects << obj
end
end
Expand All @@ -821,15 +802,17 @@ def self.merge_unit_models(model, hpxml_osm_map, common_surface_id_map)
end
end
end
return if unit_surface_to_obj_index_map.empty?

model_objects.each_with_index do |obj, index|
next unless unit_surface_to_obj_index_map.values.include? index
model_objects.each_with_index do |obj, _index|
next unless obj.to_Surface.is_initialized

unit_surface_handle = unit_model_objects[index].handle
surface = obj.to_Surface.get
adjacent_surface_index = unit_surface_to_obj_index_map[unit_model_map[unit_surface_handle]]
adjacent_surface = model_objects[adjacent_surface_index].to_Surface.get
hpxml_sameas_id = surface.additionalProperties.getFeatureAsString('HPXMLSameasID')
next unless hpxml_sameas_id.is_initialized

hpxml_sameas_id = hpxml_sameas_id.to_s
adjacent_surface = model_objects.find { |obj| obj.to_Surface.is_initialized && obj.to_Surface.get.additionalProperties.getFeatureAsString('HPXMLID').is_initialized && obj.to_Surface.get.additionalProperties.getFeatureAsString('HPXMLID').to_s == hpxml_sameas_id }.to_Surface.get

next if surface.adjacentSurface.is_initialized

surface.setAdjacentSurface(adjacent_surface)
Expand Down

0 comments on commit db9794d

Please sign in to comment.