urbanopt-reopt 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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