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

ReportUtilityBills: remove electric storage from electricity produced #1554

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ __Bugfixes__
- Various HVAC sizing bugfixes and improvements.
- Fixes low-speed heating COPs for some two-speed ASHPs and cooling COPs for some single-speed ACs/HPs.
- BuildResidentialHPXML measure: Fixes air distribution CFA served when there is not a central system that meets 100% of the load.
- ReportUtilityBills measure: Fixes detailed bill calculations to exclude any metered battery production.

## OpenStudio-HPXML v1.6.0

Expand Down
22 changes: 14 additions & 8 deletions ReportUtilityBills/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,16 @@ def energyPlusOutputRequests(runner, user_arguments)
has_fuel = hpxml.has_fuels(Constants.FossilFuels, hpxml.to_doc)
has_fuel[HPXML::FuelTypeElectricity] = true

# Fuel outputs
# Has production
has_pv = @hpxml_buildings.select { |hpxml_bldg| !hpxml_bldg.pv_systems.empty? }.size > 0
has_battery = @model.getElectricLoadCenterStorageLiIonNMCBatterys.size > 0

# Fuel outputs
fuels.each do |(fuel_type, is_production), fuel|
fuel.meters.each do |meter|
next unless has_fuel[hpxml_fuel_map[fuel_type]]
next if is_production && !has_pv
next if meter.include?('Storage') && !has_battery # we don't need to request this meter if there isn't a modeled battery

result << OpenStudio::IdfObject.load("Output:Meter,#{meter},monthly;").get
if fuel_type == FT::Elec && @hpxml_header.utility_bill_scenarios.has_detailed_electric_rates
Expand Down Expand Up @@ -702,8 +706,10 @@ def get_utility_bills(fuels, utility_rates, utility_bills, utility_bill_scenario
# @return [TODO] TODO
def setup_fuel_outputs()
fuels = {}
fuels[[FT::Elec, false]] = Fuel.new(meters: ["#{EPlus::FuelTypeElectricity}:Facility"], units: UtilityBills.get_fuel_units(HPXML::FuelTypeElectricity))
fuels[[FT::Elec, true]] = Fuel.new(meters: ["#{EPlus::FuelTypeElectricity}Produced:Facility"], units: UtilityBills.get_fuel_units(HPXML::FuelTypeElectricity))
# We add Electric Storage energy onto the Electricity fuel meter
fuels[[FT::Elec, false]] = Fuel.new(meters: ["#{EPlus::FuelTypeElectricity}:Facility", "ElectricStorage:#{EPlus::FuelTypeElectricity}Produced"], units: UtilityBills.get_fuel_units(HPXML::FuelTypeElectricity))
# We don't want Electric Storage energy here
fuels[[FT::Elec, true]] = Fuel.new(meters: ["Photovoltaic:#{EPlus::FuelTypeElectricity}Produced", "PowerConversion:#{EPlus::FuelTypeElectricity}Produced"], units: UtilityBills.get_fuel_units(HPXML::FuelTypeElectricity))
fuels[[FT::Gas, false]] = Fuel.new(meters: ["#{EPlus::FuelTypeNaturalGas}:Facility"], units: UtilityBills.get_fuel_units(HPXML::FuelTypeNaturalGas))
fuels[[FT::Oil, false]] = Fuel.new(meters: ["#{EPlus::FuelTypeOil}:Facility"], units: UtilityBills.get_fuel_units(HPXML::FuelTypeOil))
fuels[[FT::Propane, false]] = Fuel.new(meters: ["#{EPlus::FuelTypePropane}:Facility"], units: UtilityBills.get_fuel_units(HPXML::FuelTypePropane))
Expand Down Expand Up @@ -749,18 +755,17 @@ def get_outputs(fuels, utility_bill_scenario)

timeseries_freq = 'monthly'
timeseries_freq = 'hourly' if fuel_type == FT::Elec && !utility_bill_scenario.elec_tariff_filepath.nil?
fuel.timeseries = get_report_meter_data_timeseries(fuel.meters, unit_conv, 0, timeseries_freq)
fuel.timeseries = get_report_meter_data_timeseries(fuel.meters, unit_conv, timeseries_freq)
end
end

# TODO
#
# @param meter_names [TODO] TODO
# @param unit_conv [TODO] TODO
# @param unit_adder [TODO] TODO
# @param timeseries_freq [TODO] TODO
# @return [TODO] TODO
def get_report_meter_data_timeseries(meter_names, unit_conv, unit_adder, timeseries_freq)
def get_report_meter_data_timeseries(meter_names, unit_conv, timeseries_freq)
msgpack_timeseries_name = { 'hourly' => 'Hourly',
'monthly' => 'Monthly' }[timeseries_freq]
begin
Expand All @@ -775,8 +780,9 @@ def get_report_meter_data_timeseries(meter_names, unit_conv, unit_adder, timeser
rows.each do |row|
row = row[row.keys[0]]
val = 0.0
indexes.each do |i|
val += row[i] * unit_conv + unit_adder
indexes.each_with_index do |i, j|
unit_conv *= -1 if j == meter_names.index("ElectricStorage:#{EPlus::FuelTypeElectricity}Produced")
val += row[i] * unit_conv
end
vals << val
end
Expand Down
8 changes: 4 additions & 4 deletions ReportUtilityBills/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_utility_bills</name>
<uid>ca88a425-e59a-4bc4-af51-c7e7d1e960fe</uid>
<version_id>2b64d6ee-3ffd-4cc9-8d03-d4d074889bd0</version_id>
<version_modified>2024-06-05T21:34:48Z</version_modified>
<version_id>c90f95d7-bad1-4e59-85e1-cc4138e9e261</version_id>
<version_modified>2024-06-11T18:58:26Z</version_modified>
<xml_checksum>15BF4E57</xml_checksum>
<class_name>ReportUtilityBills</class_name>
<display_name>Utility Bills Report</display_name>
Expand Down Expand Up @@ -180,7 +180,7 @@
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>AD1D9C67</checksum>
<checksum>5D52D3C6</checksum>
</file>
<file>
<filename>detailed_rates/Sample Flat Rate Min Annual Charge.json</filename>
Expand Down Expand Up @@ -342,7 +342,7 @@
<filename>test_report_utility_bills.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>CDF8B24F</checksum>
<checksum>7B65C730</checksum>
</file>
</files>
</measure>
12 changes: 12 additions & 0 deletions ReportUtilityBills/tests/test_report_utility_bills.rb
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,18 @@ def test_workflow_detailed_calculations
_check_monthly_bills(actual_bills, actual_monthly_bills)
end

def test_workflow_detailed_calculations_scheduled_battery
# Detailed Rate.json was renamed from Jackson Electric Member Corp - A Residential Service Senior Citizen Low Income Assistance (Effective 2017-01-01).json
# See https://github.com/NREL/OpenStudio-HPXML/issues/1444
@args_hash['hpxml_path'] = File.absolute_path(@tmp_hpxml_path)
hpxml = HPXML.new(hpxml_path: File.join(@sample_files_path, 'base-battery-scheduled.xml'))
hpxml.header.utility_bill_scenarios.add(name: 'Test 1', elec_tariff_filepath: '../../ReportUtilityBills/tests/Detailed Rate.json')
XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path)
actual_bills, actual_monthly_bills = _test_measure()
assert_operator(actual_bills['Test 1: Total (USD)'], :>, 0)
_check_monthly_bills(actual_bills, actual_monthly_bills)
end

def test_workflow_detailed_calculations_all_electric
# Detailed Rate.json was renamed from Jackson Electric Member Corp - A Residential Service Senior Citizen Low Income Assistance (Effective 2017-01-01).json
# See https://github.com/NREL/OpenStudio-HPXML/issues/1444
Expand Down