urbanopt-reopt 0.5.4 → 0.6.1
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/.rubocop.yml +2 -2
- data/CHANGELOG.md +30 -0
- data/Gemfile +1 -1
- data/LICENSE.md +33 -21
- data/Rakefile +18 -8
- data/docs/package-lock.json +13843 -1118
- data/docs/package.json +10 -6
- data/lib/urbanopt-reopt.rb +16 -6
- data/lib/urbanopt/reopt.rb +16 -6
- data/lib/urbanopt/reopt/extension.rb +16 -6
- data/lib/urbanopt/reopt/feature_report_adapter.rb +82 -103
- data/lib/urbanopt/reopt/reopt_lite_api.rb +81 -57
- data/lib/urbanopt/reopt/reopt_logger.rb +17 -7
- data/lib/urbanopt/reopt/reopt_post_processor.rb +89 -56
- data/lib/urbanopt/reopt/scenario/reopt_scenario_csv.rb +23 -13
- data/lib/urbanopt/reopt/scenario_report_adapter.rb +88 -110
- data/lib/urbanopt/reopt/utilities.rb +106 -102
- data/lib/urbanopt/reopt/version.rb +17 -7
- data/lib/urbanopt/reopt_scenario.rb +16 -6
- data/urbanopt-reopt.gemspec +4 -7
- metadata +15 -29
@@ -1,21 +1,31 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt
|
2
|
+
# URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
|
-
|
4
|
+
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
6
6
|
# are permitted provided that the following conditions are met:
|
7
|
-
|
7
|
+
|
8
8
|
# Redistributions of source code must retain the above copyright notice, this list
|
9
9
|
# of conditions and the following disclaimer.
|
10
|
-
|
10
|
+
|
11
11
|
# Redistributions in binary form must reproduce the above copyright notice, this
|
12
12
|
# list of conditions and the following disclaimer in the documentation and/or other
|
13
13
|
# materials provided with the distribution.
|
14
|
-
|
14
|
+
|
15
15
|
# Neither the name of the copyright holder nor the names of its contributors may be
|
16
16
|
# used to endorse or promote products derived from this software without specific
|
17
17
|
# prior written permission.
|
18
|
-
|
18
|
+
|
19
|
+
# Redistribution of this software, without modification, must refer to the software
|
20
|
+
# by the same designation. Redistribution of a modified version of this software
|
21
|
+
# (i) may not refer to the modified version by the same designation, or by any
|
22
|
+
# confusingly similar designation, and (ii) must refer to the underlying software
|
23
|
+
# originally provided by Alliance as “URBANopt”. Except to comply with the foregoing,
|
24
|
+
# the term “URBANopt”, or any confusingly similar designation may not be used to
|
25
|
+
# refer to any modified version of this software or any modified version of the
|
26
|
+
# underlying software originally provided by Alliance without the prior written
|
27
|
+
# consent of Alliance.
|
28
|
+
|
19
29
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
20
30
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
21
31
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
@@ -87,6 +97,7 @@ module URBANopt # :nodoc:
|
|
87
97
|
if @use_localhost
|
88
98
|
return URI.parse("http://127.0.0.1:8000/v1/job/#{run_uuid}/results")
|
89
99
|
end
|
100
|
+
|
90
101
|
return URI.parse("https://developer.nrel.gov/api/reopt/v1/job/#{run_uuid}/results?api_key=#{@nrel_developer_key}")
|
91
102
|
end
|
92
103
|
|
@@ -104,6 +115,7 @@ module URBANopt # :nodoc:
|
|
104
115
|
if @use_localhost
|
105
116
|
return URI.parse("http://127.0.0.1:8000/v1/job/#{run_uuid}/resilience_stats")
|
106
117
|
end
|
118
|
+
|
107
119
|
return URI.parse("https://developer.nrel.gov/api/reopt/v1/job/#{run_uuid}/resilience_stats?api_key=#{@nrel_developer_key}")
|
108
120
|
end
|
109
121
|
|
@@ -112,11 +124,20 @@ module URBANopt # :nodoc:
|
|
112
124
|
tries = 0
|
113
125
|
while tries < max_tries
|
114
126
|
begin
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
127
|
+
result = http.request(r)
|
128
|
+
# Result codes sourced from https://developer.nrel.gov/docs/errors/
|
129
|
+
if result.code == '429'
|
130
|
+
@@logger.fatal('Exceeded the REopt-Lite API limit of 300 requests per hour')
|
131
|
+
puts 'Using the URBANopt CLI to submit a Scenario optimization counts as one request per scenario'
|
132
|
+
puts 'Using the URBANopt CLI to submit a Feature optimization counts as one request per feature'
|
133
|
+
abort('Please wait and try again once the time period has elapsed')
|
134
|
+
elsif (result.code != '201') && (result.code != '200') # Anything in the 200s is success
|
135
|
+
@@logger.debug("REopt-Lite has returned a '#{result.code}' status code. Visit https://developer.nrel.gov/docs/errors/ for more status code information")
|
136
|
+
end
|
137
|
+
tries = 4
|
138
|
+
rescue StandardError
|
139
|
+
tries += 1
|
140
|
+
end
|
120
141
|
end
|
121
142
|
return result
|
122
143
|
end
|
@@ -138,11 +159,11 @@ module URBANopt # :nodoc:
|
|
138
159
|
http.use_ssl = true
|
139
160
|
end
|
140
161
|
|
141
|
-
|
142
|
-
|
162
|
+
post_request = Net::HTTP::Post.new(@uri_submit, header)
|
163
|
+
post_request.body = ::JSON.generate(data, allow_nan: true)
|
143
164
|
|
144
165
|
# Send the request
|
145
|
-
response = make_request(http,
|
166
|
+
response = make_request(http, post_request)
|
146
167
|
|
147
168
|
if !response.is_a?(Net::HTTPSuccess)
|
148
169
|
@@logger.error('Check_connection Failed')
|
@@ -165,7 +186,6 @@ module URBANopt # :nodoc:
|
|
165
186
|
# [*return:*] _Bool_ - Returns true if the post succeeeds. Otherwise returns false.
|
166
187
|
##
|
167
188
|
def resilience_request(run_uuid, filename)
|
168
|
-
|
169
189
|
if File.directory? filename
|
170
190
|
if run_uuid.nil?
|
171
191
|
run_uuid = 'error'
|
@@ -176,55 +196,59 @@ module URBANopt # :nodoc:
|
|
176
196
|
filename = File.join(filename, "#{run_uuid}_resilience.json")
|
177
197
|
@@logger.info("REopt results saved to #{filename}")
|
178
198
|
end
|
179
|
-
|
180
|
-
#Submit Job
|
199
|
+
|
200
|
+
# Submit Job
|
181
201
|
@@logger.info("Submitting Resilience Statistics job for #{run_uuid}")
|
182
202
|
header = { 'Content-Type' => 'application/json' }
|
183
203
|
http = Net::HTTP.new(@uri_submit_outagesimjob.host, @uri_submit_outagesimjob.port)
|
184
204
|
if !@use_localhost
|
185
205
|
http.use_ssl = true
|
186
206
|
end
|
187
|
-
|
188
|
-
|
189
|
-
submit_response = make_request(http,
|
190
|
-
@@logger.
|
207
|
+
post_request = Net::HTTP::Post.new(@uri_submit_outagesimjob, header)
|
208
|
+
post_request.body = ::JSON.generate({ 'run_uuid' => run_uuid, 'bau' => false }, allow_nan: true)
|
209
|
+
submit_response = make_request(http, post_request)
|
210
|
+
@@logger.debug(submit_response.body)
|
191
211
|
|
192
|
-
#Fetch Results
|
212
|
+
# Fetch Results
|
193
213
|
uri = uri_resilience(run_uuid)
|
194
214
|
http = Net::HTTP.new(uri.host, uri.port)
|
195
215
|
if !@use_localhost
|
196
216
|
http.use_ssl = true
|
197
217
|
end
|
198
218
|
|
219
|
+
# Wait a few seconds for the REopt database to update before GETing results
|
220
|
+
sleep 5
|
221
|
+
get_request = Net::HTTP::Get.new(uri.request_uri)
|
222
|
+
response = make_request(http, get_request)
|
223
|
+
|
224
|
+
# Set a limit on retries when 404s are returned from REopt API
|
199
225
|
elapsed_time = 0
|
200
226
|
max_elapsed_time = 60 * 5
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
elapsed_time += 5
|
227
|
+
|
228
|
+
# If database still hasn't updated, wait a little longer and try again
|
229
|
+
while (elapsed_time < max_elapsed_time) & (response.code == '404')
|
230
|
+
response = make_request(http, get_request)
|
231
|
+
@@logger.warn('GET request was too fast for REOpt-Lite API. Retrying...')
|
232
|
+
elapsed_time += 5
|
208
233
|
sleep 5
|
209
234
|
end
|
210
|
-
|
235
|
+
|
211
236
|
data = JSON.parse(response.body)
|
212
237
|
text = ::JSON.generate(data, allow_nan: true)
|
213
238
|
begin
|
214
239
|
File.open(filename, 'w+') do |f|
|
215
240
|
f.puts(text)
|
216
241
|
end
|
217
|
-
rescue
|
218
|
-
@@logger.
|
242
|
+
rescue StandardError
|
243
|
+
@@logger.error("Cannot write - #{filename}")
|
219
244
|
end
|
220
245
|
|
221
|
-
if response.code ==
|
246
|
+
if response.code == '200'
|
222
247
|
return data
|
223
248
|
end
|
224
|
-
|
225
|
-
@@logger.
|
249
|
+
|
250
|
+
@@logger.error("Error from REopt API - #{data['Error']}")
|
226
251
|
return {}
|
227
|
-
|
228
252
|
end
|
229
253
|
|
230
254
|
##
|
@@ -251,14 +275,14 @@ module URBANopt # :nodoc:
|
|
251
275
|
if !@use_localhost
|
252
276
|
http.use_ssl = true
|
253
277
|
end
|
254
|
-
|
255
|
-
|
256
|
-
|
278
|
+
post_request = Net::HTTP::Post.new(@uri_submit, header)
|
279
|
+
post_request.body = ::JSON.generate(reopt_input, allow_nan: true)
|
280
|
+
|
257
281
|
# Send the request
|
258
|
-
response = make_request(http,
|
282
|
+
response = make_request(http, post_request)
|
259
283
|
|
260
284
|
# Get UUID
|
261
|
-
run_uuid = JSON.parse(response.body, allow_nan:true)['run_uuid']
|
285
|
+
run_uuid = JSON.parse(response.body, allow_nan: true)['run_uuid']
|
262
286
|
|
263
287
|
if File.directory? filename
|
264
288
|
if run_uuid.nil?
|
@@ -276,7 +300,7 @@ module URBANopt # :nodoc:
|
|
276
300
|
File.open(filename, 'w+') do |f|
|
277
301
|
f.puts(text)
|
278
302
|
end
|
279
|
-
@@logger.
|
303
|
+
@@logger.error("Cannot write - #{filename}")
|
280
304
|
raise "Error in REopt optimization post - see #{filename}"
|
281
305
|
end
|
282
306
|
|
@@ -288,18 +312,18 @@ module URBANopt # :nodoc:
|
|
288
312
|
http.use_ssl = true
|
289
313
|
end
|
290
314
|
|
291
|
-
|
315
|
+
get_request = Net::HTTP::Get.new(uri.request_uri)
|
292
316
|
|
293
317
|
while status == 'Optimizing...'
|
294
|
-
response = make_request(http,
|
295
|
-
|
296
|
-
data = JSON.parse(response.body, allow_nan:true)
|
318
|
+
response = make_request(http, get_request)
|
319
|
+
|
320
|
+
data = JSON.parse(response.body, allow_nan: true)
|
297
321
|
|
298
|
-
if data['outputs']['Scenario']['Site']['PV'].
|
322
|
+
if data['outputs']['Scenario']['Site']['PV'].is_a?(Array)
|
299
323
|
pv_sizes = 0
|
300
324
|
data['outputs']['Scenario']['Site']['PV'].each do |x|
|
301
|
-
pv_sizes
|
302
|
-
end
|
325
|
+
pv_sizes += x['size_kw'].to_f
|
326
|
+
end
|
303
327
|
else
|
304
328
|
pv_sizes = data['outputs']['Scenario']['Site']['PV']['size_kw'] || 0
|
305
329
|
end
|
@@ -313,14 +337,14 @@ module URBANopt # :nodoc:
|
|
313
337
|
_tries = 0
|
314
338
|
(check_complete = sizes == 0) && ((data['outputs']['Scenario']['Site']['Financial']['npv_us_dollars'] || 0) > 0)
|
315
339
|
while (_tries < _max_retry) && check_complete
|
316
|
-
sleep
|
317
|
-
response = make_request(http,
|
318
|
-
data = JSON.parse(response.body, allow_nan:true)
|
319
|
-
if data['outputs']['Scenario']['Site']['PV'].
|
340
|
+
sleep 3
|
341
|
+
response = make_request(http, get_request)
|
342
|
+
data = JSON.parse(response.body, allow_nan: true)
|
343
|
+
if data['outputs']['Scenario']['Site']['PV'].is_a?(Array)
|
320
344
|
pv_sizes = 0
|
321
345
|
data['outputs']['Scenario']['Site']['PV'].each do |x|
|
322
|
-
pv_sizes
|
323
|
-
end
|
346
|
+
pv_sizes += x['size_kw'].to_f
|
347
|
+
end
|
324
348
|
else
|
325
349
|
pv_sizes = data['outputs']['Scenario']['Site']['PV']['size_kw'] || 0
|
326
350
|
end
|
@@ -335,8 +359,8 @@ module URBANopt # :nodoc:
|
|
335
359
|
File.open(filename, 'w+') do |f|
|
336
360
|
f.puts(text)
|
337
361
|
end
|
338
|
-
rescue
|
339
|
-
@@logger.
|
362
|
+
rescue StandardError
|
363
|
+
@@logger.error("Cannot write - #{filename}")
|
340
364
|
end
|
341
365
|
|
342
366
|
if status == 'optimal'
|
@@ -1,21 +1,31 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt
|
2
|
+
# URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
|
-
|
4
|
+
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
6
6
|
# are permitted provided that the following conditions are met:
|
7
|
-
|
7
|
+
|
8
8
|
# Redistributions of source code must retain the above copyright notice, this list
|
9
9
|
# of conditions and the following disclaimer.
|
10
|
-
|
10
|
+
|
11
11
|
# Redistributions in binary form must reproduce the above copyright notice, this
|
12
12
|
# list of conditions and the following disclaimer in the documentation and/or other
|
13
13
|
# materials provided with the distribution.
|
14
|
-
|
14
|
+
|
15
15
|
# Neither the name of the copyright holder nor the names of its contributors may be
|
16
16
|
# used to endorse or promote products derived from this software without specific
|
17
17
|
# prior written permission.
|
18
|
-
|
18
|
+
|
19
|
+
# Redistribution of this software, without modification, must refer to the software
|
20
|
+
# by the same designation. Redistribution of a modified version of this software
|
21
|
+
# (i) may not refer to the modified version by the same designation, or by any
|
22
|
+
# confusingly similar designation, and (ii) must refer to the underlying software
|
23
|
+
# originally provided by Alliance as “URBANopt”. Except to comply with the foregoing,
|
24
|
+
# the term “URBANopt”, or any confusingly similar designation may not be used to
|
25
|
+
# refer to any modified version of this software or any modified version of the
|
26
|
+
# underlying software originally provided by Alliance without the prior written
|
27
|
+
# consent of Alliance.
|
28
|
+
|
19
29
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
20
30
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
21
31
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
@@ -32,7 +42,7 @@ require 'logger'
|
|
32
42
|
|
33
43
|
module URBANopt
|
34
44
|
module REopt
|
35
|
-
@@reopt_logger = Logger.new(
|
45
|
+
@@reopt_logger = Logger.new($stdout)
|
36
46
|
##
|
37
47
|
# Definining class variable "@@logger" to log errors, info and warning messages.
|
38
48
|
def self.reopt_logger
|
@@ -1,21 +1,31 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt
|
2
|
+
# URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
|
-
|
4
|
+
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
6
6
|
# are permitted provided that the following conditions are met:
|
7
|
-
|
7
|
+
|
8
8
|
# Redistributions of source code must retain the above copyright notice, this list
|
9
9
|
# of conditions and the following disclaimer.
|
10
|
-
|
10
|
+
|
11
11
|
# Redistributions in binary form must reproduce the above copyright notice, this
|
12
12
|
# list of conditions and the following disclaimer in the documentation and/or other
|
13
13
|
# materials provided with the distribution.
|
14
|
-
|
14
|
+
|
15
15
|
# Neither the name of the copyright holder nor the names of its contributors may be
|
16
16
|
# used to endorse or promote products derived from this software without specific
|
17
17
|
# prior written permission.
|
18
|
-
|
18
|
+
|
19
|
+
# Redistribution of this software, without modification, must refer to the software
|
20
|
+
# by the same designation. Redistribution of a modified version of this software
|
21
|
+
# (i) may not refer to the modified version by the same designation, or by any
|
22
|
+
# confusingly similar designation, and (ii) must refer to the underlying software
|
23
|
+
# originally provided by Alliance as “URBANopt”. Except to comply with the foregoing,
|
24
|
+
# the term “URBANopt”, or any confusingly similar designation may not be used to
|
25
|
+
# refer to any modified version of this software or any modified version of the
|
26
|
+
# underlying software originally provided by Alliance without the prior written
|
27
|
+
# consent of Alliance.
|
28
|
+
|
19
29
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
20
30
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
21
31
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
@@ -69,18 +79,18 @@ module URBANopt # :nodoc:
|
|
69
79
|
if !scenario_report.nil?
|
70
80
|
@scenario_report = scenario_report
|
71
81
|
|
72
|
-
if !Dir.exist?(File.join(@scenario_report.directory_name,
|
73
|
-
Dir.mkdir(File.join(@scenario_report.directory_name,
|
74
|
-
@@logger.info("Created directory:
|
82
|
+
if !Dir.exist?(File.join(@scenario_report.directory_name, 'reopt'))
|
83
|
+
Dir.mkdir(File.join(@scenario_report.directory_name, 'reopt'))
|
84
|
+
@@logger.info("Created directory: #{File.join(@scenario_report.directory_name, 'reopt')}")
|
75
85
|
end
|
76
86
|
|
77
87
|
@scenario_reopt_default_output_file = File.join(@scenario_report.directory_name, "reopt/scenario_report_#{@scenario_report.id}_reopt_run.json")
|
78
88
|
@scenario_timeseries_default_output_file = File.join(@scenario_report.directory_name, "scenario_report_#{@scenario_report.id}_timeseries.csv")
|
79
89
|
|
80
90
|
@scenario_report.feature_reports.each do |fr|
|
81
|
-
if !Dir.exist?(File.join(fr.directory_name,
|
82
|
-
Dir.mkdir(File.join(fr.directory_name,
|
83
|
-
@@logger.info("Created directory:
|
91
|
+
if !Dir.exist?(File.join(fr.directory_name, 'reopt'))
|
92
|
+
Dir.mkdir(File.join(fr.directory_name, 'reopt'))
|
93
|
+
@@logger.info("Created directory: #{File.join(fr.directory_name, 'reopt')}")
|
84
94
|
end
|
85
95
|
@feature_reports_reopt_default_output_files << File.join(fr.directory_name, "reopt/feature_report_#{fr.id}_reopt_run.json")
|
86
96
|
end
|
@@ -103,8 +113,7 @@ module URBANopt # :nodoc:
|
|
103
113
|
end
|
104
114
|
end
|
105
115
|
|
106
|
-
attr_accessor :scenario_reopt_default_assumptions_hash, :scenario_reopt_default_output_file, :scenario_timeseries_default_output_file
|
107
|
-
attr_accessor :feature_reports_reopt_default_assumption_hashes, :feature_reports_reopt_default_output_files, :feature_reports_timeseries_default_output_files
|
116
|
+
attr_accessor :scenario_reopt_default_assumptions_hash, :scenario_reopt_default_output_file, :scenario_timeseries_default_output_file, :feature_reports_reopt_default_assumption_hashes, :feature_reports_reopt_default_output_files, :feature_reports_timeseries_default_output_files
|
108
117
|
|
109
118
|
##
|
110
119
|
# Updates a FeatureReport based on an optional set of \REopt Lite optimization assumptions.
|
@@ -119,7 +128,7 @@ module URBANopt # :nodoc:
|
|
119
128
|
#
|
120
129
|
# [*return:*] _URBANopt::Reporting::DefaultReports::FeatureReport_ - Returns an updated FeatureReport
|
121
130
|
##
|
122
|
-
def run_feature_report(feature_report:, reopt_assumptions_hash:nil, reopt_output_file:nil, timeseries_csv_path:nil, save_name:nil, run_resilience:true)
|
131
|
+
def run_feature_report(feature_report:, reopt_assumptions_hash: nil, reopt_output_file: nil, timeseries_csv_path: nil, save_name: nil, run_resilience: true)
|
123
132
|
api = URBANopt::REopt::REoptLiteAPI.new(@nrel_developer_key, @localhost)
|
124
133
|
adapter = URBANopt::REopt::FeatureReportAdapter.new
|
125
134
|
|
@@ -133,15 +142,14 @@ module URBANopt # :nodoc:
|
|
133
142
|
if File.directory? reopt_output_file
|
134
143
|
resilience_stats = api.resilience_request(run_uuid, reopt_output_file)
|
135
144
|
else
|
136
|
-
resilience_stats = api.resilience_request(run_uuid, reopt_output_file.sub!('.json','_resilience.json'))
|
145
|
+
resilience_stats = api.resilience_request(run_uuid, reopt_output_file.sub!('.json', '_resilience.json'))
|
137
146
|
end
|
138
147
|
else
|
139
148
|
resilience_stats = nil
|
140
149
|
end
|
141
150
|
result = adapter.update_feature_report(feature_report, reopt_output, timeseries_csv_path, resilience_stats)
|
142
151
|
if !save_name.nil?
|
143
|
-
|
144
|
-
result.save_json_report(save_name)
|
152
|
+
result.save save_name
|
145
153
|
end
|
146
154
|
return result
|
147
155
|
end
|
@@ -158,7 +166,7 @@ module URBANopt # :nodoc:
|
|
158
166
|
# * +timeseries_csv_path+ - _String_ - Optional. Path to a file at which the new timeseries CSV for the ScenarioReport will be saved.
|
159
167
|
#
|
160
168
|
# [*return:*] _URBANopt::Scenario::DefaultReports::ScenarioReport_ Returns an updated ScenarioReport
|
161
|
-
def run_scenario_report(scenario_report:, reopt_assumptions_hash:nil, reopt_output_file:nil, timeseries_csv_path:nil, save_name:nil, run_resilience:true)
|
169
|
+
def run_scenario_report(scenario_report:, reopt_assumptions_hash: nil, reopt_output_file: nil, timeseries_csv_path: nil, save_name: nil, run_resilience: true)
|
162
170
|
if !reopt_assumptions_hash.nil?
|
163
171
|
@scenario_reopt_default_assumptions_hash = reopt_assumptions_hash
|
164
172
|
end
|
@@ -180,7 +188,7 @@ module URBANopt # :nodoc:
|
|
180
188
|
if File.directory? @scenario_reopt_default_output_file
|
181
189
|
resilience_stats = api.resilience_request(run_uuid, @scenario_reopt_default_output_file)
|
182
190
|
else
|
183
|
-
resilience_stats = api.resilience_request(run_uuid, @scenario_reopt_default_output_file.sub!('.json','_resilience.json'))
|
191
|
+
resilience_stats = api.resilience_request(run_uuid, @scenario_reopt_default_output_file.sub!('.json', '_resilience.json'))
|
184
192
|
end
|
185
193
|
else
|
186
194
|
resilience_stats = nil
|
@@ -204,8 +212,7 @@ module URBANopt # :nodoc:
|
|
204
212
|
# * +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.
|
205
213
|
#
|
206
214
|
# [*return:*] _Array_ Returns an array of updated _URBANopt::Scenario::DefaultReports::FeatureReport_ objects
|
207
|
-
def run_feature_reports(feature_reports:, reopt_assumptions_hashes:[], reopt_output_files:[], timeseries_csv_paths:[], save_names:nil, run_resilience:true)
|
208
|
-
|
215
|
+
def run_feature_reports(feature_reports:, reopt_assumptions_hashes: [], reopt_output_files: [], timeseries_csv_paths: [], save_names: nil, run_resilience: true, keep_existing_output: false)
|
209
216
|
if !reopt_assumptions_hashes.empty?
|
210
217
|
@feature_reports_reopt_default_assumption_hashes = reopt_assumptions_hashes
|
211
218
|
end
|
@@ -234,37 +241,59 @@ module URBANopt # :nodoc:
|
|
234
241
|
feature_adapter = URBANopt::REopt::FeatureReportAdapter.new
|
235
242
|
new_feature_reports = []
|
236
243
|
feature_reports.each_with_index do |feature_report, idx|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
if
|
243
|
-
|
244
|
+
# check if we should rerun
|
245
|
+
if !(keep_existing_output && output_exists(@feature_reports_reopt_default_output_files[idx]))
|
246
|
+
begin
|
247
|
+
reopt_input = feature_adapter.reopt_json_from_feature_report(feature_report, @feature_reports_reopt_default_assumption_hashes[idx])
|
248
|
+
reopt_output = api.reopt_request(reopt_input, @feature_reports_reopt_default_output_files[idx])
|
249
|
+
if run_resilience
|
250
|
+
run_uuid = reopt_output['outputs']['Scenario']['run_uuid']
|
251
|
+
if File.directory? @feature_reports_reopt_default_output_files[idx]
|
252
|
+
resilience_stats = api.resilience_request(run_uuid, @feature_reports_reopt_default_output_files[idx])
|
253
|
+
else
|
254
|
+
resilience_stats = api.resilience_request(run_uuid, @feature_reports_reopt_default_output_files[idx].sub!('.json', '_resilience.json'))
|
255
|
+
end
|
244
256
|
else
|
245
|
-
resilience_stats =
|
257
|
+
resilience_stats = nil
|
246
258
|
end
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
new_feature_report.save_json_report save_names[idx]
|
256
|
-
else
|
257
|
-
warn "Could not save feature reports - the number of save names provided did not match the number of feature reports"
|
259
|
+
new_feature_report = feature_adapter.update_feature_report(feature_report, reopt_output, @feature_reports_timeseries_default_output_files[idx], resilience_stats)
|
260
|
+
new_feature_reports.push(new_feature_report)
|
261
|
+
if !save_names.nil?
|
262
|
+
if save_names.length == feature_reports.length
|
263
|
+
new_feature_report.save save_names[idx]
|
264
|
+
else
|
265
|
+
warn 'Could not save feature reports - the number of save names provided did not match the number of feature reports'
|
266
|
+
end
|
258
267
|
end
|
268
|
+
rescue StandardError
|
269
|
+
@@logger.info("Could not optimize Feature Report #{feature_report.name} #{feature_report.id}")
|
259
270
|
end
|
260
|
-
|
261
|
-
|
271
|
+
else
|
272
|
+
puts('Output file already exists...skipping')
|
262
273
|
end
|
263
274
|
end
|
264
275
|
|
265
276
|
return new_feature_reports
|
266
277
|
end
|
267
278
|
|
279
|
+
# Checks whether a feature has already been run by determining if output files already exists (for rate limit issues and larger projects)
|
280
|
+
##
|
281
|
+
#
|
282
|
+
# [*parameters:*]
|
283
|
+
#
|
284
|
+
# * +output_file+ - _Array_ - Optional. An array of paths to files at which REpopt Lite responses will be saved. The number and order of the paths should match the array in ScenarioReport.feature_reports.
|
285
|
+
# [*return:*] _Boolean_ - Returns true if file or nonempty directory exist
|
286
|
+
def output_exists(output_file)
|
287
|
+
res = false
|
288
|
+
if File.directory?(output_file) && !File.empty?(output_file)
|
289
|
+
res = true
|
290
|
+
elsif File.exist? output_file
|
291
|
+
res = true
|
292
|
+
end
|
293
|
+
|
294
|
+
return res
|
295
|
+
end
|
296
|
+
|
268
297
|
# Updates a ScenarioReport based on an optional set of \REopt Lite optimization assumptions.
|
269
298
|
##
|
270
299
|
#
|
@@ -276,22 +305,26 @@ module URBANopt # :nodoc:
|
|
276
305
|
# * +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.
|
277
306
|
#
|
278
307
|
# [*return:*] _URBANopt::Scenario::DefaultReports::ScenarioReport_ - Returns an updated ScenarioReport
|
279
|
-
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:true)
|
280
|
-
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)
|
281
|
-
|
308
|
+
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: true, keep_existing_output: false)
|
309
|
+
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)
|
310
|
+
puts("KEEP EXISTING? #{keep_existing_output}")
|
311
|
+
# only do this if you have run feature reports
|
282
312
|
new_scenario_report = URBANopt::Reporting::DefaultReports::ScenarioReport.new
|
283
|
-
|
284
|
-
new_scenario_report.name = scenario_report.name
|
285
|
-
new_scenario_report.directory_name = scenario_report.directory_name
|
313
|
+
if !new_feature_reports.empty?
|
286
314
|
|
287
|
-
|
288
|
-
|
315
|
+
new_scenario_report.id = scenario_report.id
|
316
|
+
new_scenario_report.name = scenario_report.name
|
317
|
+
new_scenario_report.directory_name = scenario_report.directory_name
|
289
318
|
|
290
|
-
|
291
|
-
new_scenario_report.
|
292
|
-
|
293
|
-
|
294
|
-
|
319
|
+
timeseries_hash = { column_names: scenario_report.timeseries_csv.column_names }
|
320
|
+
new_scenario_report.timeseries_csv = URBANopt::Reporting::DefaultReports::TimeseriesCSV.new(timeseries_hash)
|
321
|
+
|
322
|
+
new_feature_reports.each do |feature_report|
|
323
|
+
new_scenario_report.add_feature_report(feature_report)
|
324
|
+
end
|
325
|
+
if !save_name_scenario_report.nil?
|
326
|
+
new_scenario_report.save save_name_scenario_report
|
327
|
+
end
|
295
328
|
end
|
296
329
|
return new_scenario_report
|
297
330
|
end
|