Skip to content

Commit

Permalink
Merge pull request #1550 from NREL/whole_mf_timeseries_temperatures
Browse files Browse the repository at this point in the history
Fix whole MF buildings -- timeseries temperature outputs
  • Loading branch information
shorowit authored Nov 11, 2023
2 parents 22d9e4d + 10488e3 commit da1d80e
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 43 deletions.
20 changes: 16 additions & 4 deletions HPXMLtoOpenStudio/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -171,15 +171,15 @@ def run(model, runner, user_arguments)

# Create OpenStudio model
hpxml_osm_map = {}
hpxml.buildings.each do |hpxml_bldg|
hpxml.buildings.each_with_index do |hpxml_bldg, i|
schedules_file = hpxml_sch_map[hpxml_bldg]
if hpxml.buildings.size > 1
# Create the model for this single unit
unit_model = OpenStudio::Model::Model.new
create_unit_model(hpxml, hpxml_bldg, runner, unit_model, epw_path, epw_file, weather, debug, schedules_file, eri_version)
create_unit_model(hpxml, hpxml_bldg, runner, unit_model, epw_path, epw_file, weather, debug, schedules_file, eri_version, i + 1)
hpxml_osm_map[hpxml_bldg] = unit_model
else
create_unit_model(hpxml, hpxml_bldg, runner, model, epw_path, epw_file, weather, debug, schedules_file, eri_version)
create_unit_model(hpxml, hpxml_bldg, runner, model, epw_path, epw_file, weather, debug, schedules_file, eri_version, i + 1)
hpxml_osm_map[hpxml_bldg] = model
end
end
Expand Down Expand Up @@ -398,7 +398,7 @@ def make_variable_name(obj_name, unit_number)
return "unit#{unit_number + 1}_#{obj_name}".gsub(' ', '_').gsub('-', '_')
end

def create_unit_model(hpxml, hpxml_bldg, runner, model, epw_path, epw_file, weather, debug, schedules_file, eri_version)
def create_unit_model(hpxml, hpxml_bldg, runner, model, epw_path, epw_file, weather, debug, schedules_file, eri_version, unit_num)
@hpxml_header = hpxml.header
@hpxml_bldg = hpxml_bldg
@debug = debug
Expand Down Expand Up @@ -471,6 +471,7 @@ def create_unit_model(hpxml, hpxml_bldg, runner, model, epw_path, epw_file, weat
add_photovoltaics(model)
add_generators(model)
add_batteries(runner, model, spaces)
add_building_unit(model, unit_num)
end

def check_emissions_references(hpxml_header, hpxml_path)
Expand Down Expand Up @@ -2029,6 +2030,16 @@ def add_batteries(runner, model, spaces)
end
end

def add_building_unit(model, unit_num)
return if unit_num.nil?

unit = OpenStudio::Model::BuildingUnit.new(model)
unit.additionalProperties.setFeature('unit_num', unit_num)
model.getSpaces.each do |s|
s.setBuildingUnit(unit)
end
end

def add_additional_properties(model, hpxml, hpxml_osm_map, hpxml_path, building_id, epw_file, hpxml_defaults_path)
# Store some data for use in reporting measure
additionalProperties = model.getBuilding.additionalProperties
Expand Down Expand Up @@ -2702,6 +2713,7 @@ def get_space_temperature_schedule(model, location, spaces)

sch = OpenStudio::Model::ScheduleConstant.new(model)
sch.setName(location)
sch.additionalProperties.setFeature('ObjectType', location)

space_values = Geometry.get_temperature_scheduled_space_values(location)

Expand Down
6 changes: 3 additions & 3 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>d52cfc78-4726-417a-a202-353922442ca0</version_id>
<version_modified>2023-11-10T02:13:31Z</version_modified>
<version_id>7a10799f-a5e9-4579-8668-64fa401efc75</version_id>
<version_modified>2023-11-10T22:41:43Z</version_modified>
<xml_checksum>D8922A73</xml_checksum>
<class_name>HPXMLtoOpenStudio</class_name>
<display_name>HPXML to OpenStudio Translator</display_name>
Expand Down Expand Up @@ -142,7 +142,7 @@
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>AFA848DB</checksum>
<checksum>04D14D5A</checksum>
</file>
<file>
<filename>airflow.rb</filename>
Expand Down
83 changes: 57 additions & 26 deletions ReportSimulationOutput/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -496,9 +496,10 @@ def energyPlusOutputRequests(runner, user_arguments)
HPXML::LocationExteriorWall,
HPXML::LocationUnderSlab]
keys.each do |key|
next if @model.getScheduleConstants.select { |o| o.name.to_s == key }.size == 0
schedules = @model.getScheduleConstants.select { |sch| sch.additionalProperties.getFeatureAsString('ObjectType').to_s == key }
next if schedules.empty?

result << OpenStudio::IdfObject.load("Output:Variable,#{key},Schedule Value,#{args[:timeseries_frequency]};").get
result << OpenStudio::IdfObject.load("Output:Variable,#{schedules[0].name.to_s.upcase},Schedule Value,#{args[:timeseries_frequency]};").get
end
# Also report thermostat setpoints
heated_zones.each do |heated_zone|
Expand Down Expand Up @@ -605,7 +606,7 @@ def run(runner, user_arguments)
end

# Retrieve outputs
outputs = get_outputs(runner, args)
outputs = get_outputs(runner, args, building_id)

if not check_for_errors(runner, outputs)
return false
Expand Down Expand Up @@ -709,7 +710,7 @@ def rollup_timeseries_output_to_daily_or_monthly(timeseries_output, timeseries_f
return ts_output
end

def get_outputs(runner, args)
def get_outputs(runner, args, building_id)
outputs = {}

args = setup_timeseries_includes(@emissions, args)
Expand Down Expand Up @@ -1066,37 +1067,67 @@ def get_outputs(runner, args)

# Zone temperatures
if args[:include_timeseries_zone_temperatures]
def sanitize_name(name)
return name.gsub('_', ' ').split.map(&:capitalize).join(' ')
end

# Zone temperatures
zone_names = []
scheduled_temperature_names = []
@model.getThermalZones.each do |zone|
if zone.floorArea > 1
zone_names << zone.name.to_s.upcase
end
end
@model.getScheduleConstants.each do |schedule|
next unless [HPXML::LocationOtherHeatedSpace, HPXML::LocationOtherMultifamilyBufferSpace, HPXML::LocationOtherNonFreezingSpace,
HPXML::LocationOtherHousingUnit, HPXML::LocationExteriorWall, HPXML::LocationUnderSlab].include? schedule.name.to_s
next if zone.floorArea <= 1

scheduled_temperature_names << schedule.name.to_s.upcase
zone_names << zone.name.to_s.upcase
end
zone_names.sort.each do |zone_name|
@zone_temps[zone_name] = ZoneTemp.new
@zone_temps[zone_name].name = "Temperature: #{zone_name.split.map(&:capitalize).join(' ')}"
@zone_temps[zone_name].name = "Temperature: #{sanitize_name(zone_name)}"
@zone_temps[zone_name].timeseries_units = 'F'
@zone_temps[zone_name].timeseries_output = get_report_variable_data_timeseries([zone_name], ['Zone Mean Air Temperature'], 9.0 / 5.0, 32.0, args[:timeseries_frequency])
end
scheduled_temperature_names.sort.each do |scheduled_temperature_name|
@zone_temps[scheduled_temperature_name] = ZoneTemp.new
@zone_temps[scheduled_temperature_name].name = "Temperature: #{scheduled_temperature_name.split.map(&:capitalize).join(' ')}"
@zone_temps[scheduled_temperature_name].timeseries_units = 'F'
@zone_temps[scheduled_temperature_name].timeseries_output = get_report_variable_data_timeseries([scheduled_temperature_name], ['Schedule Value'], 9.0 / 5.0, 32.0, args[:timeseries_frequency])
end
{ 'Heating Setpoint' => 'Zone Thermostat Heating Setpoint Temperature',
'Cooling Setpoint' => 'Zone Thermostat Cooling Setpoint Temperature' }.each do |sp_name, sp_var|
@zone_temps[sp_name] = ZoneTemp.new
@zone_temps[sp_name].name = "Temperature: #{sp_name}"
@zone_temps[sp_name].timeseries_units = 'F'
@zone_temps[sp_name].timeseries_output = get_report_variable_data_timeseries([HPXML::LocationConditionedSpace.upcase], [sp_var], 9.0 / 5.0, 32.0, args[:timeseries_frequency])

# Scheduled temperatures
[HPXML::LocationOtherHeatedSpace, HPXML::LocationOtherMultifamilyBufferSpace,
HPXML::LocationOtherNonFreezingSpace, HPXML::LocationOtherHousingUnit,
HPXML::LocationExteriorWall, HPXML::LocationUnderSlab].each do |sch_location|
@model.getScheduleConstants.each do |schedule|
next unless schedule.additionalProperties.getFeatureAsString('ObjectType').to_s == sch_location

sch_name = schedule.name.to_s.upcase
@zone_temps[sch_name] = ZoneTemp.new
@zone_temps[sch_name].name = "Temperature: #{sanitize_name(sch_name)}"
@zone_temps[sch_name].timeseries_units = 'F'
@zone_temps[sch_name].timeseries_output = get_report_variable_data_timeseries([sch_name], ['Schedule Value'], 9.0 / 5.0, 32.0, args[:timeseries_frequency])

break
end
end

# Heating Setpoints
heated_zones = eval(@model.getBuilding.additionalProperties.getFeatureAsString('heated_zones').get)
heated_zones.each do |heated_zone|
var_name = 'Temperature: Heating Setpoint'
if building_id == 'ALL'
unit_num = @model.getThermalZones.find { |z| z.name.to_s == heated_zone }.spaces[0].buildingUnit.get.additionalProperties.getFeatureAsInteger('unit_num').get
var_name = "Temperature: Unit#{unit_num} Heating Setpoint"
end
@zone_temps["#{heated_zone} Heating Setpoint"] = ZoneTemp.new
@zone_temps["#{heated_zone} Heating Setpoint"].name = var_name
@zone_temps["#{heated_zone} Heating Setpoint"].timeseries_units = 'F'
@zone_temps["#{heated_zone} Heating Setpoint"].timeseries_output = get_report_variable_data_timeseries([heated_zone.upcase], ['Zone Thermostat Heating Setpoint Temperature'], 9.0 / 5.0, 32.0, args[:timeseries_frequency])
end

# Cooling Setpoints
cooled_zones = eval(@model.getBuilding.additionalProperties.getFeatureAsString('cooled_zones').get)
cooled_zones.each do |cooled_zone|
var_name = 'Temperature: Cooling Setpoint'
if building_id == 'ALL'
unit_num = @model.getThermalZones.find { |z| z.name.to_s == cooled_zone }.spaces[0].buildingUnit.get.additionalProperties.getFeatureAsInteger('unit_num').get
var_name = "Temperature: Unit#{unit_num} Cooling Setpoint"
end
@zone_temps["#{cooled_zone} Cooling Setpoint"] = ZoneTemp.new
@zone_temps["#{cooled_zone} Cooling Setpoint"].name = var_name
@zone_temps["#{cooled_zone} Cooling Setpoint"].timeseries_units = 'F'
@zone_temps["#{cooled_zone} Cooling Setpoint"].timeseries_output = get_report_variable_data_timeseries([cooled_zone.upcase], ['Zone Thermostat Cooling Setpoint Temperature'], 9.0 / 5.0, 32.0, args[:timeseries_frequency])
end
end

Expand Down
8 changes: 4 additions & 4 deletions ReportSimulationOutput/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>report_simulation_output</name>
<uid>df9d170c-c21a-4130-866d-0d46b06073fd</uid>
<version_id>24e7b614-2b4f-4273-ba8a-e3617d8d0409</version_id>
<version_modified>2023-11-06T20:36:46Z</version_modified>
<version_id>ccfaa47b-cf8d-4947-9eb7-6c5dcdf89e92</version_id>
<version_modified>2023-11-10T22:41:45Z</version_modified>
<xml_checksum>9BF1E6AC</xml_checksum>
<class_name>ReportSimulationOutput</class_name>
<display_name>HPXML Simulation Output Report</display_name>
Expand Down Expand Up @@ -1929,13 +1929,13 @@
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>BF3DF39A</checksum>
<checksum>8CE20783</checksum>
</file>
<file>
<filename>test_report_sim_output.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>CFAF52E1</checksum>
<checksum>2E2543E8</checksum>
</file>
</files>
</measure>
29 changes: 29 additions & 0 deletions ReportSimulationOutput/tests/test_report_sim_output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,32 @@ def test_timeseries_hourly_zone_temperatures_mf_space
_check_for_nonzero_avg_timeseries_value(timeseries_csv, cols_temps_other_side)
end

def test_timeseries_hourly_zone_temperatures_whole_mf_building
args_hash = { 'hpxml_path' => File.join(File.dirname(__FILE__), '../../workflow/sample_files/base-multiple-mf-units.xml'),
'building_id' => 'ALL',
'skip_validation' => true,
'timeseries_frequency' => 'hourly',
'include_timeseries_zone_temperatures' => true }
annual_csv, timeseries_csv = _test_measure(args_hash)
assert(File.exist?(annual_csv))
assert(File.exist?(timeseries_csv))
actual_timeseries_cols = File.readlines(timeseries_csv)[0].strip.split(',')
expected_timeseries_cols = ['Time']
for i in 1..6
expected_timeseries_cols << "Temperature: Unit#{i} Conditioned Space"
if i <= 2
expected_timeseries_cols << "Temperature: Unit#{i} Basement Unconditioned"
elsif i >= 5
expected_timeseries_cols << "Temperature: Unit#{i} Attic Vented"
end
expected_timeseries_cols << "Temperature: Unit#{i} Heating Setpoint"
expected_timeseries_cols << "Temperature: Unit#{i} Cooling Setpoint"
end
assert_equal(expected_timeseries_cols.sort, actual_timeseries_cols.sort)
timeseries_rows = CSV.read(timeseries_csv)
assert_equal(8760, timeseries_rows.size - 2)
end

def test_timeseries_hourly_airflows_with_exhaust_mechvent
args_hash = { 'hpxml_path' => File.join(File.dirname(__FILE__), '../../workflow/sample_files/base-mechvent-exhaust.xml'),
'skip_validation' => true,
Expand Down Expand Up @@ -1564,6 +1590,9 @@ def _test_measure(args_hash, expect_success: true)
workflow.setWorkflowSteps(steps)
osw_path = File.join(File.dirname(template_osw), 'test.osw')
workflow.saveAs(osw_path)
if args_hash.size != found_args.size
puts "ERROR: Did not find an argument (#{(args_hash.keys - found_args)[0]}) in #{File.basename(template_osw)}."
end
assert_equal(args_hash.size, found_args.size)

# Run OSW
Expand Down
2 changes: 1 addition & 1 deletion tasks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def create_hpxmls
measures['BuildResidentialHPXML'][0]['schedules_filepaths'] = "../../HPXMLtoOpenStudio/resources/schedule_files/occupancy-stochastic#{suffix}.csv"
end
if hpxml_path.include?('base-multiple-mf-units')
measures['BuildResidentialHPXML'][0]['geometry_foundation_type'] = (i <= 1 ? 'UnconditionedBasement' : 'AboveApartment')
measures['BuildResidentialHPXML'][0]['geometry_foundation_type'] = (i <= 2 ? 'UnconditionedBasement' : 'AboveApartment')
measures['BuildResidentialHPXML'][0]['geometry_attic_type'] = (i >= 5 ? 'VentedAttic' : 'BelowApartment')
end

Expand Down
Loading

0 comments on commit da1d80e

Please sign in to comment.