urbanopt-reopt 0.11.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/nightly_ci_build.yml +5 -7
- data/.gitignore +1 -1
- data/CHANGELOG.md +24 -0
- data/Gemfile +16 -11
- data/LICENSE.md +1 -1
- data/RDOC_MAIN.md +6 -6
- data/README.md +6 -6
- data/doc_templates/LICENSE.md +1 -1
- data/doc_templates/copyright_erb.txt +1 -1
- data/docs/README.md +6 -6
- data/docs/schemas/reopt-input-schema.md +25 -23
- data/docs/schemas/reopt-output-schema.md +7 -7
- data/index.md +9 -9
- data/lib/urbanopt/reopt/feature_report_adapter.rb +230 -198
- data/lib/urbanopt/reopt/reopt_ghp_adapter.rb +337 -0
- data/lib/urbanopt/reopt/reopt_ghp_api.rb +156 -0
- data/lib/urbanopt/reopt/reopt_ghp_files/reopt_ghp_assumption.json +27 -0
- data/lib/urbanopt/reopt/reopt_ghp_post_processor.rb +149 -0
- data/lib/urbanopt/reopt/reopt_lite_api.rb +84 -46
- data/lib/urbanopt/reopt/reopt_logger.rb +1 -1
- data/lib/urbanopt/reopt/reopt_post_processor.rb +12 -12
- data/lib/urbanopt/reopt/reopt_schema/REopt-GHP-input.json +148 -0
- data/lib/urbanopt/reopt/reopt_schema/reopt_input_schema.json +1125 -1105
- data/lib/urbanopt/reopt/reopt_schema/reopt_output_schema.json +488 -523
- data/lib/urbanopt/reopt/scenario_report_adapter.rb +260 -229
- data/lib/urbanopt/reopt/utilities.rb +2 -2
- data/lib/urbanopt/reopt/version.rb +1 -1
- data/lib/urbanopt/reopt.rb +3 -0
- data/urbanopt-reopt.gemspec +9 -10
- metadata +27 -64
@@ -8,7 +8,6 @@ require 'openssl'
|
|
8
8
|
require 'uri'
|
9
9
|
require 'json'
|
10
10
|
require 'securerandom'
|
11
|
-
require 'certified'
|
12
11
|
require_relative '../../../developer_nrel_key'
|
13
12
|
require 'urbanopt/reopt/reopt_logger'
|
14
13
|
|
@@ -16,7 +15,7 @@ module URBANopt # :nodoc:
|
|
16
15
|
module REopt # :nodoc:
|
17
16
|
class REoptLiteAPI
|
18
17
|
##
|
19
|
-
# \REoptLiteAPI manages submitting optimization tasks to the \REopt API and
|
18
|
+
# \REoptLiteAPI manages submitting optimization tasks to the \REopt API and receiving results.
|
20
19
|
# Results can either be sourced from the production \REopt API with an API key from developer.nrel.gov, or from
|
21
20
|
# a version running at localhost.
|
22
21
|
##
|
@@ -29,8 +28,8 @@ module URBANopt # :nodoc:
|
|
29
28
|
def initialize(nrel_developer_key = nil, use_localhost = false)
|
30
29
|
@use_localhost = use_localhost
|
31
30
|
if @use_localhost
|
32
|
-
@uri_submit = URI.parse('http//:127.0.0.1:8000/
|
33
|
-
@uri_submit_outagesimjob = URI.parse('http//:127.0.0.1:8000/
|
31
|
+
@uri_submit = URI.parse('http//:127.0.0.1:8000/v3/job/')
|
32
|
+
@uri_submit_outagesimjob = URI.parse('http//:127.0.0.1:8000/v3/outagesimjob/')
|
34
33
|
else
|
35
34
|
if [nil, '', '<insert your key here>'].include? nrel_developer_key
|
36
35
|
if [nil, '', '<insert your key here>'].include? DEVELOPER_NREL_KEY
|
@@ -40,8 +39,8 @@ module URBANopt # :nodoc:
|
|
40
39
|
end
|
41
40
|
end
|
42
41
|
@nrel_developer_key = nrel_developer_key
|
43
|
-
@uri_submit = URI.parse("https://developer.nrel.gov/api/reopt/
|
44
|
-
@uri_submit_outagesimjob = URI.parse("https://developer.nrel.gov/api/reopt/
|
42
|
+
@uri_submit = URI.parse("https://developer.nrel.gov/api/reopt/v3/job?api_key=#{@nrel_developer_key}")
|
43
|
+
@uri_submit_outagesimjob = URI.parse("https://developer.nrel.gov/api/reopt/v3/outagesimjob?api_key=#{@nrel_developer_key}")
|
45
44
|
# initialize @@logger
|
46
45
|
@@logger ||= URBANopt::REopt.reopt_logger
|
47
46
|
end
|
@@ -55,14 +54,14 @@ module URBANopt # :nodoc:
|
|
55
54
|
#
|
56
55
|
# * +run_uuid+ - _String_ - Unique run_uuid obtained from the \REopt job submittal URL for a specific optimization task.
|
57
56
|
#
|
58
|
-
# [*return:*] _URI_ - Returns URI object for use in calling the \REopt results endpoint for a
|
57
|
+
# [*return:*] _URI_ - Returns URI object for use in calling the \REopt results endpoint for a specific optimization task.
|
59
58
|
##
|
60
59
|
def uri_results(run_uuid) # :nodoc:
|
61
60
|
if @use_localhost
|
62
|
-
return URI.parse("http://127.0.0.1:8000/
|
61
|
+
return URI.parse("http://127.0.0.1:8000/v3/job/#{run_uuid}/results")
|
63
62
|
end
|
64
63
|
|
65
|
-
return URI.parse("https://developer.nrel.gov/api/reopt/
|
64
|
+
return URI.parse("https://developer.nrel.gov/api/reopt/v3/job/#{run_uuid}/results?api_key=#{@nrel_developer_key}")
|
66
65
|
end
|
67
66
|
|
68
67
|
##
|
@@ -73,14 +72,14 @@ module URBANopt # :nodoc:
|
|
73
72
|
#
|
74
73
|
# * +run_uuid+ - _String_ - Resilience statistics for a unique run_uuid obtained from the \REopt job submittal URL for a specific optimization task.
|
75
74
|
#
|
76
|
-
# [*return:*] _URI_ - Returns URI object for use in calling the \REopt resilience statistics endpoint for a
|
75
|
+
# [*return:*] _URI_ - Returns URI object for use in calling the \REopt resilience statistics endpoint for a specific optimization task.
|
77
76
|
##
|
78
77
|
def uri_resilience(run_uuid) # :nodoc:
|
79
78
|
if @use_localhost
|
80
|
-
return URI.parse("http://127.0.0.1:8000/
|
79
|
+
return URI.parse("http://127.0.0.1:8000/v3/job/#{run_uuid}/resilience_stats")
|
81
80
|
end
|
82
81
|
|
83
|
-
return URI.parse("https://developer.nrel.gov/api/reopt/
|
82
|
+
return URI.parse("https://developer.nrel.gov/api/reopt/v3/job/#{run_uuid}/resilience_stats?api_key=#{@nrel_developer_key}")
|
84
83
|
end
|
85
84
|
|
86
85
|
def make_request(http, req, max_tries = 3)
|
@@ -112,11 +111,11 @@ module URBANopt # :nodoc:
|
|
112
111
|
end
|
113
112
|
tries = max_tries
|
114
113
|
rescue StandardError => e
|
115
|
-
@@logger.
|
114
|
+
@@logger.error("error from REopt API: #{e}")
|
116
115
|
if tries + 1 < max_tries
|
117
116
|
@@logger.debug('trying again...')
|
118
117
|
else
|
119
|
-
@@logger.
|
118
|
+
@@logger.warn('max tries reached!')
|
120
119
|
return result
|
121
120
|
end
|
122
121
|
tries += 1
|
@@ -133,7 +132,7 @@ module URBANopt # :nodoc:
|
|
133
132
|
#
|
134
133
|
# * +data+ - _Hash_ - Default \REopt formatted post containing at least all the required parameters.
|
135
134
|
#
|
136
|
-
# [*return:*] _Bool_ - Returns true if the post
|
135
|
+
# [*return:*] _Bool_ - Returns true if the post succeeds. Otherwise returns false.
|
137
136
|
##
|
138
137
|
def check_connection(data)
|
139
138
|
header = { 'Content-Type' => 'application/json' }
|
@@ -166,7 +165,7 @@ module URBANopt # :nodoc:
|
|
166
165
|
# * +reopt_input+ - _Hash_ - \REopt formatted post containing at least required parameters.
|
167
166
|
# * +filename+ - _String_ - Path to file that will be created containing the full \REopt response.
|
168
167
|
#
|
169
|
-
# [*return:*] _Bool_ - Returns true if the post
|
168
|
+
# [*return:*] _Bool_ - Returns true if the post succeeds. Otherwise returns false.
|
170
169
|
##
|
171
170
|
def resilience_request(run_uuid, filename)
|
172
171
|
if File.directory? filename
|
@@ -199,21 +198,21 @@ module URBANopt # :nodoc:
|
|
199
198
|
http.use_ssl = true
|
200
199
|
end
|
201
200
|
|
202
|
-
# Wait
|
203
|
-
sleep
|
201
|
+
# Wait for the REopt API before attempting to GET results
|
202
|
+
sleep 30
|
204
203
|
get_request = Net::HTTP::Get.new(uri.request_uri)
|
205
204
|
response = make_request(http, get_request, 8)
|
206
205
|
|
207
206
|
# Set a limit on retries when 404s are returned from REopt API
|
208
207
|
elapsed_time = 0
|
209
|
-
max_elapsed_time = 60 *
|
208
|
+
max_elapsed_time = 60 * 15
|
210
209
|
|
211
|
-
# If database still hasn't updated, wait
|
210
|
+
# If database still hasn't updated, wait longer and try again
|
212
211
|
while (elapsed_time < max_elapsed_time) && (response && response.code == '404')
|
213
212
|
response = make_request(http, get_request)
|
214
213
|
@@logger.warn('GET request was too fast for REOpt-API. Retrying...')
|
215
|
-
elapsed_time +=
|
216
|
-
sleep
|
214
|
+
elapsed_time += 15
|
215
|
+
sleep 15
|
217
216
|
end
|
218
217
|
|
219
218
|
data = JSON.parse(response.body, allow_nan: true)
|
@@ -246,10 +245,10 @@ module URBANopt # :nodoc:
|
|
246
245
|
# * +reopt_input+ - _Hash_ - \REopt formatted post containing at least required parameters.
|
247
246
|
# * +filename+ - _String_ - Path to file that will be created containing the full \REopt response.
|
248
247
|
#
|
249
|
-
# [*return:*] _Bool_ - Returns true if the post
|
248
|
+
# [*return:*] _Bool_ - Returns true if the post succeeds. Otherwise returns false.
|
250
249
|
##
|
251
250
|
def reopt_request(reopt_input, filename)
|
252
|
-
description = reopt_input[:
|
251
|
+
description = reopt_input[:description]
|
253
252
|
|
254
253
|
@@logger.info("Submitting #{description} to REopt API")
|
255
254
|
|
@@ -301,45 +300,84 @@ module URBANopt # :nodoc:
|
|
301
300
|
|
302
301
|
get_request = Net::HTTP::Get.new(uri.request_uri)
|
303
302
|
|
303
|
+
counter = 0
|
304
304
|
while status == 'Optimizing...'
|
305
305
|
response = make_request(http, get_request)
|
306
306
|
|
307
307
|
data = JSON.parse(response.body, allow_nan: true)
|
308
308
|
|
309
|
-
if data['outputs']['
|
309
|
+
if !data['outputs']['PV']
|
310
310
|
pv_sizes = 0
|
311
|
-
|
312
|
-
pv_sizes += x['size_kw'].to_f
|
313
|
-
end
|
311
|
+
sizes = 0
|
314
312
|
else
|
315
|
-
|
313
|
+
# there should be results in there now
|
314
|
+
if data['outputs']['PV'].is_a?(Array)
|
315
|
+
pv_sizes = 0
|
316
|
+
data['outputs']['PV'].each do |x|
|
317
|
+
pv_sizes += x['size_kw'].to_f
|
318
|
+
end
|
319
|
+
else
|
320
|
+
data['outputs'].each do |energy_source, data|
|
321
|
+
if data.is_a?(Hash) && data.key?('size_kw')
|
322
|
+
@@logger.debug("#{energy_source}: size_kw = #{data['size_kw'].to_f}")
|
323
|
+
sizes += data['size_kw'].to_f
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
status = data['status']
|
330
|
+
@@logger.debug("STATUS: #{status}")
|
331
|
+
|
332
|
+
if status == 'error'
|
333
|
+
puts "response.code: #{response.code}"
|
334
|
+
puts "message: #{response.message}"
|
335
|
+
error_message = data['messages']['errors']
|
336
|
+
raise "Error from REopt API - #{error_message}"
|
316
337
|
end
|
317
|
-
sizes = pv_sizes + (data['outputs']['Scenario']['Site']['Storage']['size_kw'] || 0) + (data['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) + (data['outputs']['Scenario']['Site']['Generator']['size_kw'] || 0)
|
318
|
-
status = data['outputs']['Scenario']['status']
|
319
338
|
|
320
|
-
sleep
|
339
|
+
sleep 15
|
321
340
|
end
|
322
341
|
|
323
342
|
max_retry = 5
|
324
343
|
tries = 0
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
344
|
+
|
345
|
+
check_complete = sizes == 0
|
346
|
+
# I don't know what this line does:
|
347
|
+
# (((data['outputs'] && data['outputs'].key?('Financial') && data['outputs']['Financial']['npv']) || 0) > 0)
|
348
|
+
|
349
|
+
if check_complete
|
350
|
+
@@logger.info('sizes are 0...checking optimization complete')
|
351
|
+
|
352
|
+
while (tries < max_retry) && check_complete
|
353
|
+
sleep 3
|
354
|
+
response = make_request(http, get_request)
|
355
|
+
data = JSON.parse(response.body, allow_nan: true)
|
356
|
+
|
357
|
+
if data['outputs'].key?('PV') && data['outputs']['PV'].is_a?(Array)
|
358
|
+
pv_sizes = 0
|
359
|
+
data['outputs']['PV'].each do |x|
|
360
|
+
pv_sizes += x['size_kw'].to_f
|
361
|
+
end
|
362
|
+
else
|
363
|
+
data['outputs'].each do |energy_source, data|
|
364
|
+
if data.is_a?(Hash) && data.key?('size_kw')
|
365
|
+
@@logger.debug("#{energy_source}: size_kw = #{data['size_kw'].to_f}")
|
366
|
+
sizes += data['size_kw'].to_f
|
367
|
+
end
|
368
|
+
end
|
334
369
|
end
|
335
|
-
|
336
|
-
|
370
|
+
|
371
|
+
# I don't understand this line fully:
|
372
|
+
#(check_complete = sizes == 0) && ((data['outputs']['Financial']['npv'] || 0) > 0)
|
373
|
+
|
374
|
+
check_complete = sizes == 0
|
375
|
+
tries += 1
|
337
376
|
end
|
338
|
-
sizes = pv_sizes + (data['outputs']['Scenario']['Site']['Storage']['size_kw'] || 0) + (data['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) + (data['outputs']['Scenario']['Site']['Generator']['size_kw'] || 0)
|
339
|
-
(check_complete = sizes == 0) && ((data['outputs']['Scenario']['Site']['Financial']['npv_us_dollars'] || 0) > 0)
|
340
|
-
tries += 1
|
341
377
|
end
|
342
378
|
|
379
|
+
@@logger.info('REopt optimization complete and processed')
|
380
|
+
|
343
381
|
data = JSON.parse(response.body, allow_nan: true)
|
344
382
|
text = JSON.pretty_generate(data)
|
345
383
|
begin
|
@@ -12,7 +12,7 @@ module URBANopt
|
|
12
12
|
# Set Logger::DEBUG for development
|
13
13
|
@@reopt_logger.level = Logger::WARN
|
14
14
|
##
|
15
|
-
#
|
15
|
+
# Defining class variable "@@logger" to log errors, info and warning messages.
|
16
16
|
def self.reopt_logger
|
17
17
|
@@reopt_logger
|
18
18
|
end
|
@@ -7,6 +7,7 @@ require 'bundler/setup'
|
|
7
7
|
require 'urbanopt/reporting/default_reports'
|
8
8
|
require 'urbanopt/reopt/reopt_logger'
|
9
9
|
require 'csv'
|
10
|
+
require 'json'
|
10
11
|
|
11
12
|
module URBANopt # :nodoc:
|
12
13
|
module REopt # :nodoc:
|
@@ -32,7 +33,6 @@ module URBANopt # :nodoc:
|
|
32
33
|
end
|
33
34
|
@nrel_developer_key = nrel_developer_key
|
34
35
|
@localhost = localhost
|
35
|
-
@reopt_base_post = { Scenario: { Site: { ElectricTariff: {}, LoadProfile: {}, Wind: { max_kw: 0 } } } }
|
36
36
|
|
37
37
|
@scenario_reopt_default_output_file = nil
|
38
38
|
@scenario_timeseries_default_output_file = nil
|
@@ -92,7 +92,7 @@ module URBANopt # :nodoc:
|
|
92
92
|
#
|
93
93
|
# [*return:*] _URBANopt::Reporting::DefaultReports::FeatureReport_ - Returns an updated FeatureReport
|
94
94
|
##
|
95
|
-
def run_feature_report(feature_report:, reopt_assumptions_hash: nil, reopt_output_file: nil, timeseries_csv_path: nil, save_name: nil, run_resilience:
|
95
|
+
def run_feature_report(feature_report:, reopt_assumptions_hash: nil, reopt_output_file: nil, timeseries_csv_path: nil, save_name: nil, run_resilience: false)
|
96
96
|
api = URBANopt::REopt::REoptLiteAPI.new(@nrel_developer_key, @localhost)
|
97
97
|
adapter = URBANopt::REopt::FeatureReportAdapter.new
|
98
98
|
|
@@ -103,7 +103,7 @@ module URBANopt # :nodoc:
|
|
103
103
|
reopt_output = api.reopt_request(reopt_input, reopt_output_file)
|
104
104
|
@@logger.debug("REOpt output file: #{reopt_output_file}")
|
105
105
|
if run_resilience
|
106
|
-
run_uuid = reopt_output['outputs']['
|
106
|
+
run_uuid = reopt_output['outputs']['run_uuid']
|
107
107
|
if File.directory? reopt_output_file
|
108
108
|
resilience_stats = api.resilience_request(run_uuid, reopt_output_file)
|
109
109
|
else
|
@@ -112,6 +112,7 @@ module URBANopt # :nodoc:
|
|
112
112
|
else
|
113
113
|
resilience_stats = nil
|
114
114
|
end
|
115
|
+
|
115
116
|
result = adapter.update_feature_report(feature_report, reopt_output, timeseries_csv_path, resilience_stats)
|
116
117
|
if !save_name.nil?
|
117
118
|
result.save save_name
|
@@ -131,8 +132,7 @@ module URBANopt # :nodoc:
|
|
131
132
|
# * +timeseries_csv_path+ - _String_ - Optional. Path to a file at which the new timeseries CSV for the ScenarioReport will be saved.
|
132
133
|
#
|
133
134
|
# [*return:*] _URBANopt::Scenario::DefaultReports::ScenarioReport_ Returns an updated ScenarioReport
|
134
|
-
def run_scenario_report(scenario_report:, reopt_assumptions_hash: nil, reopt_output_file: nil, timeseries_csv_path: nil, save_name: nil, run_resilience:
|
135
|
-
puts 'run scenario report'
|
135
|
+
def run_scenario_report(scenario_report:, reopt_assumptions_hash: nil, reopt_output_file: nil, timeseries_csv_path: nil, save_name: nil, run_resilience: false, community_photovoltaic: nil)
|
136
136
|
@save_assumptions_filepath = false
|
137
137
|
if !reopt_assumptions_hash.nil?
|
138
138
|
@scenario_reopt_default_assumptions_hash = reopt_assumptions_hash
|
@@ -150,10 +150,10 @@ module URBANopt # :nodoc:
|
|
150
150
|
adapter = URBANopt::REopt::ScenarioReportAdapter.new
|
151
151
|
|
152
152
|
reopt_input = adapter.reopt_json_from_scenario_report(scenario_report, @scenario_reopt_default_assumptions_hash, community_photovoltaic)
|
153
|
-
|
154
153
|
reopt_output = api.reopt_request(reopt_input, @scenario_reopt_default_output_file)
|
154
|
+
|
155
155
|
if run_resilience
|
156
|
-
run_uuid = reopt_output['outputs']['
|
156
|
+
run_uuid = reopt_output['outputs']['run_uuid']
|
157
157
|
if File.directory? @scenario_reopt_default_output_file
|
158
158
|
resilience_stats = api.resilience_request(run_uuid, @scenario_reopt_default_output_file)
|
159
159
|
else
|
@@ -181,13 +181,13 @@ module URBANopt # :nodoc:
|
|
181
181
|
#
|
182
182
|
# [*parameters:*]
|
183
183
|
#
|
184
|
-
# * +feature_reports+ - _Array_ - An array of _URBANopt::Reporting::DefaultReports::FeatureReport_
|
184
|
+
# * +feature_reports+ - _Array_ - An array of _URBANopt::Reporting::DefaultReports::FeatureReport_ objects which will each be used to create (and are subsequently updated by) a \REopt opimization response.
|
185
185
|
# * +reopt_assumptions_hashes+ - _Array_ - Optional. An array of \REopt formatted hashes containing default parameters (i.e. utility rate, escalation rate) which will be updated by the ScenarioReport (i.e. location, roof availability). The number and order of the hashes should match the feature_reports array.
|
186
186
|
# * +reopt_output_files+ - _Array_ - Optional. A array of paths to files at which REpopt responses will be saved. The number and order of the paths should match the feature_reports array.
|
187
187
|
# * +timeseries_csv_path+ - _Array_ - Optional. A array of paths to files at which the new timeseries CSV for the FeatureReports will be saved. The number and order of the paths should match the feature_reports array.
|
188
188
|
#
|
189
189
|
# [*return:*] _Array_ Returns an array of updated _URBANopt::Scenario::DefaultReports::FeatureReport_ objects
|
190
|
-
def run_feature_reports(feature_reports:, reopt_assumptions_hashes: [], reopt_output_files: [], timeseries_csv_paths: [], save_names: nil, run_resilience:
|
190
|
+
def run_feature_reports(feature_reports:, reopt_assumptions_hashes: [], reopt_output_files: [], timeseries_csv_paths: [], save_names: nil, run_resilience: false, keep_existing_output: false, groundmount_photovoltaic: nil)
|
191
191
|
if !reopt_assumptions_hashes.empty?
|
192
192
|
@feature_reports_reopt_default_assumption_hashes = reopt_assumptions_hashes
|
193
193
|
end
|
@@ -222,7 +222,7 @@ module URBANopt # :nodoc:
|
|
222
222
|
reopt_input = feature_adapter.reopt_json_from_feature_report(feature_report, @feature_reports_reopt_default_assumption_hashes[idx], groundmount_photovoltaic)
|
223
223
|
reopt_output = api.reopt_request(reopt_input, @feature_reports_reopt_default_output_files[idx])
|
224
224
|
if run_resilience
|
225
|
-
run_uuid = reopt_output['outputs']['
|
225
|
+
run_uuid = reopt_output['outputs']['run_uuid']
|
226
226
|
if File.directory? @feature_reports_reopt_default_output_files[idx]
|
227
227
|
resilience_stats = api.resilience_request(run_uuid, @feature_reports_reopt_default_output_files[idx])
|
228
228
|
else
|
@@ -275,13 +275,13 @@ module URBANopt # :nodoc:
|
|
275
275
|
#
|
276
276
|
# [*parameters:*]
|
277
277
|
#
|
278
|
-
# * +scenario_report+ - _Array_ - A _URBANopt::Reporting::DefaultReports::ScenarioReport_ which will each be used to create (and is
|
278
|
+
# * +scenario_report+ - _Array_ - A _URBANopt::Reporting::DefaultReports::ScenarioReport_ which will each be used to create (and is subsequently updated by) \REopt opimization responses for each of its FeatureReports.
|
279
279
|
# * +reopt_assumptions_hashes+ - _Array_ - Optional. An array of \REopt formatted hashes containing default parameters (i.e. utility rate, escalation rate) which will be updated by the ScenarioReport (i.e. location, roof availability). The number and order of the hashes should match the array in ScenarioReport.feature_reports.
|
280
280
|
# * +reopt_output_files+ - _Array_ - Optional. An array of paths to files at which REpopt responses will be saved. The number and order of the paths should match the array in ScenarioReport.feature_reports.
|
281
281
|
# * +feature_report_timeseries_csv_paths+ - _Array_ - Optional. An array of paths to files at which the new timeseries CSV for the FeatureReports will be saved. The number and order of the paths should match the array in ScenarioReport.feature_reports.
|
282
282
|
#
|
283
283
|
# [*return:*] _URBANopt::Scenario::DefaultReports::ScenarioReport_ - Returns an updated ScenarioReport
|
284
|
-
def run_scenario_report_features(scenario_report:, reopt_assumptions_hashes: [], reopt_output_files: [], feature_report_timeseries_csv_paths: [], save_names_feature_reports: nil, save_name_scenario_report: nil, run_resilience:
|
284
|
+
def run_scenario_report_features(scenario_report:, reopt_assumptions_hashes: [], reopt_output_files: [], feature_report_timeseries_csv_paths: [], save_names_feature_reports: nil, save_name_scenario_report: nil, run_resilience: false, keep_existing_output: false, groundmount_photovoltaic: nil)
|
285
285
|
new_feature_reports = run_feature_reports(feature_reports: scenario_report.feature_reports, reopt_assumptions_hashes: reopt_assumptions_hashes, reopt_output_files: reopt_output_files, timeseries_csv_paths: feature_report_timeseries_csv_paths, save_names: save_names_feature_reports, run_resilience: run_resilience, keep_existing_output: keep_existing_output, groundmount_photovoltaic: groundmount_photovoltaic)
|
286
286
|
|
287
287
|
# only do this if you have run feature reports
|
@@ -0,0 +1,148 @@
|
|
1
|
+
{
|
2
|
+
"Site": {
|
3
|
+
"latitude": {
|
4
|
+
"type": "float",
|
5
|
+
"required": true
|
6
|
+
},
|
7
|
+
"longitude": {
|
8
|
+
"type": "float",
|
9
|
+
"required": true
|
10
|
+
}
|
11
|
+
},
|
12
|
+
"SpaceHeatingLoad": {
|
13
|
+
"fuel_loads_mmbtu_per_hour": {
|
14
|
+
"type": "array",
|
15
|
+
"required": true,
|
16
|
+
"description": "8760 timeseries",
|
17
|
+
"note": "This parameter is required to run REopt's GHP module but is not used to calculate URBANopt's GHP system LCCA. Users can set this to small numbers in GHP scenario"
|
18
|
+
}
|
19
|
+
},
|
20
|
+
"DomesticHotWaterLoad": {
|
21
|
+
"fuel_loads_mmbtu_per_hour": {
|
22
|
+
"type": "array",
|
23
|
+
"required": true,
|
24
|
+
"description": "8760 timeseries, if GHP not providing DHW set to zeros"
|
25
|
+
}
|
26
|
+
},
|
27
|
+
"ElectricLoad": {
|
28
|
+
"load_kw": {
|
29
|
+
"type": "array",
|
30
|
+
"required": true,
|
31
|
+
"description": "8760 timeseries",
|
32
|
+
"note": "15 min interval data do not work in GHP module. Please make sure all timeseries are 8760"
|
33
|
+
}
|
34
|
+
},
|
35
|
+
"ElectricTarriff": {
|
36
|
+
"urdb_label": "string",
|
37
|
+
"required": true
|
38
|
+
},
|
39
|
+
"GHP": {
|
40
|
+
"require_ghp_purchase": {
|
41
|
+
"type": "boolean",
|
42
|
+
"required": true,
|
43
|
+
"description": "choices of 0 or 1. Always set at 1 for URBANopt's LCCA"
|
44
|
+
},
|
45
|
+
"building_sqft": {
|
46
|
+
"type": "float",
|
47
|
+
"required": true,
|
48
|
+
"description": "to calculate cost of hydronic loop",
|
49
|
+
"note": "for the GHX iteration, set building_sqft to a number close to 0 but not exactly 0"
|
50
|
+
},
|
51
|
+
"heatpump_capacity_sizing_factor_on_peak_load": {
|
52
|
+
"type": "float",
|
53
|
+
"required": true,
|
54
|
+
"description": "always set to 1"
|
55
|
+
},
|
56
|
+
"ghpghx_responses":{
|
57
|
+
"outputs": {
|
58
|
+
"heat_pump_configuration": {
|
59
|
+
"type": "string",
|
60
|
+
"required": true,
|
61
|
+
"description": "set as WSHP"
|
62
|
+
},
|
63
|
+
"peak_combined_heatpump_thermal_ton": {
|
64
|
+
"type": "float",
|
65
|
+
"required": true,
|
66
|
+
"description": "size of GHP in ton",
|
67
|
+
"note": "in the GHX iteration, set this value to a number close to 0 but NOT exactly 0S"
|
68
|
+
},
|
69
|
+
"number_of_boreholes": {
|
70
|
+
"type": "int",
|
71
|
+
"required": true,
|
72
|
+
"note": "in the GHP iteration, set this value to 0"
|
73
|
+
},
|
74
|
+
"length_boreholes_ft": {
|
75
|
+
"type": "float",
|
76
|
+
"required": true,
|
77
|
+
"note": "in the GHP iteration, set this value to 0"
|
78
|
+
},
|
79
|
+
"yearly_total_electric_consumption_series_kw": {
|
80
|
+
"type": "array",
|
81
|
+
"required": true,
|
82
|
+
"description": "8760 timeseries of building total electric consumption",
|
83
|
+
"note": "in the GHX iteration, set this value to a number close to 0 but not exactly 0"
|
84
|
+
},
|
85
|
+
"yearly_ghx_pump_electric_consumption_series_kw": {
|
86
|
+
"type": "array",
|
87
|
+
"required": true,
|
88
|
+
"description": "8760 timeseries of ghx's total electric consumption",
|
89
|
+
"note": "in the GHP iteration, set this value to 0"
|
90
|
+
}
|
91
|
+
},
|
92
|
+
"inputs": {
|
93
|
+
"heating_thermal_load_mmbtu_per_hr": {
|
94
|
+
"type": "array",
|
95
|
+
"required": true,
|
96
|
+
"description": "not used for URBANopt's GHP LCCA but required for formatting, set to number close to 0"
|
97
|
+
},
|
98
|
+
"cooling_thermal_load_ton": {
|
99
|
+
"type": "array",
|
100
|
+
"required": true,
|
101
|
+
"description": "not used for URBANopt's GHP LCCA but required for formatting, can set as zeros"
|
102
|
+
}
|
103
|
+
}
|
104
|
+
},
|
105
|
+
"installed_cost_heatpump_per_ton": {
|
106
|
+
"type": "float",
|
107
|
+
"required": false,
|
108
|
+
"description": "installation cost per unit (ton) of GHP"
|
109
|
+
},
|
110
|
+
"installed_cost_ghx_per_ft": {
|
111
|
+
"type": "float",
|
112
|
+
"required": false,
|
113
|
+
"description": "installation cost per unit (ft) of GHX"
|
114
|
+
},
|
115
|
+
"installed_cost_building_hydronic_loop_per_sqft": {
|
116
|
+
"type": "float",
|
117
|
+
"required": false,
|
118
|
+
"description": "installation cost per sqft of building hydronic loop"
|
119
|
+
},
|
120
|
+
"om_cost_per_sqft_year": {
|
121
|
+
"type": "float",
|
122
|
+
"required": false,
|
123
|
+
"description": "if not specified, the value is -$0.51, capturing saving from HVAC operation. Recommended setting at 0"
|
124
|
+
},
|
125
|
+
"macrs_bonus_fraction": {
|
126
|
+
"type": "float",
|
127
|
+
"required": false,
|
128
|
+
"description": "Percentage of macrs benefits for GHP. Value between 0 and 1"
|
129
|
+
},
|
130
|
+
"macrs_itc_reduction": {
|
131
|
+
"type": "float",
|
132
|
+
"required": false,
|
133
|
+
"description": "Percentage of macrs benefits for GHP. Value between 0 and 1"
|
134
|
+
},
|
135
|
+
"federal_itc_fraction": {
|
136
|
+
"type": "float",
|
137
|
+
"required": false,
|
138
|
+
"description": "Percentage of ITC benefits for GHP. Value between 0 and 1"
|
139
|
+
}
|
140
|
+
},
|
141
|
+
"ExistingBoiler": {
|
142
|
+
"fuel_cost_per_mmbtu": {
|
143
|
+
"type": "float",
|
144
|
+
"required": true,
|
145
|
+
"description": "to calculate BAU cost, and required for formatting in GHP scenario"
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|