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

URBANopt-REopt GHP LCCA integration #481

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

# rspec test folder
spec/test_directory*

spec/reopt_ghp
Gemfile.lock
.rubocop*

Expand All @@ -30,3 +30,4 @@ example_files/python_deps/Miniconda*
example_files/python_deps/python_config.json
example_files/python_deps/python
example_files/python_deps/python-3.10

3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ gem 'parser', '3.2.2.2'
# if allow_local && File.exist?('../urbanopt-reopt-gem')
# gem 'urbanopt-reopt', path: '../urbanopt-reopt-gem'
# elsif allow_local
# gem 'urbanopt-reopt', github: 'URBANopt/urbanopt-reopt-gem', branch: 'develop'
#TODO: Comment out and change to develop once reopt gem is released.
gem 'urbanopt-reopt', github: 'URBANopt/urbanopt-reopt-gem', branch: 'ghp_lcca'
# end

# if allow_local && File.exist?('../urbanopt-reporting-gem')
Expand Down
2 changes: 1 addition & 1 deletion example_files/python_deps/dependencies.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
{ "name": "ThermalNetwork", "version": "0.2.5"},
{ "name": "urbanopt-ditto-reader", "version": "0.6.4"},
{ "name": "NREL-disco", "version": "0.5.1"},
{ "name": "geojson-modelica-translator", "version": "0.7.0"}
{ "name": "geojson-modelica-translator", "version": "0.8.0"}
]
26 changes: 26 additions & 0 deletions example_files/reopt_ghp/ghp_assumptions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"Site": {
"latitude": 39.99153232,
"longitude": -105.2648427
},
"SpaceHeatingLoad": {
},
"DomesticHotWaterLoad": {
},
"ElectricLoad": {
},
"ElectricTariff": {
"urdb_label": "594976725457a37b1175d089"
},
"GHP":{
"installed_cost_heatpump_per_ton": 1075,
"installed_cost_ghx_per_ft": 14,
"installed_cost_building_hydronic_loop_per_sqft": 1.7,
"om_cost_per_sqft_year": 0,
"macrs_bonus_fraction": 0.6,
"macrs_itc_reduction": 0.5,
"federal_itc_fraction": 0.3
},
"ExistingBoiler": {
}
}
149 changes: 145 additions & 4 deletions lib/uo_cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ class UrbanOptCLI
'des_params' => 'Make a DES system parameters config file',
'des_create' => 'Create a Modelica model',
'des_run' => 'Run a Modelica DES model',
'ghe_size' => 'Run a Ground Heat Exchanger model for sizing'
'des_process' => 'Post-Process a Modelica DES model for REopt Financial Analysis',
'ghe_size' => 'Run a Ground Heat Exchanger model for sizing',
}.freeze

def initialize
Expand Down Expand Up @@ -314,6 +315,15 @@ def opt_process
opt :reopt_scenario_assumptions_file, "\nPath to the scenario REopt assumptions JSON file you want to use. Use with the --reopt-scenario post-processor.\n" \
'If not specified, the reopt/base_assumptions.json file will be used', type: String, short: :a

opt :reopt_ghp, "\nAnalyze LCCA for GHP. This command is run with --reopt_ghp_assumptions_file (optional), --system_parameter (required), --modelica_model (required).", short: :t

opt :reopt_ghp_assumptions_file, "\nPath to the GHP REopt assumptions JSON file you want to use. Use with the --reopt-ghp post-processor.\n" \
'If not specified, the reopt_ghp/ghp_assumptions.json file will be used', type: String, short: :b

opt :system_parameter, "\nSystem Parameter file used for GHP sizing analysis. This is a required argument for the REopt GHP LCCA Analysis.", default: 'system_parameter.json', short: :y

opt :modelica_model, "\Path to GHP Modelica project dir created and run previously. This is a required argument for the REopt GHP LCCA Analysis.", default: 'modelica', short: :m

opt :scenario, "\nSelect which scenario to optimize", default: 'baseline_scenario.csv', required: true, short: :s

opt :feature, "\nSelect which FeatureFile to use", default: 'example_project.json', required: true, short: :f
Expand Down Expand Up @@ -410,6 +420,23 @@ def opt_des_run

opt :model, "\nPath to Modelica model dir, possibly created with 'des_create' command in this CLI\n" \
'Example: uo des_run --model path/to/model/dir', type: String, required: true

opt :start_time, "\nStart time of the simulation (seconds of a year)\n", type: Integer, required: false, short: :a\

opt :stop_time, "\nStop time of the simulation (seconds of a year)\n", type: Integer, required: false, short: :z\

opt :step_size, "\nStep size of the simulation (seconds)\n", type: Integer, required: false, short: :x\

opt :interval, "\nNumber of intervals to divide the simulation into (alternative to step_size)\n", type: Integer, required: false, short: :i\
end
end

def opt_des_process
@subopts = Optimist.options do
banner "\nURBANopt #{@command}:\n \n"

opt :model, "\nPath to Modelica model dir, possibly created with 'des_create' command in this CLI\n" \
'Example: uo des_process --model path/to/model/dir', type: String, required: true
end
end

Expand All @@ -427,7 +454,6 @@ def opt_ghe_size
"Example: uo ghe_size --sys-param-file path/to/sys_params.json --feature path/to/example_project.json\n", type: String, required: true, short: :f
end
end

attr_reader :mainopts, :command, :subopts
end

Expand Down Expand Up @@ -1488,7 +1514,7 @@ def self.install_python_dependencies

# Post-process the scenario
if @opthash.command == 'process'
if @opthash.subopts[:default] == false && @opthash.subopts[:opendss] == false && @opthash.subopts[:reopt_scenario] == false && @opthash.subopts[:reopt_feature] == false && @opthash.subopts[:disco] == false
if @opthash.subopts[:default] == false && @opthash.subopts[:opendss] == false && @opthash.subopts[:reopt_scenario] == false && @opthash.subopts[:reopt_feature] == false && @opthash.subopts[:disco] == false && @opthash.subopts[:reopt_ghp] == false
abort("\nERROR: No valid process type entered. Must enter a valid process type\n")
end

Expand All @@ -1504,6 +1530,8 @@ def self.install_python_dependencies
scenario_report.save(file_name = 'default_scenario_report', save_feature_reports: false)
scenario_report.feature_reports.each(&:save)

run_dir = File.join(@root_dir, 'run', @scenario_name.downcase)

if @opthash.subopts[:with_database] == true
default_post_processor.create_scenario_db_file
end
Expand Down Expand Up @@ -1611,11 +1639,89 @@ def self.install_python_dependencies
results << { process_type: 'reopt_feature', status: 'Complete', timestamp: Time.now.strftime('%Y-%m-%dT%k:%M:%S.%L') }
puts "\nDone\n"
end
elsif @opthash.subopts[:reopt_ghp] == true

puts "\nPerforming REopt LCCA Analysis for GHP"

if @opthash.subopts[:system_parameter].nil? || @opthash.subopts[:modelica_model].nil?
abort("System Parameter and Modelica Model arguments must be provided to run GHP LCCA analysis.")
end

run_dir = File.join(@root_dir, 'run', @scenario_name.downcase)

# system parameter
if @opthash.subopts[:system_parameter]
system_parameter = File.expand_path(@opthash.subopts[:system_parameter])
loop_order = File.join(File.dirname(system_parameter), '_loop_order_list.json')
if !File.exist?(loop_order)
puts "Run the Thermal Network Analysis using --ghe_size prior to running this command"
end
end

# modelica result
if @opthash.subopts[:modelica_model]
modelica_model = @opthash.subopts[:modelica_model]
base_model_name = File.basename(modelica_model)
modelica_result = File.expand_path(File.join(modelica_model, "#{base_model_name}.Districts.DistrictEnergySystem_results","#{base_model_name}.Districts.DistrictEnergySystem_result.csv"))
unless File.exist?(modelica_result)
abort("Modelica results need to be processed using des_process prior to running this commmand")
end
end

# make reopt_ghp folder (if it does not exist)
reopt_ghp_dir = File.join(@root_dir, 'reopt_ghp')

unless Dir.exist?(reopt_ghp_dir)
FileUtils.mkdir_p(reopt_ghp_dir)
puts "Created directory: #{reopt_ghp_dir}"
end

# Copy reopt GHP assumptions from CLI example files folder
$LOAD_PATH.each do |path_item|
if path_item.to_s.end_with?('example_files')
reopt_files = File.join(path_item, 'reopt_ghp')

if Dir.exist?(reopt_files)
Pathname.new(reopt_files).children.each do |reopt_file|
target_path = File.join(reopt_ghp_dir, reopt_file.basename)
FileUtils.cp(reopt_file, target_path)
puts "Copied #{reopt_file} to #{target_path}"
end
else
puts "Directory does not exist: #{reopt_files}"
end
end
end


# see if reopt-scenario-assumptions-file was passed in, otherwise use the default
reopt_ghp_assumptions = File.join(@root_dir, 'reopt_ghp', 'ghp_assumptions.json')
if @opthash.subopts[:reopt_ghp_assumptions_file]
reopt_ghp_assumptions = File.expand_path(@opthash.subopts[:reopt_ghp_assumptions_file]).to_s
end

puts "\nRunning the REopt GHP LCCA assumptions file: #{reopt_ghp_assumptions}\n"

reopt_ghp_post_processor = URBANopt::REopt::REoptGHPPostProcessor.new(
run_dir,
system_parameter,
modelica_model,
reopt_ghp_assumptions,
DEVELOPER_NREL_KEY,
false
)

reopt_ghp_post_processor.run_reopt_lcca(run_dir)

results << { process_type: 'reopt_ghp', status: 'Complete', timestamp: Time.now.strftime('%Y-%m-%dT%k:%M:%S.%L') }
puts "\nDone\n"


end

# write process status file
File.open(process_filename, 'w') { |f| f.write JSON.pretty_generate(results) }

end

if @opthash.command == 'visualize'
Expand Down Expand Up @@ -1867,6 +1973,41 @@ def self.install_python_dependencies
des_cli_root = "#{res[:pvars][:gmt_path]} run-model"
if @opthash.subopts[:model]
des_cli_addition = " #{File.expand_path(@opthash.subopts[:model])}"
if @opthash.subopts[:start_time]
des_cli_addition += " -a #{@opthash.subopts[:start_time]}"
end
if @opthash.subopts[:stop_time]
des_cli_addition += " -z #{@opthash.subopts[:stop_time]}"
end
if @opthash.subopts[:step_size]
des_cli_addition += " -x #{@opthash.subopts[:step_size]}"
end
if @opthash.subopts[:interval]
des_cli_addition += " -i #{@opthash.subopts[:interval]}"
end
else
abort("\nCommand must include Modelica model name. Please try again")
end

begin
system(des_cli_root + des_cli_addition)
rescue FileNotFoundError
abort("\nMust simulate using 'uo run' before preparing Modelica models.")
rescue StandardError => e
puts "\nERROR: #{e.message}"
end
end

if @opthash.command == 'des_process'
# first check python
res = check_python
if res[:python] == false
puts "\nPython error: #{res[:message]}"
abort("\nPython dependencies are needed to run this workflow. Install with the CLI command: uo install_python \n")
end
des_cli_root = "#{res[:pvars][:gmt_path]} process-model"
if @opthash.subopts[:model]
des_cli_addition = " #{@opthash.subopts[:model]}"
else
abort("\nCommand must include Modelica model name. Please try again")
end
Expand Down
11 changes: 11 additions & 0 deletions spec/spec_files/reopt_ghp/_loop_order.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
{
"list_bldg_ids_in_group": [
"4",
"5"
],
"list_ghe_ids_in_group": [
"7932a208-dcb6-4d23-a46f-288896eaa1bc"
]
}
]
Loading