Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Total water use outputs #1786

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ __New Features__
- BuildResidentialScheduleFile measure:
- **Breaking change**: Replaced `slab_under_width` argument with `slab_under_insulation_width`.
- **Breaking change**: Replaced `slab_perimeter_depth` argument with `slab_perimeter_insulation_depth`.
- Output updates:
- Adds total water volume outputs.

__Bugfixes__
- Prevents possible error when using multiple `Attic`/`Foundation` elements for the same attic/foundation type.
Expand Down
12 changes: 9 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>120754c6-25ec-4f11-9a26-0a7833ae9443</version_id>
<version_modified>2024-07-23T16:13:45Z</version_modified>
<version_id>34e72af0-d8f4-4269-8493-61fab9d9ab48</version_id>
<version_modified>2024-07-25T16:15:18Z</version_modified>
<xml_checksum>D8922A73</xml_checksum>
<class_name>HPXMLtoOpenStudio</class_name>
<display_name>HPXML to OpenStudio Translator</display_name>
Expand Down Expand Up @@ -435,7 +435,7 @@
<filename>output.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>37D464E6</checksum>
<checksum>DE8D7860</checksum>
</file>
<file>
<filename>psychrometrics.rb</filename>
Expand Down Expand Up @@ -629,6 +629,12 @@
<usage_type>resource</usage_type>
<checksum>93120E27</checksum>
</file>
<file>
<filename>in.schedules.csv</filename>
<filetype>csv</filetype>
<usage_type>test</usage_type>
<checksum>B0D702CF</checksum>
</file>
<file>
<filename>test_airflow.rb</filename>
<filetype>rb</filetype>
Expand Down
9 changes: 9 additions & 0 deletions HPXMLtoOpenStudio/resources/output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ module HWT
DistributionWaste = 'Distribution Waste'
end

# TODO
module TWT
# Total Water Types
ClothesWasher = 'Clothes Washer'
Dishwasher = 'Dishwasher'
Fixtures = 'Fixtures'
DistributionWaste = 'Distribution Waste'
end

# TODO
module LT
# Load Types
Expand Down
30 changes: 30 additions & 0 deletions ReportSimulationOutput/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,17 @@ Generates annual hot water usages for each end use.

<br/>

**Generate Annual Output: Total Water Uses**

Generates annual total water usages for each end use.

- **Name:** ``include_annual_total_water_uses``
- **Type:** ``Boolean``

- **Required:** ``false``

<br/>

**Generate Annual Output: HVAC Summary**

Generates HVAC capacities, design temperatures, and design loads.
Expand Down Expand Up @@ -290,6 +301,17 @@ Generates timeseries hot water usages for each end use.

<br/>

**Generate Timeseries Output: Total Water Uses**

Generates timeseries total water usages for each end use.

- **Name:** ``include_timeseries_total_water_uses``
- **Type:** ``Boolean``

- **Required:** ``false``

<br/>

**Generate Timeseries Output: Total Loads**

Generates timeseries heating, cooling, and hot water loads.
Expand Down Expand Up @@ -782,6 +804,14 @@ All possible measure outputs are listed below. Actual outputs depend on measure

- ``hot_water_distribution_waste_gal``

- ``total_water_clothes_washer_gal``

- ``total_water_dishwasher_gal``

- ``total_water_fixtures_gal``

- ``total_water_distribution_waste_gal``

- ``resilience_battery_hr``


93 changes: 86 additions & 7 deletions ReportSimulationOutput/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument
arg.setDefaultValue(true)
args << arg

arg = OpenStudio::Measure::OSArgument::makeBoolArgument('include_annual_total_water_uses', false)
arg.setDisplayName('Generate Annual Output: Total Water Uses')
arg.setDescription('Generates annual total water usages for each end use.')
arg.setDefaultValue(true)
args << arg

arg = OpenStudio::Measure::OSArgument::makeBoolArgument('include_annual_hvac_summary', false)
arg.setDisplayName('Generate Annual Output: HVAC Summary')
arg.setDescription('Generates HVAC capacities, design temperatures, and design loads.')
Expand Down Expand Up @@ -197,6 +203,12 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument
arg.setDefaultValue(false)
args << arg

arg = OpenStudio::Measure::OSArgument::makeBoolArgument('include_timeseries_total_water_uses', false)
arg.setDisplayName('Generate Timeseries Output: Total Water Uses')
arg.setDescription('Generates timeseries total water usages for each end use.')
arg.setDefaultValue(false)
args << arg

arg = OpenStudio::Measure::OSArgument::makeBoolArgument('include_timeseries_total_loads', false)
arg.setDisplayName('Generate Timeseries Output: Total Loads')
arg.setDescription('Generates timeseries heating, cooling, and hot water loads.')
Expand Down Expand Up @@ -300,6 +312,7 @@ def outputs
@peak_loads,
@component_loads,
@hot_water_uses,
@total_water_uses,
@resilience].each do |outputs|
outputs.values.each do |obj|
output_name = OpenStudio::toUnderscoreCase("#{obj.name} #{obj.annual_units}")
Expand Down Expand Up @@ -408,9 +421,10 @@ def energyPlusOutputRequests(runner, user_arguments)
end
end

# End Use/Hot Water Use/Ideal Load outputs
# End Use/Hot Water Use/Total Water Use/Ideal Load outputs
{ @end_uses => args[:include_timeseries_end_use_consumptions],
@hot_water_uses => args[:include_timeseries_hot_water_uses] }.each do |uses, include_ts|
@hot_water_uses => args[:include_timeseries_hot_water_uses],
@total_water_uses => args[:include_timeseries_total_water_uses] }.each do |uses, include_ts|
uses.each do |key, use|
use.variables.each do |_sys_id, varkey, var|
result << OpenStudio::IdfObject.load("Output:Variable,#{varkey},#{var},runperiod;").get
Expand Down Expand Up @@ -901,6 +915,19 @@ def get_outputs(runner, args)
end
end

# Total Water Uses
@total_water_uses.each do |_total_water_type, total_water|
total_water.variables.map { |v| v[0] }.uniq.each do |sys_id|
keys = total_water.variables.select { |v| v[0] == sys_id }.map { |v| v[1] }
vars = total_water.variables.select { |v| v[0] == sys_id }.map { |v| v[2] }

total_water.annual_output_by_system[sys_id] = get_report_variable_data_annual(keys, vars, UnitConversions.convert(1.0, 'm^3', total_water.annual_units))
if args[:include_timeseries_total_water_uses]
total_water.timeseries_output_by_system[sys_id] = get_report_variable_data_timeseries(keys, vars, UnitConversions.convert(1.0, 'm^3', total_water.timeseries_units), 0, args[:timeseries_frequency])
end
end
end

@hpxml_bldgs.each do |hpxml_bldg|
# Apply Heating/Cooling DSEs
(hpxml_bldg.heating_systems + hpxml_bldg.heat_pumps).each do |htg_system|
Expand Down Expand Up @@ -981,7 +1008,7 @@ def get_outputs(runner, args)
end

# Calculate aggregated values from per-system values as needed
(@end_uses.values + @loads.values + @hot_water_uses.values).each do |obj|
(@end_uses.values + @loads.values + @hot_water_uses.values + @total_water_uses.values).each do |obj|
# Annual
if obj.annual_output.nil?
if not obj.annual_output_by_system.empty?
Expand Down Expand Up @@ -1632,6 +1659,14 @@ def report_runperiod_output_results(runner, outputs, args, annual_output_path)
results_out << [line_break]
end

# Total water uses
if args[:include_annual_total_water_uses]
@total_water_uses.each do |_total_water_type, total_water|
results_out << ["#{total_water.name} (#{total_water.annual_units})", total_water.annual_output.to_f.round(n_digits - 2)]
end
results_out << [line_break]
end

# Resilience
if args[:include_annual_resilience]
@resilience.each do |_type, resilience|
Expand Down Expand Up @@ -1776,6 +1811,11 @@ def report_timeseries_output_results(runner, outputs, timeseries_output_path, ar
else
hot_water_use_data = []
end
if args[:include_timeseries_total_water_uses]
total_water_use_data = @total_water_uses.values.select { |x| x.timeseries_output.sum(0.0) != 0 }.map { |x| [x.name, x.timeseries_units] + x.timeseries_output.map { |v| v.round(n_digits) } }
else
total_water_use_data = []
end
if args[:include_timeseries_total_loads]
total_loads_data = @loads.values.select { |x| x.timeseries_output.sum(0.0) != 0 }.map { |x| [x.name, x.timeseries_units] + x.timeseries_output.map { |v| v.round(n_digits) } }
else
Expand Down Expand Up @@ -1820,15 +1860,15 @@ def report_timeseries_output_results(runner, outputs, timeseries_output_path, ar
end

return if (total_energy_data.size + fuel_data.size + end_use_data.size + system_use_data.size + emissions_data.size + emission_fuel_data.size +
emission_end_use_data.size + hot_water_use_data.size + total_loads_data.size + comp_loads_data.size + unmet_hours_data.size +
emission_end_use_data.size + hot_water_use_data.size + total_water_use_data.size + total_loads_data.size + comp_loads_data.size + unmet_hours_data.size +
zone_temps_data.size + airflows_data.size + weather_data.size + resilience_data.size + output_variables_data.size) == 0

fail 'Unable to obtain timestamps.' if @timestamps.empty?

if ['csv'].include? args[:output_format]
# Assemble data
data = data.zip(*timestamps2, *timestamps3, *total_energy_data, *fuel_data, *end_use_data, *system_use_data, *emissions_data,
*emission_fuel_data, *emission_end_use_data, *hot_water_use_data, *total_loads_data, *comp_loads_data,
*emission_fuel_data, *emission_end_use_data, *hot_water_use_data, *total_water_use_data, *total_loads_data, *comp_loads_data,
*unmet_hours_data, *zone_temps_data, *airflows_data, *weather_data, *resilience_data, *output_variables_data)

# Error-check
Expand Down Expand Up @@ -1892,7 +1932,7 @@ def report_timeseries_output_results(runner, outputs, timeseries_output_path, ar
h['TimeUTC'] = timestamps3[2..-1] if timestamps_utc

[total_energy_data, fuel_data, end_use_data, system_use_data, emissions_data, emission_fuel_data,
emission_end_use_data, hot_water_use_data, total_loads_data, comp_loads_data, unmet_hours_data,
emission_end_use_data, hot_water_use_data, total_water_use_data, total_loads_data, comp_loads_data, unmet_hours_data,
zone_temps_data, airflows_data, weather_data, resilience_data, output_variables_data].each do |d|
d.each do |o|
grp, name = o[0].split(':', 2)
Expand Down Expand Up @@ -2205,7 +2245,7 @@ def create_all_object_outputs_by_key
@model.getModelObjects.sort.each do |object|
next if object.to_AdditionalProperties.is_initialized

[EUT, HWT, LT, RT].each do |class_name|
[EUT, HWT, TWT, LT, RT].each do |class_name|
vars_by_key = get_object_outputs_by_key(@model, object, class_name)
next if vars_by_key.size == 0

Expand Down Expand Up @@ -2318,6 +2358,19 @@ def initialize(outputs: [])
attr_accessor(:variables, :meters, :annual_output_by_system, :timeseries_output_by_system)
end

# TODO
class TotalWater < BaseOutput
# @param outputs [TODO] TODO
def initialize(outputs: [])
super()
@variables = outputs.select { |o| !o[2].include?(':') }
@meters = outputs.select { |o| o[2].include?(':') }
@timeseries_output_by_system = {}
@annual_output_by_system = {}
end
attr_accessor(:variables, :meters, :annual_output_by_system, :timeseries_output_by_system)
end

# TODO
class Resilience < BaseOutput
# @param variables [TODO] TODO
Expand Down Expand Up @@ -2629,6 +2682,19 @@ def get_timeseries_units_from_fuel_type(fuel_type)
hot_water.timeseries_units = 'gal'
end

# Total Water Uses
@total_water_uses = {}
@total_water_uses[TWT::ClothesWasher] = TotalWater.new(outputs: get_object_outputs(TWT, TWT::ClothesWasher))
@total_water_uses[TWT::Dishwasher] = TotalWater.new(outputs: get_object_outputs(TWT, TWT::Dishwasher))
@total_water_uses[TWT::Fixtures] = TotalWater.new(outputs: get_object_outputs(TWT, TWT::Fixtures))
@total_water_uses[TWT::DistributionWaste] = TotalWater.new(outputs: get_object_outputs(TWT, TWT::DistributionWaste))

@total_water_uses.each do |total_water_type, total_water|
total_water.name = "Total Water: #{total_water_type}"
total_water.annual_units = 'gal'
total_water.timeseries_units = 'gal'
end

# Resilience
@resilience = {}
@resilience[RT::Battery] = Resilience.new(variables: get_object_outputs(RT, RT::Battery))
Expand Down Expand Up @@ -3071,6 +3137,19 @@ def get_object_outputs_by_key(model, object, class_name)

end

elsif class_name == TWT

# Total Water Use

if object.to_WaterUseEquipment.is_initialized
total_water_use = { Constants.ObjectNameFixtures => TWT::Fixtures,
Constants.ObjectNameDistributionWaste => TWT::DistributionWaste,
Constants.ObjectNameClothesWasher => TWT::ClothesWasher,
Constants.ObjectNameDishwasher => TWT::Dishwasher }[object.to_WaterUseEquipment.get.waterUseEquipmentDefinition.endUseSubcategory]
return { total_water_use => ['Water Use Equipment Total Volume'] }

end

elsif class_name == LT

# Load
Expand Down
Loading