Skip to content

Commit

Permalink
Merge pull request #929 from NREL/resstock-args-refactor
Browse files Browse the repository at this point in the history
New ResStockArgumentsPostHPXML measure
  • Loading branch information
joseph-robertson authored Feb 4, 2025
2 parents cd7cf2a + df0cd90 commit 819683e
Show file tree
Hide file tree
Showing 15 changed files with 283 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ The BuildExistingModel and ApplyUpgrade meta measures call the following model m
1 ResStockArguments Model No ResStock
2 BuildResidentialHPXML Model No OS-HPXML
3 BuildResidentialScheduleFile Model No OS-HPXML
4 ResStockArgumentsPostHPXML Model No ResStock
===== ============================= ================== ========= ============= ==========================

.. _model-measures:
Expand Down Expand Up @@ -117,6 +118,16 @@ They contribute to the generation of the model.
:start-after: <modeler_description>
:end-before: <

**ResStockArgumentsPostHPXML**

.. include:: ../../../../measures/ResStockArgumentsPostHPXML/measure.xml
:start-after: <description>
:end-before: <

.. include:: ../../../../measures/ResStockArgumentsPostHPXML/measure.xml
:start-after: <modeler_description>
:end-before: <

.. _tutorial-apply-upgrade:

**ApplyUpgrade**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@ Development Changelog
:version: v3.5.0
:released: pending

.. change::
:tags: workflow, feature
:pullreq: 929
:tickets: 927

**Date**: 2025-02-04

Title:
New ResStockArgumentsPostHPXML measure

Description:
This measure is introduced to the workflow for postprocessing the output of the BuildResidentialHPXML and BuildResidentialScheduleFile measures.
In short, we can use generated schedules (e.g., occupant schedule) to create other detailed schedules (e.g., setpoint schedules).
Currently, this is just a stubbed version of the measure -- future versions will actually take advantage of the new functionality.

Assignees: Joe Robertson, Rajendra Adhikari


.. change::
:tags: characteristics
:pullreq: 1339
Expand Down
13 changes: 12 additions & 1 deletion measures/ApplyUpgrade/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -524,10 +524,20 @@ def run(model, runner, user_arguments)
return false
end

measures['ResStockArgumentsPostHPXML'] = [{}] if !measures.keys.include?('ResStockArgumentsPostHPXML')
measures['ResStockArgumentsPostHPXML'][0]['hpxml_path'] = hpxml_path
measures['ResStockArgumentsPostHPXML'][0]['output_csv_path'] = File.expand_path('../schedules.csv')
measures['ResStockArgumentsPostHPXML'][0]['building_id'] = values['building_id']
measures_hash = { 'ResStockArgumentsPostHPXML' => measures['ResStockArgumentsPostHPXML'] }
if not apply_measures(measures_dir, measures_hash, new_runner, model, true, 'OpenStudio::Measure::ModelMeasure', nil)
register_logs(runner, new_runner)
return false
end

# Specify measures to run
measures_to_apply_hash = { measures_dir => {} }

upgrade_measures = measures.keys - ['ResStockArguments', 'BuildResidentialHPXML', 'BuildResidentialScheduleFile']
upgrade_measures = measures.keys - ['ResStockArguments', 'BuildResidentialHPXML', 'BuildResidentialScheduleFile', 'ResStockArgumentsPostHPXML']
upgrade_measures.each do |upgrade_measure|
measures_to_apply_hash[measures_dir][upgrade_measure] = measures[upgrade_measure]
end
Expand All @@ -549,6 +559,7 @@ def run(model, runner, user_arguments)
FileUtils.cp(hpxml_path, in_path)

register_logs(runner, resstock_arguments_runner)
register_logs(runner, new_runner)

return true
end
Expand Down
6 changes: 3 additions & 3 deletions measures/ApplyUpgrade/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>apply_upgrade</name>
<uid>33f1654c-f734-43d1-b35d-9d2856e41b5a</uid>
<version_id>9e554ddb-2d72-4a51-b9c1-fcd24c95f33d</version_id>
<version_modified>2025-01-30T17:46:21Z</version_modified>
<version_id>8ce6c8df-ccf4-4d0d-a717-bc5d7367c7ca</version_id>
<version_modified>2025-02-04T21:34:51Z</version_modified>
<xml_checksum>9339BE01</xml_checksum>
<class_name>ApplyUpgrade</class_name>
<display_name>Apply Upgrade</display_name>
Expand Down Expand Up @@ -25025,7 +25025,7 @@
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>42D55698</checksum>
<checksum>414B0950</checksum>
</file>
<file>
<filename>constants.rb</filename>
Expand Down
11 changes: 11 additions & 0 deletions measures/BuildExistingModel/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,16 @@ def run(model, runner, user_arguments)
end
end

measures['ResStockArgumentsPostHPXML'] = [{}] if !measures.keys.include?('ResStockArgumentsPostHPXML')
measures['ResStockArgumentsPostHPXML'][0]['hpxml_path'] = hpxml_path
measures['ResStockArgumentsPostHPXML'][0]['output_csv_path'] = File.expand_path('../schedules.csv')
measures['ResStockArgumentsPostHPXML'][0]['building_id'] = args[:building_id]
measures_hash = { 'ResStockArgumentsPostHPXML' => measures['ResStockArgumentsPostHPXML'] }
if not apply_measures(measures_dir, measures_hash, new_runner, model, true, 'OpenStudio::Measure::ModelMeasure', nil)
register_logs(runner, new_runner)
return false
end

# Copy existing.xml to home.xml for downstream HPXMLtoOpenStudio
# We need existing.xml (and not just home.xml) for UpgradeCosts
in_path = File.expand_path('../home.xml')
Expand Down Expand Up @@ -809,6 +819,7 @@ def run(model, runner, user_arguments)
end

register_logs(runner, resstock_arguments_runner)
register_logs(runner, new_runner)

return true
end
Expand Down
6 changes: 3 additions & 3 deletions measures/BuildExistingModel/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>build_existing_model</name>
<uid>dedf59bb-3b88-4f16-8755-2c1ff5519cbf</uid>
<version_id>8d7c2d5f-2ee5-4f23-bd93-debbead74238</version_id>
<version_modified>2025-01-30T17:46:22Z</version_modified>
<version_id>4545129e-a6bf-44ce-b091-3db9fad11222</version_id>
<version_modified>2025-01-31T03:46:19Z</version_modified>
<xml_checksum>2C38F48B</xml_checksum>
<class_name>BuildExistingModel</class_name>
<display_name>Build Existing Model</display_name>
Expand Down Expand Up @@ -357,7 +357,7 @@
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>32867677</checksum>
<checksum>2F739BE5</checksum>
</file>
</files>
</measure>
2 changes: 1 addition & 1 deletion measures/ResStockArguments/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
## Description
Measure that pre-processes the arguments passed to the BuildResidentialHPXML and BuildResidentialScheduleFile measures.

Passes in all arguments from the options lookup, processes them, and then registers values to the runner to be used by other measures.
Passes in all ResStockArguments arguments from the options lookup, processes them, and then registers values to the runner to be used by other measures.

## Arguments

Expand Down
2 changes: 1 addition & 1 deletion measures/ResStockArguments/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def description

# human readable description of modeling approach
def modeler_description
return 'Passes in all arguments from the options lookup, processes them, and then registers values to the runner to be used by other measures.'
return 'Passes in all ResStockArguments arguments from the options lookup, processes them, and then registers values to the runner to be used by other measures.'
end

# define the arguments that the user will input
Expand Down
12 changes: 6 additions & 6 deletions measures/ResStockArguments/measure.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
<schema_version>3.1</schema_version>
<name>res_stock_arguments</name>
<uid>c984bb9e-4ac4-4930-a399-9d23f8f6936a</uid>
<version_id>87f66003-9d8d-48be-9ea5-17006046955d</version_id>
<version_modified>2025-01-30T17:46:23Z</version_modified>
<version_id>d4503561-5947-467e-a470-7e3a3244d991</version_id>
<version_modified>2025-02-04T20:54:44Z</version_modified>
<xml_checksum>2C38F48B</xml_checksum>
<class_name>ResStockArguments</class_name>
<display_name>ResStock Arguments</display_name>
<description>Measure that pre-processes the arguments passed to the BuildResidentialHPXML and BuildResidentialScheduleFile measures.</description>
<modeler_description>Passes in all arguments from the options lookup, processes them, and then registers values to the runner to be used by other measures.</modeler_description>
<modeler_description>Passes in all ResStockArguments arguments from the options lookup, processes them, and then registers values to the runner to be used by other measures.</modeler_description>
<arguments>
<argument>
<name>simulation_control_daylight_saving_enabled</name>
Expand Down Expand Up @@ -7684,7 +7684,7 @@
<filename>README.md</filename>
<filetype>md</filetype>
<usage_type>readme</usage_type>
<checksum>B3F720DE</checksum>
<checksum>39109EF9</checksum>
</file>
<file>
<filename>README.md.erb</filename>
Expand All @@ -7701,7 +7701,7 @@
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>C85AA9D8</checksum>
<checksum>315B55D1</checksum>
</file>
<file>
<filename>constants.rb</filename>
Expand All @@ -7713,7 +7713,7 @@
<filename>measure.txt</filename>
<filetype>txt</filetype>
<usage_type>resource</usage_type>
<checksum>96A4BB9E</checksum>
<checksum>5505BBDE</checksum>
</file>
<file>
<filename>resstock_arguments_test.rb</filename>
Expand Down
2 changes: 1 addition & 1 deletion measures/ResStockArguments/resources/measure.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3827e629e35c9fbbbc53363b9886e22d
357944431a5a88e46e2b12c30da3f703
106 changes: 106 additions & 0 deletions measures/ResStockArgumentsPostHPXML/measure.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# frozen_string_literal: true

# see the URL below for information on how to write OpenStudio measures
# http://nrel.github.io/OpenStudio-user-documentation/reference/measure_writing_guide/

# start the measure
class ResStockArgumentsPostHPXML < OpenStudio::Measure::ModelMeasure
# human readable name
def name
return 'ResStock Arguments Post-HPXML'
end

# human readable description
def description
return 'Measure that post-processes the output of the BuildResidentialHPXML and BuildResidentialScheduleFile measures.'
end

# human readable description of modeling approach
def modeler_description
return 'Passes in all ResStockArgumentsPostHPXML arguments from the options lookup, processes them, and then modifies output of other measures.'
end

# define the arguments that the user will input
def arguments(model) # rubocop:disable Lint/UnusedMethodArgument
args = OpenStudio::Measure::OSArgumentVector.new

arg = OpenStudio::Measure::OSArgument.makeStringArgument('hpxml_path', false)
arg.setDisplayName('HPXML File Path')
arg.setDescription('Absolute/relative path of the HPXML file.')
args << arg

arg = OpenStudio::Measure::OSArgument::makeStringArgument('building_id', false)
arg.setDisplayName('Building Unit ID')
arg.setDescription('The building unit number (between 1 and the number of samples).')
args << arg

arg = OpenStudio::Measure::OSArgument::makeStringArgument('output_csv_path', false)
arg.setDisplayName('Schedules: Output CSV Path')
arg.setDescription('Absolute/relative path of the csv file containing occupancy schedules. Relative paths are relative to the HPXML output path.')
args << arg

return args
end

# define what happens when the measure is run
def run(model, runner, user_arguments)
super(model, runner, user_arguments)

# use the built-in error checking
if !runner.validateUserArguments(arguments(model), user_arguments)
return false
end

# assign the user inputs to variables
args = runner.getArgumentValues(arguments(model), user_arguments)

hpxml_path = args[:hpxml_path]
unless (Pathname.new hpxml_path).absolute?
hpxml_path = File.expand_path(File.join(File.dirname(__FILE__), hpxml_path))
end
unless File.exist?(hpxml_path) && hpxml_path.downcase.end_with?('.xml')
fail "'#{hpxml_path}' does not exist or is not an .xml file."
end

_hpxml = HPXML.new(hpxml_path: hpxml_path)

# init
new_schedules = {}

# TODO: populate new_schedules

# return if not writing schedules
return true if new_schedules.empty?

# write schedules
schedules_filepath = File.join(File.dirname(args[:output_csv_path].get), 'schedules2.csv')
write_new_schedules(new_schedules, schedules_filepath)

# modify the hpxml with the schedules path
doc = XMLHelper.parse_file(hpxml_path)
extension = XMLHelper.create_elements_as_needed(XMLHelper.get_element(doc, '/HPXML'), ['SoftwareInfo', 'extension'])
schedules_filepaths = XMLHelper.get_values(extension, 'SchedulesFilePath', :string)
if !schedules_filepaths.include?(schedules_filepath)
XMLHelper.add_element(extension, 'SchedulesFilePath', schedules_filepath, :string)

# write out the modified hpxml
XMLHelper.write_file(doc, hpxml_path)
runner.registerInfo("Wrote file: #{hpxml_path}")
end

return true
end

def write_new_schedules(schedules, schedules_filepath)
CSV.open(schedules_filepath, 'w') do |csv|
csv << schedules.keys
rows = schedules.values.transpose
rows.each do |row|
csv << row.map { |x| '%.3g' % x }
end
end
end
end

# register the measure to be used by the application
ResStockArgumentsPostHPXML.new.registerWithApplication
70 changes: 70 additions & 0 deletions measures/ResStockArgumentsPostHPXML/measure.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?xml version="1.0"?>
<measure>
<schema_version>3.1</schema_version>
<name>res_stock_arguments_post_hpxml</name>
<uid>db102ce5-ac96-4ef9-90d3-abbe53478716</uid>
<version_id>6566f1b1-977e-47da-9d62-b4cd3fae0553</version_id>
<version_modified>2025-02-04T21:19:03Z</version_modified>
<xml_checksum>2C38F48B</xml_checksum>
<class_name>ResStockArgumentsPostHPXML</class_name>
<display_name>ResStock Arguments Post-HPXML</display_name>
<description>Measure that post-processes the output of the BuildResidentialHPXML and BuildResidentialScheduleFile measures.</description>
<modeler_description>Passes in all ResStockArgumentsPostHPXML arguments from the options lookup, processes them, and then modifies output of other measures.</modeler_description>
<arguments>
<argument>
<name>hpxml_path</name>
<display_name>HPXML File Path</display_name>
<description>Absolute/relative path of the HPXML file.</description>
<type>String</type>
<required>false</required>
<model_dependent>false</model_dependent>
</argument>
<argument>
<name>building_id</name>
<display_name>Building Unit ID</display_name>
<description>The building unit number (between 1 and the number of samples).</description>
<type>String</type>
<required>false</required>
<model_dependent>false</model_dependent>
</argument>
<argument>
<name>output_csv_path</name>
<display_name>Schedules: Output CSV Path</display_name>
<description>Absolute/relative path of the csv file containing occupancy schedules. Relative paths are relative to the HPXML output path.</description>
<type>String</type>
<required>false</required>
<model_dependent>false</model_dependent>
</argument>
</arguments>
<outputs />
<provenances />
<tags>
<tag>Whole Building.Space Types</tag>
</tags>
<attributes>
<attribute>
<name>Measure Type</name>
<value>ModelMeasure</value>
<datatype>string</datatype>
</attribute>
</attributes>
<files>
<file>
<version>
<software_program>OpenStudio</software_program>
<identifier>3.3.0</identifier>
<min_compatible>3.3.0</min_compatible>
</version>
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>A81E9245</checksum>
</file>
<file>
<filename>test_resstock_arguments_post_hpxml.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>31C4A0A8</checksum>
</file>
</files>
</measure>
Loading

0 comments on commit 819683e

Please sign in to comment.