urbanopt-reopt 0.11.0 → 0.12.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.
@@ -29,8 +29,8 @@ module URBANopt # :nodoc:
29
29
  def initialize(nrel_developer_key = nil, use_localhost = false)
30
30
  @use_localhost = use_localhost
31
31
  if @use_localhost
32
- @uri_submit = URI.parse('http//:127.0.0.1:8000/v2/job/')
33
- @uri_submit_outagesimjob = URI.parse('http//:127.0.0.1:8000/v2/outagesimjob/')
32
+ @uri_submit = URI.parse('http//:127.0.0.1:8000/v3/job/')
33
+ @uri_submit_outagesimjob = URI.parse('http//:127.0.0.1:8000/v3/outagesimjob/')
34
34
  else
35
35
  if [nil, '', '<insert your key here>'].include? nrel_developer_key
36
36
  if [nil, '', '<insert your key here>'].include? DEVELOPER_NREL_KEY
@@ -40,8 +40,8 @@ module URBANopt # :nodoc:
40
40
  end
41
41
  end
42
42
  @nrel_developer_key = nrel_developer_key
43
- @uri_submit = URI.parse("https://developer.nrel.gov/api/reopt/v2/job?api_key=#{@nrel_developer_key}")
44
- @uri_submit_outagesimjob = URI.parse("https://developer.nrel.gov/api/reopt/v2/outagesimjob?api_key=#{@nrel_developer_key}")
43
+ @uri_submit = URI.parse("https://developer.nrel.gov/api/reopt/v3/job?api_key=#{@nrel_developer_key}")
44
+ @uri_submit_outagesimjob = URI.parse("https://developer.nrel.gov/api/reopt/v3/outagesimjob?api_key=#{@nrel_developer_key}")
45
45
  # initialize @@logger
46
46
  @@logger ||= URBANopt::REopt.reopt_logger
47
47
  end
@@ -59,10 +59,10 @@ module URBANopt # :nodoc:
59
59
  ##
60
60
  def uri_results(run_uuid) # :nodoc:
61
61
  if @use_localhost
62
- return URI.parse("http://127.0.0.1:8000/v2/job/#{run_uuid}/results")
62
+ return URI.parse("http://127.0.0.1:8000/v3/job/#{run_uuid}/results")
63
63
  end
64
64
 
65
- return URI.parse("https://developer.nrel.gov/api/reopt/v2/job/#{run_uuid}/results?api_key=#{@nrel_developer_key}")
65
+ return URI.parse("https://developer.nrel.gov/api/reopt/v3/job/#{run_uuid}/results?api_key=#{@nrel_developer_key}")
66
66
  end
67
67
 
68
68
  ##
@@ -77,10 +77,10 @@ module URBANopt # :nodoc:
77
77
  ##
78
78
  def uri_resilience(run_uuid) # :nodoc:
79
79
  if @use_localhost
80
- return URI.parse("http://127.0.0.1:8000/v2/job/#{run_uuid}/resilience_stats")
80
+ return URI.parse("http://127.0.0.1:8000/v3/job/#{run_uuid}/resilience_stats")
81
81
  end
82
82
 
83
- return URI.parse("https://developer.nrel.gov/api/reopt/v2/job/#{run_uuid}/resilience_stats?api_key=#{@nrel_developer_key}")
83
+ return URI.parse("https://developer.nrel.gov/api/reopt/v3/job/#{run_uuid}/resilience_stats?api_key=#{@nrel_developer_key}")
84
84
  end
85
85
 
86
86
  def make_request(http, req, max_tries = 3)
@@ -199,21 +199,21 @@ module URBANopt # :nodoc:
199
199
  http.use_ssl = true
200
200
  end
201
201
 
202
- # Wait a few seconds for the REopt database to update before GETing results
203
- sleep 5
202
+ # Wait for the REopt API before attempting to GET results
203
+ sleep 30
204
204
  get_request = Net::HTTP::Get.new(uri.request_uri)
205
205
  response = make_request(http, get_request, 8)
206
206
 
207
207
  # Set a limit on retries when 404s are returned from REopt API
208
208
  elapsed_time = 0
209
- max_elapsed_time = 60 * 5
209
+ max_elapsed_time = 60 * 15
210
210
 
211
- # If database still hasn't updated, wait a little longer and try again
211
+ # If database still hasn't updated, wait longer and try again
212
212
  while (elapsed_time < max_elapsed_time) && (response && response.code == '404')
213
213
  response = make_request(http, get_request)
214
214
  @@logger.warn('GET request was too fast for REOpt-API. Retrying...')
215
- elapsed_time += 5
216
- sleep 5
215
+ elapsed_time += 15
216
+ sleep 15
217
217
  end
218
218
 
219
219
  data = JSON.parse(response.body, allow_nan: true)
@@ -249,7 +249,7 @@ module URBANopt # :nodoc:
249
249
  # [*return:*] _Bool_ - Returns true if the post succeeeds. Otherwise returns false.
250
250
  ##
251
251
  def reopt_request(reopt_input, filename)
252
- description = reopt_input[:Scenario][:description]
252
+ description = reopt_input[:description]
253
253
 
254
254
  @@logger.info("Submitting #{description} to REopt API")
255
255
 
@@ -301,45 +301,84 @@ module URBANopt # :nodoc:
301
301
 
302
302
  get_request = Net::HTTP::Get.new(uri.request_uri)
303
303
 
304
+ counter = 0
304
305
  while status == 'Optimizing...'
305
306
  response = make_request(http, get_request)
306
307
 
307
308
  data = JSON.parse(response.body, allow_nan: true)
308
309
 
309
- if data['outputs']['Scenario']['Site']['PV'].is_a?(Array)
310
+ if !data['outputs']['PV']
310
311
  pv_sizes = 0
311
- data['outputs']['Scenario']['Site']['PV'].each do |x|
312
- pv_sizes += x['size_kw'].to_f
313
- end
312
+ sizes = 0
314
313
  else
315
- pv_sizes = data['outputs']['Scenario']['Site']['PV']['size_kw'] || 0
314
+ # there should be results in there now
315
+ if data['outputs']['PV'].is_a?(Array)
316
+ pv_sizes = 0
317
+ data['outputs']['PV'].each do |x|
318
+ pv_sizes += x['size_kw'].to_f
319
+ end
320
+ else
321
+ data['outputs'].each do |energy_source, data|
322
+ if data.is_a?(Hash) && data.key?('size_kw')
323
+ @@logger.debug("#{energy_source}: size_kw = #{data['size_kw'].to_f}")
324
+ sizes += data['size_kw'].to_f
325
+ end
326
+ end
327
+ end
328
+ end
329
+
330
+ status = data['status']
331
+ @@logger.debug("STATUS: #{status}")
332
+
333
+ if status == 'error'
334
+ puts "response.code: #{response.code}"
335
+ puts "message: #{response.message}"
336
+ error_message = data['messages']['errors']
337
+ raise "Error from REopt API - #{error_message}"
316
338
  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
339
 
320
- sleep 5
340
+ sleep 15
321
341
  end
322
342
 
323
343
  max_retry = 5
324
344
  tries = 0
325
- (check_complete = sizes == 0) && ((data['outputs']['Scenario']['Site']['Financial']['npv_us_dollars'] || 0) > 0)
326
- while (tries < max_retry) && check_complete
327
- sleep 3
328
- response = make_request(http, get_request)
329
- data = JSON.parse(response.body, allow_nan: true)
330
- if data['outputs']['Scenario']['Site']['PV'].is_a?(Array)
331
- pv_sizes = 0
332
- data['outputs']['Scenario']['Site']['PV'].each do |x|
333
- pv_sizes += x['size_kw'].to_f
345
+
346
+ check_complete = sizes == 0
347
+ # I don't know what this line does:
348
+ # (((data['outputs'] && data['outputs'].key?('Financial') && data['outputs']['Financial']['npv']) || 0) > 0)
349
+
350
+ if check_complete
351
+ @@logger.info('sizes are 0...checking optimization complete')
352
+
353
+ while (tries < max_retry) && check_complete
354
+ sleep 3
355
+ response = make_request(http, get_request)
356
+ data = JSON.parse(response.body, allow_nan: true)
357
+
358
+ if data['outputs'].key?('PV') && data['outputs']['PV'].is_a?(Array)
359
+ pv_sizes = 0
360
+ data['outputs']['PV'].each do |x|
361
+ pv_sizes += x['size_kw'].to_f
362
+ end
363
+ else
364
+ data['outputs'].each do |energy_source, data|
365
+ if data.is_a?(Hash) && data.key?('size_kw')
366
+ @@logger.debug("#{energy_source}: size_kw = #{data['size_kw'].to_f}")
367
+ sizes += data['size_kw'].to_f
368
+ end
369
+ end
334
370
  end
335
- else
336
- pv_sizes = data['outputs']['Scenario']['Site']['PV']['size_kw'] || 0
371
+
372
+ # I don't understand this line fully:
373
+ #(check_complete = sizes == 0) && ((data['outputs']['Financial']['npv'] || 0) > 0)
374
+
375
+ check_complete = sizes == 0
376
+ tries += 1
337
377
  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
378
  end
342
379
 
380
+ @@logger.info('REopt optimization complete and processed')
381
+
343
382
  data = JSON.parse(response.body, allow_nan: true)
344
383
  text = JSON.pretty_generate(data)
345
384
  begin
@@ -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,7 @@ 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
+ @reopt_base_post = { ElectricTariff: {}, ElectricLoad: {}, Wind: { max_kw: 0 } }
36
37
 
37
38
  @scenario_reopt_default_output_file = nil
38
39
  @scenario_timeseries_default_output_file = nil
@@ -92,7 +93,7 @@ module URBANopt # :nodoc:
92
93
  #
93
94
  # [*return:*] _URBANopt::Reporting::DefaultReports::FeatureReport_ - Returns an updated FeatureReport
94
95
  ##
95
- def run_feature_report(feature_report:, reopt_assumptions_hash: nil, reopt_output_file: nil, timeseries_csv_path: nil, save_name: nil, run_resilience: true)
96
+ 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
97
  api = URBANopt::REopt::REoptLiteAPI.new(@nrel_developer_key, @localhost)
97
98
  adapter = URBANopt::REopt::FeatureReportAdapter.new
98
99
 
@@ -103,7 +104,7 @@ module URBANopt # :nodoc:
103
104
  reopt_output = api.reopt_request(reopt_input, reopt_output_file)
104
105
  @@logger.debug("REOpt output file: #{reopt_output_file}")
105
106
  if run_resilience
106
- run_uuid = reopt_output['outputs']['Scenario']['run_uuid']
107
+ run_uuid = reopt_output['outputs']['run_uuid']
107
108
  if File.directory? reopt_output_file
108
109
  resilience_stats = api.resilience_request(run_uuid, reopt_output_file)
109
110
  else
@@ -112,6 +113,7 @@ module URBANopt # :nodoc:
112
113
  else
113
114
  resilience_stats = nil
114
115
  end
116
+
115
117
  result = adapter.update_feature_report(feature_report, reopt_output, timeseries_csv_path, resilience_stats)
116
118
  if !save_name.nil?
117
119
  result.save save_name
@@ -131,8 +133,7 @@ module URBANopt # :nodoc:
131
133
  # * +timeseries_csv_path+ - _String_ - Optional. Path to a file at which the new timeseries CSV for the ScenarioReport will be saved.
132
134
  #
133
135
  # [*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: true, community_photovoltaic: nil)
135
- puts 'run scenario report'
136
+ 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
137
  @save_assumptions_filepath = false
137
138
  if !reopt_assumptions_hash.nil?
138
139
  @scenario_reopt_default_assumptions_hash = reopt_assumptions_hash
@@ -150,10 +151,10 @@ module URBANopt # :nodoc:
150
151
  adapter = URBANopt::REopt::ScenarioReportAdapter.new
151
152
 
152
153
  reopt_input = adapter.reopt_json_from_scenario_report(scenario_report, @scenario_reopt_default_assumptions_hash, community_photovoltaic)
153
-
154
154
  reopt_output = api.reopt_request(reopt_input, @scenario_reopt_default_output_file)
155
+
155
156
  if run_resilience
156
- run_uuid = reopt_output['outputs']['Scenario']['run_uuid']
157
+ run_uuid = reopt_output['outputs']['run_uuid']
157
158
  if File.directory? @scenario_reopt_default_output_file
158
159
  resilience_stats = api.resilience_request(run_uuid, @scenario_reopt_default_output_file)
159
160
  else
@@ -187,7 +188,7 @@ module URBANopt # :nodoc:
187
188
  # * +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
189
  #
189
190
  # [*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: true, keep_existing_output: false, groundmount_photovoltaic: nil)
191
+ 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
192
  if !reopt_assumptions_hashes.empty?
192
193
  @feature_reports_reopt_default_assumption_hashes = reopt_assumptions_hashes
193
194
  end
@@ -222,7 +223,7 @@ module URBANopt # :nodoc:
222
223
  reopt_input = feature_adapter.reopt_json_from_feature_report(feature_report, @feature_reports_reopt_default_assumption_hashes[idx], groundmount_photovoltaic)
223
224
  reopt_output = api.reopt_request(reopt_input, @feature_reports_reopt_default_output_files[idx])
224
225
  if run_resilience
225
- run_uuid = reopt_output['outputs']['Scenario']['run_uuid']
226
+ run_uuid = reopt_output['outputs']['run_uuid']
226
227
  if File.directory? @feature_reports_reopt_default_output_files[idx]
227
228
  resilience_stats = api.resilience_request(run_uuid, @feature_reports_reopt_default_output_files[idx])
228
229
  else
@@ -281,7 +282,7 @@ module URBANopt # :nodoc:
281
282
  # * +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
283
  #
283
284
  # [*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: true, keep_existing_output: false, groundmount_photovoltaic: nil)
285
+ 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
286
  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
287
 
287
288
  # only do this if you have run feature reports