From 42a6031cda9a5a7d6a378274c7cccbe1fa485e60 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 9 Sep 2026 10:03:30 -0700 Subject: [PATCH 1/2] Include testing of mrt calc types other than EnclosureAveraged. --- model/simulationtests/zonemrtcalculation.rb | 34 +++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/model/simulationtests/zonemrtcalculation.rb b/model/simulationtests/zonemrtcalculation.rb index cd16e569..9b938356 100644 --- a/model/simulationtests/zonemrtcalculation.rb +++ b/model/simulationtests/zonemrtcalculation.rb @@ -51,7 +51,6 @@ 'offset' => 1, 'application_type' => 'Above Floor' }) -# create the zone property user view factors by surface name object # There are a number of preconditions you must meet: # * All People objects should be assigned directly to a space, # * All spaces should be assigned to the same Thermal Zone. @@ -69,6 +68,23 @@ # get all people in the zone peoples = [] spaces.each do |space| + surfaces = [] + sub_surfaces = [] + space.surfaces.each do |surface| + surfaces << surface + surface.subSurfaces.each do |sub_surface| + sub_surfaces << sub_surface + end + end + + surfaces = surfaces.uniq.sort_by { |s| s.name.to_s } + sub_surfaces = sub_surfaces.uniq.sort_by { |s| s.name.to_s } + + comfortview = OpenStudio::Model::ComfortViewFactorAngles.new(model) + (surfaces + sub_surfaces).each do |surface| + comfortview.addAngleFactor(surface, 1.0 / (surfaces.size + sub_surfaces.size)) + end + definition1 = OpenStudio::Model::PeopleDefinition.new(model) definition1.setNumberofPeople(1.0) definition1.setMeanRadiantTemperatureCalculationType('EnclosureAveraged') @@ -83,7 +99,8 @@ definition2 = OpenStudio::Model::PeopleDefinition.new(model) definition2.setNumberofPeople(1.0) - definition2.setMeanRadiantTemperatureCalculationType('EnclosureAveraged') # SurfaceWeighted, AngleFactor not supported? + definition2.setMeanRadiantTemperatureCalculationType('SurfaceWeighted') + definition2.setSurfaceNameAngleFactorListName(surfaces[0]) definition2.setThermalComfortModelType(0, 'Pierce') people2 = OpenStudio::Model::People.new(definition2) @@ -92,6 +109,19 @@ people2.setAirVelocitySchedule(airvelsch) people2.setSpace(space) peoples << people2 + + definition3 = OpenStudio::Model::PeopleDefinition.new(model) + definition3.setNumberofPeople(1.0) + definition3.setMeanRadiantTemperatureCalculationType('AngleFactor') + definition3.setSurfaceNameAngleFactorListName(comfortview) + definition3.setThermalComfortModelType(0, 'KSU') + + people3 = OpenStudio::Model::People.new(definition3) + people3.setWorkEfficiencySchedule(workeffsch) + people3.setClothingInsulationSchedule(cloinssch) + people3.setAirVelocitySchedule(airvelsch) + people3.setSpace(space) + peoples << people3 end # Extensible: MRT Weighting Factors for people From fcb113e48dbaf38fc5d98cf6e912cc6460b73a22 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 10 Sep 2026 08:50:33 -0700 Subject: [PATCH 2/2] Move ZoneMRTCalc updates to new ComfortViewFactorAngles test file, and cleanup. --- .../comfortviewfactorangles.rb | 107 ++++++++++++++++++ model/simulationtests/zonemrtcalculation.rb | 33 +----- model_tests.rb | 13 +++ 3 files changed, 121 insertions(+), 32 deletions(-) create mode 100644 model/simulationtests/comfortviewfactorangles.rb diff --git a/model/simulationtests/comfortviewfactorangles.rb b/model/simulationtests/comfortviewfactorangles.rb new file mode 100644 index 00000000..c52f5a0a --- /dev/null +++ b/model/simulationtests/comfortviewfactorangles.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +require 'openstudio' +require_relative 'lib/baseline_model' + +model = BaselineModel.new + +# make a 1 story, 100m X 50m, 5 zone core/perimeter building +model.add_geometry({ 'length' => 100, + 'width' => 50, + 'num_floors' => 1, + 'floor_to_floor_height' => 4, + 'plenum_height' => 1, + 'perimeter_zone_depth' => 3 }) + +# add windows at a 40% window-to-wall ratio +model.add_windows({ 'wwr' => 0.4, + 'offset' => 1, + 'application_type' => 'Above Floor' }) + +# add thermostats +model.add_thermostats({ 'heating_setpoint' => 19, + 'cooling_setpoint' => 26 }) + +# assign constructions from a local library to the walls/windows/etc. in the model +model.set_constructions + +# set whole building space type; simplified 90.1-2004 Large Office Whole Building +model.set_space_type + +# add design days to the model (Chicago) +model.add_design_days + +# In order to produce more consistent results between different runs, +# we sort the spaces by names +spaces = model.getSpaces.sort_by { |s| s.name.to_s } + +# Collapse all spaces into one thermal zone +thermal_zone = spaces[0].thermalZone.get +spaces.each do |space| + z = space.thermalZone.get + space.setThermalZone(thermal_zone) + z.remove if z != thermal_zone +end +thermal_zone.setName('5 spaces zone') +raise if model.getThermalZones.size != 1 +raise if thermal_zone.spaces.size != spaces.size + +# add windows at a 40% window-to-wall ratio +model.add_windows({ 'wwr' => 0.4, + 'offset' => 1, + 'application_type' => 'Above Floor' }) + +# create thermal comfort schedules +workeffsch = OpenStudio::Model::ScheduleConstant.new(model) +workeffsch.setValue(0.5) +cloinssch = OpenStudio::Model::ScheduleConstant.new(model) +cloinssch.setValue(0.5) +airvelsch = OpenStudio::Model::ScheduleConstant.new(model) +airvelsch.setValue(0.5) + +spaces.each do |space| + surfaces = [] + sub_surfaces = [] + space.surfaces.each do |surface| + surfaces << surface + surface.subSurfaces.each do |sub_surface| + sub_surfaces << sub_surface + end + end + + surfaces = surfaces.uniq.sort_by { |s| s.name.to_s } + sub_surfaces = sub_surfaces.uniq.sort_by { |s| s.name.to_s } + + comfortview = OpenStudio::Model::ComfortViewFactorAngles.new(model) + (surfaces + sub_surfaces).each do |surface| + comfortview.addAngleFactor(surface, 1.0 / (surfaces.size + sub_surfaces.size)) + end + + definition1 = OpenStudio::Model::PeopleDefinition.new(model) + definition1.setNumberofPeople(1.0) + definition1.setMeanRadiantTemperatureCalculationType('SurfaceWeighted') + definition1.setSurfaceNameAngleFactorListName(surfaces[0]) + definition1.setThermalComfortModelType(0, 'Fanger') + + people1 = OpenStudio::Model::People.new(definition1) + people1.setWorkEfficiencySchedule(workeffsch) + people1.setClothingInsulationSchedule(cloinssch) + people1.setAirVelocitySchedule(airvelsch) + people1.setSpace(space) + + definition2 = OpenStudio::Model::PeopleDefinition.new(model) + definition2.setNumberofPeople(1.0) + definition2.setMeanRadiantTemperatureCalculationType('AngleFactor') + definition2.setSurfaceNameAngleFactorListName(comfortview) + definition2.setThermalComfortModelType(0, 'Pierce') + + people2 = OpenStudio::Model::People.new(definition2) + people2.setWorkEfficiencySchedule(workeffsch) + people2.setClothingInsulationSchedule(cloinssch) + people2.setAirVelocitySchedule(airvelsch) + people2.setSpace(space) +end + +# save the OpenStudio model (.osm) +model.save_openstudio_osm({ 'osm_save_directory' => Dir.pwd, + 'osm_name' => 'in.osm' }) diff --git a/model/simulationtests/zonemrtcalculation.rb b/model/simulationtests/zonemrtcalculation.rb index 9b938356..280e7208 100644 --- a/model/simulationtests/zonemrtcalculation.rb +++ b/model/simulationtests/zonemrtcalculation.rb @@ -68,23 +68,6 @@ # get all people in the zone peoples = [] spaces.each do |space| - surfaces = [] - sub_surfaces = [] - space.surfaces.each do |surface| - surfaces << surface - surface.subSurfaces.each do |sub_surface| - sub_surfaces << sub_surface - end - end - - surfaces = surfaces.uniq.sort_by { |s| s.name.to_s } - sub_surfaces = sub_surfaces.uniq.sort_by { |s| s.name.to_s } - - comfortview = OpenStudio::Model::ComfortViewFactorAngles.new(model) - (surfaces + sub_surfaces).each do |surface| - comfortview.addAngleFactor(surface, 1.0 / (surfaces.size + sub_surfaces.size)) - end - definition1 = OpenStudio::Model::PeopleDefinition.new(model) definition1.setNumberofPeople(1.0) definition1.setMeanRadiantTemperatureCalculationType('EnclosureAveraged') @@ -99,8 +82,7 @@ definition2 = OpenStudio::Model::PeopleDefinition.new(model) definition2.setNumberofPeople(1.0) - definition2.setMeanRadiantTemperatureCalculationType('SurfaceWeighted') - definition2.setSurfaceNameAngleFactorListName(surfaces[0]) + definition2.setMeanRadiantTemperatureCalculationType('EnclosureAveraged') definition2.setThermalComfortModelType(0, 'Pierce') people2 = OpenStudio::Model::People.new(definition2) @@ -109,19 +91,6 @@ people2.setAirVelocitySchedule(airvelsch) people2.setSpace(space) peoples << people2 - - definition3 = OpenStudio::Model::PeopleDefinition.new(model) - definition3.setNumberofPeople(1.0) - definition3.setMeanRadiantTemperatureCalculationType('AngleFactor') - definition3.setSurfaceNameAngleFactorListName(comfortview) - definition3.setThermalComfortModelType(0, 'KSU') - - people3 = OpenStudio::Model::People.new(definition3) - people3.setWorkEfficiencySchedule(workeffsch) - people3.setClothingInsulationSchedule(cloinssch) - people3.setAirVelocitySchedule(airvelsch) - people3.setSpace(space) - peoples << people3 end # Extensible: MRT Weighting Factors for people diff --git a/model_tests.rb b/model_tests.rb index bdff4231..b6442738 100644 --- a/model_tests.rb +++ b/model_tests.rb @@ -437,6 +437,19 @@ def test_coilsystem_cooling_water_osm result = sim_test('coilsystem_cooling_water.osm') end + def test_comfortviewfactorangles_rb + result = sim_test('comfortviewfactorangles.rb') + end + + def test_comfortviewfactorangles_py + result = sim_test('comfortviewfactorangles.py') + end + + # TODO: To be added in the next official release after: 3.11.0 + # def test_comfortviewfactorangles_osm + # result = sim_test('comfortviewfactorangles.osm') + # end + def test_coolingtowers_osm result = sim_test('coolingtowers.osm') end