Skip to content

Commit

Permalink
Merge pull request #1012 from NREL/simple-bill-calcs2
Browse files Browse the repository at this point in the history
Simple bill calcs (enhancement)
  • Loading branch information
joseph-robertson committed Jun 13, 2023
2 parents 79c130d + 9325dc0 commit 9c08240
Show file tree
Hide file tree
Showing 18 changed files with 7,720 additions and 7,429 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ jobs:
- name: Run buildstockbatch
run: |
pip install git+https://github.com/NREL/buildstockbatch.git@v2023.05.0
pip install git+https://github.com/NREL/buildstockbatch.git@v2023.06.0
buildstock_local project_national/national_baseline.yml
buildstock_local project_testing/testing_baseline.yml
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Fixes

Features
- Include battery modeling capabilities for project_testing ([#1009](https://github.com/NREL/resstock/pull/1009))
- Add ability to calculate simple utility bills based on a user-specified TSV file of utility rates ([#1012](https://github.com/NREL/resstock/pull/1012))
- Ability to check buildstock csv against an options lookup as a command line utility ([#1042](https://github.com/NREL/resstock/pull/1042))
- Demonstrate new power outage modeling feature using upgrades specified in example project yml files ([#1054](https://github.com/NREL/resstock/pull/1054))
- Ability to specify a "sample_weight" column in the precomputed buildstock.csv ([#1056](https://github.com/NREL/resstock/pull/1056))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ build_existing_model.utility_bill_pv_monthly_grid_connection_fees,"Utility bill
build_existing_model.utility_bill_pv_net_metering_annual_excess_sellback_rate_types,"Utility bill PV net metering annual excess sellback rate types. Only applies if the PV compensation type is 'NetMetering'. If multiple scenarios, use a comma-separated list."
build_existing_model.utility_bill_pv_net_metering_annual_excess_sellback_rates,"Utility bill PV net metering annual excess sellback rates. Only applies if the PV compensation type is 'NetMetering' and the PV annual excess sellback rate type is 'User-Specified'. If multiple scenarios, use a comma-separated list."
build_existing_model.utility_bill_scenario_names,"Names of utility bill scenarios. If multiple scenarios, use a comma-separated list. If multiple scenarios, use a comma-separated list."
build_existing_model.utility_bill_simple_filepaths,"Relative paths of simple utility rates. Paths are relative to the resources folder. If multiple scenarios, use a comma-separated list. Files must contain the name of the Parameter as the column header."
build_existing_model.utility_bill_wood_fixed_charges,"Wood utility bill monthly fixed charges. If multiple scenarios, use a comma-separated list."
build_existing_model.utility_bill_wood_marginal_rates,"Wood utility bill marginal rates. If multiple scenarios, use a comma-separated list."
build_existing_model.weather_file_city,City from the EPW weather file.
Expand Down
169 changes: 158 additions & 11 deletions measures/BuildExistingModel/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument
arg.setDescription('Names of utility bill scenarios. If multiple scenarios, use a comma-separated list. If multiple scenarios, use a comma-separated list.')
args << arg

arg = OpenStudio::Measure::OSArgument.makeStringArgument('utility_bill_simple_filepaths', false)
arg.setDisplayName('Utility Bills: Simple Filepaths')
arg.setDescription('Relative paths of simple utility rates. Paths are relative to the resources folder. If multiple scenarios, use a comma-separated list. Files must contain the name of the Parameter as the column header.')
args << arg

arg = OpenStudio::Measure::OSArgument.makeStringArgument('utility_bill_electricity_fixed_charges', false)
arg.setDisplayName('Utility Bills: Electricity Fixed Charges')
arg.setDescription('Electricity utility bill monthly fixed charges. If multiple scenarios, use a comma-separated list.')
Expand Down Expand Up @@ -412,38 +417,180 @@ def run(model, runner, user_arguments)

# Utility Bills
if args[:utility_bill_scenario_names].is_initialized
utility_bill_scenario_names = args[:utility_bill_scenario_names].get

utility_bill_scenario_names = args[:utility_bill_scenario_names].get.split(',').map(&:strip)

utility_bill_simple_filepaths = args[:utility_bill_simple_filepaths].get.split(',').map(&:strip)
if utility_bill_simple_filepaths.empty?
utility_bill_simple_filepaths = [nil] * utility_bill_scenario_names.size
end

utility_bill_electricity_fixed_charges = args[:utility_bill_electricity_fixed_charges].get.split(',').map(&:strip)
if utility_bill_electricity_fixed_charges.empty?
utility_bill_electricity_fixed_charges = [nil] * utility_bill_scenario_names.size
end

utility_bill_electricity_marginal_rates = args[:utility_bill_electricity_marginal_rates].get.split(',').map(&:strip)
if utility_bill_electricity_marginal_rates.empty?
utility_bill_electricity_marginal_rates = [nil] * utility_bill_scenario_names.size
end

utility_bill_natural_gas_fixed_charges = args[:utility_bill_natural_gas_fixed_charges].get.split(',').map(&:strip)
if utility_bill_natural_gas_fixed_charges.empty?
utility_bill_natural_gas_fixed_charges = [nil] * utility_bill_scenario_names.size
end

utility_bill_natural_gas_marginal_rates = args[:utility_bill_natural_gas_marginal_rates].get.split(',').map(&:strip)
if utility_bill_natural_gas_marginal_rates.empty?
utility_bill_natural_gas_marginal_rates = [nil] * utility_bill_scenario_names.size
end

utility_bill_propane_fixed_charges = args[:utility_bill_propane_fixed_charges].get.split(',').map(&:strip)
if utility_bill_propane_fixed_charges.empty?
utility_bill_propane_fixed_charges = [nil] * utility_bill_scenario_names.size
end

utility_bill_propane_marginal_rates = args[:utility_bill_propane_marginal_rates].get.split(',').map(&:strip)
if utility_bill_propane_marginal_rates.empty?
utility_bill_propane_marginal_rates = [nil] * utility_bill_scenario_names.size
end

utility_bill_fuel_oil_fixed_charges = args[:utility_bill_fuel_oil_fixed_charges].get.split(',').map(&:strip)
if utility_bill_fuel_oil_fixed_charges.empty?
utility_bill_fuel_oil_fixed_charges = [nil] * utility_bill_scenario_names.size
end

utility_bill_fuel_oil_marginal_rates = args[:utility_bill_fuel_oil_marginal_rates].get.split(',').map(&:strip)
if utility_bill_fuel_oil_marginal_rates.empty?
utility_bill_fuel_oil_marginal_rates = [nil] * utility_bill_scenario_names.size
end

utility_bill_wood_fixed_charges = args[:utility_bill_wood_fixed_charges].get.split(',').map(&:strip)
if utility_bill_wood_fixed_charges.empty?
utility_bill_wood_fixed_charges = [nil] * utility_bill_scenario_names.size
end

utility_bill_wood_marginal_rates = args[:utility_bill_wood_marginal_rates].get.split(',').map(&:strip)
if utility_bill_wood_marginal_rates.empty?
utility_bill_wood_marginal_rates = [nil] * utility_bill_scenario_names.size
end

utility_bill_scenarios = utility_bill_scenario_names.zip(utility_bill_simple_filepaths,
utility_bill_electricity_fixed_charges,
utility_bill_electricity_marginal_rates,
utility_bill_natural_gas_fixed_charges,
utility_bill_natural_gas_marginal_rates,
utility_bill_propane_fixed_charges,
utility_bill_propane_marginal_rates,
utility_bill_fuel_oil_fixed_charges,
utility_bill_fuel_oil_marginal_rates,
utility_bill_wood_fixed_charges,
utility_bill_wood_marginal_rates)

utility_bill_electricity_fixed_charges = []
utility_bill_electricity_marginal_rates = []
utility_bill_natural_gas_fixed_charges = []
utility_bill_natural_gas_marginal_rates = []
utility_bill_propane_fixed_charges = []
utility_bill_propane_marginal_rates = []
utility_bill_fuel_oil_fixed_charges = []
utility_bill_fuel_oil_marginal_rates = []
utility_bill_wood_fixed_charges = []
utility_bill_wood_marginal_rates = []
utility_bill_scenarios.each do |utility_bill_scenario|
_name, simple_filepath, electricity_fixed_charge, electricity_marginal_rate, natural_gas_fixed_charge, natural_gas_marginal_rate, propane_fixed_charge, propane_marginal_rate, fuel_oil_fixed_charge, fuel_oil_marginal_rate, wood_fixed_charge, wood_marginal_rate = utility_bill_scenario

if !simple_filepath.nil? && !simple_filepath.empty?
simple_filepath = File.join(resources_dir, simple_filepath)
if !File.exist?(simple_filepath)
runner.registerError("Utility bill scenario file '#{simple_filepath}' does not exist.")
return false
end

rows = CSV.read(simple_filepath, headers: true, col_sep: "\t")
utility_rates = rows.map { |d| d.to_hash }
parameter = utility_rates[0].keys[0]

if !bldg_data.keys.include?(parameter)
runner.registerError("Utility bill scenario(s) were specified, but could not find #{parameter}.")
return false
end

utility_rates = utility_rates.select { |r| r[parameter] == bldg_data[parameter] }

if utility_rates.size != 1
runner.registerWarning("Could not find #{parameter}=#{bldg_data[parameter]} in #{simple_filepath}.")
utility_rate = Hash[rows.headers.map { |x| [x, nil] }]
else
utility_rate = utility_rates[0]
end

utility_bill_electricity_fixed_charges << utility_rate['electricity_fixed_charge']
utility_bill_electricity_marginal_rates << utility_rate['electricity_marginal_rate']
utility_bill_natural_gas_fixed_charges << utility_rate['natural_gas_fixed_charge']
utility_bill_natural_gas_marginal_rates << utility_rate['natural_gas_marginal_rate']
utility_bill_propane_fixed_charges << utility_rate['propane_fixed_charge']
utility_bill_propane_marginal_rates << utility_rate['propane_marginal_rate']
utility_bill_fuel_oil_fixed_charges << utility_rate['fuel_oil_fixed_charge']
utility_bill_fuel_oil_marginal_rates << utility_rate['fuel_oil_marginal_rate']
utility_bill_wood_fixed_charges << utility_rate['wood_fixed_charge']
utility_bill_wood_marginal_rates << utility_rate['wood_marginal_rate']
else
utility_bill_electricity_fixed_charges << electricity_fixed_charge
utility_bill_electricity_marginal_rates << electricity_marginal_rate
utility_bill_natural_gas_fixed_charges << natural_gas_fixed_charge
utility_bill_natural_gas_marginal_rates << natural_gas_marginal_rate
utility_bill_propane_fixed_charges << propane_fixed_charge
utility_bill_propane_marginal_rates << propane_marginal_rate
utility_bill_fuel_oil_fixed_charges << fuel_oil_fixed_charge
utility_bill_fuel_oil_marginal_rates << fuel_oil_marginal_rate
utility_bill_wood_fixed_charges << wood_fixed_charge
utility_bill_wood_marginal_rates << wood_marginal_rate
end
end

utility_bill_scenario_names = utility_bill_scenario_names.join(',')
measures['BuildResidentialHPXML'][0]['utility_bill_scenario_names'] = utility_bill_scenario_names

utility_bill_electricity_fixed_charges = args[:utility_bill_electricity_fixed_charges].get
utility_bill_electricity_fixed_charges = utility_bill_electricity_fixed_charges.join(',')
measures['BuildResidentialHPXML'][0]['utility_bill_electricity_fixed_charges'] = utility_bill_electricity_fixed_charges
register_value(runner, 'utility_bill_electricity_fixed_charges', utility_bill_electricity_fixed_charges)

utility_bill_electricity_marginal_rates = args[:utility_bill_electricity_marginal_rates].get
utility_bill_electricity_marginal_rates = utility_bill_electricity_marginal_rates.join(',')
measures['BuildResidentialHPXML'][0]['utility_bill_electricity_marginal_rates'] = utility_bill_electricity_marginal_rates
register_value(runner, 'utility_bill_electricity_marginal_rates', utility_bill_electricity_marginal_rates)

utility_bill_natural_gas_fixed_charges = args[:utility_bill_natural_gas_fixed_charges].get
utility_bill_natural_gas_fixed_charges = utility_bill_natural_gas_fixed_charges.join(',')
measures['BuildResidentialHPXML'][0]['utility_bill_natural_gas_fixed_charges'] = utility_bill_natural_gas_fixed_charges
register_value(runner, 'utility_bill_natural_gas_fixed_charges', utility_bill_natural_gas_fixed_charges)

utility_bill_natural_gas_marginal_rates = args[:utility_bill_natural_gas_marginal_rates].get
utility_bill_natural_gas_marginal_rates = utility_bill_natural_gas_marginal_rates.join(',')
measures['BuildResidentialHPXML'][0]['utility_bill_natural_gas_marginal_rates'] = utility_bill_natural_gas_marginal_rates
register_value(runner, 'utility_bill_natural_gas_marginal_rates', utility_bill_natural_gas_marginal_rates)

utility_bill_propane_fixed_charges = args[:utility_bill_propane_fixed_charges].get
utility_bill_propane_fixed_charges = utility_bill_propane_fixed_charges.join(',')
measures['BuildResidentialHPXML'][0]['utility_bill_propane_fixed_charges'] = utility_bill_propane_fixed_charges
register_value(runner, 'utility_bill_propane_fixed_charges', utility_bill_propane_fixed_charges)

utility_bill_propane_marginal_rates = args[:utility_bill_propane_marginal_rates].get
utility_bill_propane_marginal_rates = utility_bill_propane_marginal_rates.join(',')
measures['BuildResidentialHPXML'][0]['utility_bill_propane_marginal_rates'] = utility_bill_propane_marginal_rates
register_value(runner, 'utility_bill_propane_marginal_rates', utility_bill_propane_marginal_rates)

utility_bill_fuel_oil_fixed_charges = args[:utility_bill_fuel_oil_fixed_charges].get
utility_bill_fuel_oil_fixed_charges = utility_bill_fuel_oil_fixed_charges.join(',')
measures['BuildResidentialHPXML'][0]['utility_bill_fuel_oil_fixed_charges'] = utility_bill_fuel_oil_fixed_charges
register_value(runner, 'utility_bill_fuel_oil_fixed_charges', utility_bill_fuel_oil_fixed_charges)

utility_bill_fuel_oil_marginal_rates = args[:utility_bill_fuel_oil_marginal_rates].get
utility_bill_fuel_oil_marginal_rates = utility_bill_fuel_oil_marginal_rates.join(',')
measures['BuildResidentialHPXML'][0]['utility_bill_fuel_oil_marginal_rates'] = utility_bill_fuel_oil_marginal_rates
register_value(runner, 'utility_bill_fuel_oil_marginal_rates', utility_bill_fuel_oil_marginal_rates)

utility_bill_wood_fixed_charges = args[:utility_bill_wood_fixed_charges].get
utility_bill_wood_fixed_charges = utility_bill_wood_fixed_charges.join(',')
measures['BuildResidentialHPXML'][0]['utility_bill_wood_fixed_charges'] = utility_bill_wood_fixed_charges
register_value(runner, 'utility_bill_wood_fixed_charges', utility_bill_wood_fixed_charges)

utility_bill_wood_marginal_rates = args[:utility_bill_wood_marginal_rates].get
utility_bill_wood_marginal_rates = utility_bill_wood_marginal_rates.join(',')
measures['BuildResidentialHPXML'][0]['utility_bill_wood_marginal_rates'] = utility_bill_wood_marginal_rates
register_value(runner, 'utility_bill_wood_marginal_rates', utility_bill_wood_marginal_rates)

utility_bill_pv_compensation_types = args[:utility_bill_pv_compensation_types].get
measures['BuildResidentialHPXML'][0]['utility_bill_pv_compensation_types'] = utility_bill_pv_compensation_types
Expand Down
14 changes: 11 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>2cbbedc8-e178-41e0-9dc0-37db93544dc8</version_id>
<version_modified>2023-05-31T22:39:26Z</version_modified>
<version_id>ea432f5d-93a2-4116-b9d0-a35123c7722d</version_id>
<version_modified>2023-06-08T18:07:12Z</version_modified>
<xml_checksum>2C38F48B</xml_checksum>
<class_name>BuildExistingModel</class_name>
<display_name>Build Existing Model</display_name>
Expand Down Expand Up @@ -161,6 +161,14 @@
<required>false</required>
<model_dependent>false</model_dependent>
</argument>
<argument>
<name>utility_bill_simple_filepaths</name>
<display_name>Utility Bills: Simple Filepaths</display_name>
<description>Relative paths of simple utility rates. Paths are relative to the resources folder. If multiple scenarios, use a comma-separated list. Files must contain the name of the Parameter as the column header.</description>
<type>String</type>
<required>false</required>
<model_dependent>false</model_dependent>
</argument>
<argument>
<name>utility_bill_electricity_fixed_charges</name>
<display_name>Utility Bills: Electricity Fixed Charges</display_name>
Expand Down Expand Up @@ -312,7 +320,7 @@
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>CCFA81D9</checksum>
<checksum>DE976555</checksum>
</file>
</files>
</measure>
6 changes: 6 additions & 0 deletions project_testing/testing_baseline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ workflow_generator:
pv_monthly_grid_connection_fee_units: $/kW
pv_monthly_grid_connection_fee: 2.5

- scenario_name: Bills2
simple_filepath: data/simple_rates/State.tsv

- scenario_name: Bills3
simple_filepath: data/simple_rates/County.tsv

simulation_output_report:
timeseries_frequency: hourly
include_timeseries_total_consumptions: true
Expand Down
6 changes: 6 additions & 0 deletions project_testing/testing_upgrades.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ workflow_generator:
pv_monthly_grid_connection_fee_units: $/kW
pv_monthly_grid_connection_fee: 2.5

- scenario_name: Bills2
simple_filepath: data/simple_rates/State.tsv

- scenario_name: Bills3
simple_filepath: data/simple_rates/County.tsv

simulation_output_report:
timeseries_frequency: hourly
include_timeseries_total_consumptions: true
Expand Down

0 comments on commit 9c08240

Please sign in to comment.