From db9794d63b82ef0333860c8c52b694215611fdfa Mon Sep 17 00:00:00 2001 From: Yueyue Zhou Date: Fri, 4 Oct 2024 16:49:36 -0600 Subject: [PATCH] simplify implementation with additional properties --- HPXMLtoOpenStudio/measure.rb | 15 +++++----- HPXMLtoOpenStudio/measure.xml | 10 +++---- HPXMLtoOpenStudio/resources/geometry.rb | 37 ++++++++++--------------- HPXMLtoOpenStudio/resources/model.rb | 37 +++++++------------------ 4 files changed, 36 insertions(+), 63 deletions(-) diff --git a/HPXMLtoOpenStudio/measure.rb b/HPXMLtoOpenStudio/measure.rb index 4f7957c081..765a946b69 100644 --- a/HPXMLtoOpenStudio/measure.rb +++ b/HPXMLtoOpenStudio/measure.rb @@ -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) @@ -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 @@ -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) @@ -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) diff --git a/HPXMLtoOpenStudio/measure.xml b/HPXMLtoOpenStudio/measure.xml index 8bf22e893c..423af401c0 100644 --- a/HPXMLtoOpenStudio/measure.xml +++ b/HPXMLtoOpenStudio/measure.xml @@ -3,8 +3,8 @@ 3.1 hpxm_lto_openstudio b1543b30-9465-45ff-ba04-1d1f85e763bc - d81e4aaa-3c8f-450e-84f9-b2aab461ebb2 - 2024-10-04T21:15:24Z + 467dc276-ddaf-4852-abb2-79d9c697e97b + 2024-10-04T22:49:09Z D8922A73 HPXMLtoOpenStudio HPXML to OpenStudio Translator @@ -183,7 +183,7 @@ measure.rb rb script - 1D9A5E79 + 0E8701A3 airflow.rb @@ -345,7 +345,7 @@ geometry.rb rb resource - 83A8258E + 909F2101 hotwater_appliances.rb @@ -447,7 +447,7 @@ model.rb rb resource - 46B2B024 + B1054535 output.rb diff --git a/HPXMLtoOpenStudio/resources/geometry.rb b/HPXMLtoOpenStudio/resources/geometry.rb index 44851f8808..826a9e2f82 100644 --- a/HPXMLtoOpenStudio/resources/geometry.rb +++ b/HPXMLtoOpenStudio/resources/geometry.rb @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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 @@ -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) @@ -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) @@ -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) @@ -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) @@ -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 diff --git a/HPXMLtoOpenStudio/resources/model.rb b/HPXMLtoOpenStudio/resources/model.rb index a1faee0081..5e8c82961e 100644 --- a/HPXMLtoOpenStudio/resources/model.rb +++ b/HPXMLtoOpenStudio/resources/model.rb @@ -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', @@ -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 @@ -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)