urbanopt-reopt 0.5.6 → 0.6.2

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.
data/docs/package.json CHANGED
@@ -10,17 +10,24 @@
10
10
  },
11
11
  "author": "NREL",
12
12
  "dependencies": {
13
- "braces": "^3.0.2",
14
13
  "highlight.js": "^10.4.1",
15
14
  "json-schema-ref-parser": "^6.1.0",
16
15
  "json-schema-view-js": "git+https://git@github.com/bgschiller/json-schema-view-js.git",
17
- "serialize-javascript": "^5.0.1",
18
- "vuepress": "^1.6.0",
19
- "webpack-dev-middleware": "^3.6.0",
20
- "yargs-parser": "^18.1.1"
16
+ "webpack-dev-middleware": "^3.6.0"
21
17
  },
22
18
  "devDependencies": {
19
+ "braces": "^3.0.2",
20
+ "chokidar": ">=3.5.1",
21
+ "fsevents": ">=2.3.2",
23
22
  "gh-pages": "^2.0.1",
24
- "ini": "^2.0.0"
23
+ "ini": "^2.0.0",
24
+ "is-svg": "4.3.1",
25
+ "lodash": "^4.17.21",
26
+ "postcss": "^8.2.15",
27
+ "serialize-javascript": "^5.0.1",
28
+ "ssri": "8.0.1",
29
+ "url-parse": "^1.5.1",
30
+ "vuepress": "^1.8.2",
31
+ "yargs-parser": "^18.1.1"
25
32
  }
26
33
  }
@@ -68,7 +68,7 @@ module URBANopt # :nodoc:
68
68
  #
69
69
  # [*return:*] _Hash_ - Returns hash formatted for submittal to the \REopt Lite API
70
70
  ##
71
- def reopt_json_from_feature_report(feature_report, reopt_assumptions_hash = nil)
71
+ def reopt_json_from_feature_report(feature_report, reopt_assumptions_hash = nil, groundmount_photovoltaic = nil)
72
72
  name = feature_report.name.delete ' '
73
73
  description = "feature_report_#{name}_#{feature_report.id}"
74
74
  reopt_inputs = { Scenario: { Site: { ElectricTariff: { blended_monthly_demand_charges_us_dollars_per_kw: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], blended_monthly_rates_us_dollars_per_kwh: [0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13] }, LoadProfile: {}, Wind: { max_kw: 0 } } } }
@@ -99,15 +99,21 @@ module URBANopt # :nodoc:
99
99
  reopt_inputs[:Scenario][:Site][:longitude] = feature_report.location.longitude_deg
100
100
 
101
101
  # Parse Optional FeatureReport metrics - do not overwrite from assumptions file
102
- if reopt_inputs[:Scenario][:Site][:roof_squarefeet].nil?
103
- unless feature_report.program.roof_area_sqft.nil?
104
- reopt_inputs[:Scenario][:Site][:roof_squarefeet] = feature_report.program.roof_area_sqft[:available_roof_area_sqft]
105
- end
102
+ if reopt_inputs[:Scenario][:Site][:roof_squarefeet].nil? && !feature_report.program.roof_area_sqft.nil?
103
+ reopt_inputs[:Scenario][:Site][:roof_squarefeet] = feature_report.program.roof_area_sqft[:available_roof_area_sqft]
106
104
  end
107
105
 
108
106
  if reopt_inputs[:Scenario][:Site][:land_acres].nil?
109
- unless feature_report.program.site_area_sqft.nil?
110
- reopt_inputs[:Scenario][:Site][:land_acres] = feature_report.program.site_area_sqft * 1.0 / 43560 # acres/sqft
107
+ # Check if ground-mount PV is specified with the Feature ID and take footprint area of PV
108
+ # constrain for REopt optimization
109
+ begin
110
+ if !groundmount_photovoltaic[feature_report.id].nil?
111
+ reopt_inputs[:Scenario][:Site][:land_acres] = groundmount_photovoltaic[feature_report.id] * 1.0 / 43560 # acres/sqft
112
+ # If no ground-mount PV associated with feature use site area as constrain for REopt optimization
113
+ elsif !feature_report.program.site_area_sqft.nil?
114
+ reopt_inputs[:Scenario][:Site][:land_acres] = feature_report.program.site_area_sqft * 1.0 / 43560 # acres/sqft
115
+ end
116
+ rescue StandardError
111
117
  end
112
118
  end
113
119
 
@@ -117,23 +123,23 @@ module URBANopt # :nodoc:
117
123
 
118
124
  # Parse Load Profile
119
125
  begin
120
- #Convert kWh values in the timeseries CSV to kW
126
+ # Convert kWh values in the timeseries CSV to kW
121
127
  col_num = feature_report.timeseries_csv.column_names.index('Electricity:Facility(kWh)')
122
128
  t = CSV.read(feature_report.timeseries_csv.path, headers: true, converters: :numeric)
123
- energy_timeseries_kw = t.by_col[col_num].map { |e| ((e * feature_report.timesteps_per_hour || 0) ) }
124
- #Fill in missing timestep values with 0 if a full year is not provided
129
+ energy_timeseries_kw = t.by_col[col_num].map { |e| ((e * feature_report.timesteps_per_hour || 0)) }
130
+ # Fill in missing timestep values with 0 if a full year is not provided
125
131
  if energy_timeseries_kw.length < (feature_report.timesteps_per_hour * 8760)
126
- start_date = Time.parse(t.by_col["Datetime"][0])
132
+ start_date = Time.parse(t.by_col['Datetime'][0])
127
133
  start_ts = (((start_date.yday * 60.0 * 60.0 * 24) + (start_date.hour * 60.0 * 60.0) + (start_date.min * 60.0) + start_date.sec) /
128
- (( 60 / feature_report.timesteps_per_hour ) * 60)).to_int
129
- end_date = Time.parse(t.by_col["Datetime"][-1])
134
+ ((60 / feature_report.timesteps_per_hour) * 60)).to_int
135
+ end_date = Time.parse(t.by_col['Datetime'][-1])
130
136
  end_ts = (((end_date.yday * 60.0 * 60.0 * 24) + (end_date.hour * 60.0 * 60.0) + (end_date.min * 60.0) + end_date.sec) /
131
- (( 60 / feature_report.timesteps_per_hour ) * 60)).to_int
132
- energy_timeseries_kw = [0.0]*(start_ts-1) + energy_timeseries_kw + [0.0]*((feature_report.timesteps_per_hour * 8760) - end_ts)
137
+ ((60 / feature_report.timesteps_per_hour) * 60)).to_int
138
+ energy_timeseries_kw = [0.0] * (start_ts - 1) + energy_timeseries_kw + [0.0] * ((feature_report.timesteps_per_hour * 8760) - end_ts)
133
139
  end
134
- #Clip to one non-leap year's worth of data
135
- energy_timeseries_kw = energy_timeseries_kw.map { |e| e ? e : 0 }[0,(feature_report.timesteps_per_hour * 8760)]
136
- #Convert from the OpenDSS resolution to the REopt Lite resolution, if necessary
140
+ # Clip to one non-leap year's worth of data
141
+ energy_timeseries_kw = energy_timeseries_kw.map { |e| e || 0 }[0, (feature_report.timesteps_per_hour * 8760)]
142
+ # Convert from the OpenDSS resolution to the REopt Lite resolution, if necessary
137
143
  rescue StandardError
138
144
  @@logger.error("Could not parse the annual electric load from the timeseries csv - #{feature_report.timeseries_csv.path}")
139
145
  raise "Could not parse the annual electric load from the timeseries csv - #{feature_report.timeseries_csv.path}"
@@ -142,8 +148,7 @@ module URBANopt # :nodoc:
142
148
  # Convert load to REopt Resolution
143
149
  begin
144
150
  reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw] = convert_powerflow_resolution(energy_timeseries_kw, feature_report.timesteps_per_hour, reopt_inputs[:Scenario][:time_steps_per_hour])
145
-
146
- rescue
151
+ rescue StandardError
147
152
  @@logger.error("Could not convert the annual electric load from a resolution of #{feature_report.timesteps_per_hour} to #{reopt_inputs[:Scenario][:time_steps_per_hour]}")
148
153
  raise "Could not convert the annual electric load from a resolution of #{feature_report.timesteps_per_hour} to #{reopt_inputs[:Scenario][:time_steps_per_hour]}"
149
154
  end
@@ -151,9 +156,9 @@ module URBANopt # :nodoc:
151
156
  if reopt_inputs[:Scenario][:Site][:ElectricTariff][:coincident_peak_load_active_timesteps].nil?
152
157
  n_top_values = 100
153
158
  tmp1 = reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw]
154
- tmp2 = tmp1.each_index.max_by(n_top_values*reopt_inputs[:Scenario][:time_steps_per_hour]){|i| tmp1[i]}
159
+ tmp2 = tmp1.each_index.max_by(n_top_values * reopt_inputs[:Scenario][:time_steps_per_hour]) { |i| tmp1[i] }
155
160
  for i in (0...tmp2.count)
156
- tmp2[i] += 1
161
+ tmp2[i] += 1
157
162
  end
158
163
  reopt_inputs[:Scenario][:Site][:ElectricTariff][:coincident_peak_load_active_timesteps] = tmp2
159
164
  end
@@ -165,7 +170,6 @@ module URBANopt # :nodoc:
165
170
  return reopt_inputs
166
171
  end
167
172
 
168
-
169
173
  ##
170
174
  # Update a FeatureReport from a \REopt Lite response
171
175
  #
@@ -177,7 +181,7 @@ module URBANopt # :nodoc:
177
181
  #
178
182
  # [*return:*] _URBANopt::Reporting::DefaultReports::FeatureReport_ - Returns an updated FeatureReport.
179
183
  ##
180
- def update_feature_report(feature_report, reopt_output, timeseries_csv_path=nil, resilience_stats=nil)
184
+ def update_feature_report(feature_report, reopt_output, timeseries_csv_path = nil, resilience_stats = nil)
181
185
  # Check if the \REopt Lite response is valid
182
186
  if reopt_output['outputs']['Scenario']['status'] != 'optimal'
183
187
  @@logger.info("Warning cannot Feature Report #{feature_report.name} #{feature_report.id} - REopt optimization was non-optimal")
@@ -210,29 +214,40 @@ module URBANopt # :nodoc:
210
214
  feature_report.distributed_generation.probs_of_surviving_by_hour_of_the_day = resilience_stats['probs_of_surviving_by_hour_of_the_day']
211
215
  end
212
216
 
213
- if reopt_output['outputs']['Scenario']['Site']['PV'].class == Hash
217
+ if reopt_output['outputs']['Scenario']['Site']['PV'].instance_of?(Hash)
214
218
  reopt_output['outputs']['Scenario']['Site']['PV'] = [reopt_output['outputs']['Scenario']['Site']['PV']]
215
219
  elsif reopt_output['outputs']['Scenario']['Site']['PV'].nil?
216
220
  reopt_output['outputs']['Scenario']['Site']['PV'] = []
217
221
  end
218
222
 
223
+ # Store the PV name and location in a hash
224
+ location = {}
225
+ # Check whether multi PV assumption input file is used or single PV
226
+ if reopt_output['inputs']['Scenario']['Site']['PV'].is_a?(Array)
227
+ reopt_output['inputs']['Scenario']['Site']['PV'].each do |pv|
228
+ location[pv['pv_name']] = pv['location']
229
+ end
230
+ else
231
+ location[reopt_output['inputs']['Scenario']['Site']['PV']['pv_name']] = reopt_output['inputs']['Scenario']['Site']['PV']['location']
232
+ end
233
+
219
234
  reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
220
- feature_report.distributed_generation.add_tech 'solar_pv', URBANopt::Reporting::DefaultReports::SolarPV.new( {size_kw: (pv['size_kw'] || 0), id: i })
235
+ feature_report.distributed_generation.add_tech 'solar_pv', URBANopt::Reporting::DefaultReports::SolarPV.new({ size_kw: (pv['size_kw'] || 0), id: i, location: location[pv['pv_name']] })
221
236
  end
222
237
 
223
238
  wind = reopt_output['outputs']['Scenario']['Site']['Wind']
224
- if !wind['size_kw'].nil? and wind['size_kw'] != 0
225
- feature_report.distributed_generation.add_tech 'wind', URBANopt::Reporting::DefaultReports::Wind.new( {size_kw: (wind['size_kw'] || 0) })
239
+ if !wind['size_kw'].nil? && (wind['size_kw'] != 0)
240
+ feature_report.distributed_generation.add_tech 'wind', URBANopt::Reporting::DefaultReports::Wind.new({ size_kw: (wind['size_kw'] || 0) })
226
241
  end
227
242
 
228
243
  generator = reopt_output['outputs']['Scenario']['Site']['Generator']
229
- if !generator['size_kw'].nil? and generator['size_kw'] != 0
230
- feature_report.distributed_generation.add_tech 'generator', URBANopt::Reporting::DefaultReports::Generator.new( {size_kw: (generator['size_kw'] || 0) })
244
+ if !generator['size_kw'].nil? && (generator['size_kw'] != 0)
245
+ feature_report.distributed_generation.add_tech 'generator', URBANopt::Reporting::DefaultReports::Generator.new({ size_kw: (generator['size_kw'] || 0) })
231
246
  end
232
247
 
233
248
  storage = reopt_output['outputs']['Scenario']['Site']['Storage']
234
- if !storage['size_kw'].nil? and storage['size_kw'] != 0
235
- feature_report.distributed_generation.add_tech 'storage', URBANopt::Reporting::DefaultReports::Storage.new( {size_kwh: (storage['size_kwh'] || 0), size_kw: (storage['size_kw'] || 0) })
249
+ if !storage['size_kw'].nil? && (storage['size_kw'] != 0)
250
+ feature_report.distributed_generation.add_tech 'storage', URBANopt::Reporting::DefaultReports::Storage.new({ size_kwh: (storage['size_kwh'] || 0), size_kw: (storage['size_kw'] || 0) })
236
251
  end
237
252
 
238
253
  generation_timeseries_kwh = Matrix[[0] * (8760 * feature_report.timesteps_per_hour)]
@@ -240,28 +255,18 @@ module URBANopt # :nodoc:
240
255
 
241
256
  unless reopt_output['outputs']['Scenario']['Site']['PV'].nil?
242
257
  reopt_output['outputs']['Scenario']['Site']['PV'].each do |pv|
243
- if (pv['size_kw'] || 0) > 0
244
- if !pv['year_one_power_production_series_kw'].nil?
245
- generation_timeseries_kwh += Matrix[convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
246
- end
258
+ if (pv['size_kw'] || 0) > 0 && !pv['year_one_power_production_series_kw'].nil?
259
+ generation_timeseries_kwh += Matrix[convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
247
260
  end
248
- end
261
+ end
249
262
  end
250
263
 
251
- unless reopt_output['outputs']['Scenario']['Site']['Wind'].nil?
252
- if (reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) > 0
253
- if !reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'].nil?
254
- generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
255
- end
256
- end
264
+ if !reopt_output['outputs']['Scenario']['Site']['Wind'].nil? && ((reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) > 0) && !reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'].nil?
265
+ generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
257
266
  end
258
267
 
259
- unless reopt_output['outputs']['Scenario']['Site']['Generator'].nil?
260
- if (reopt_output['outputs']['Scenario']['Site']['Generator']['size_kw'] || 0) > 0
261
- if !reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'].nil?
262
- generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
263
- end
264
- end
268
+ if !reopt_output['outputs']['Scenario']['Site']['Generator'].nil? && ((reopt_output['outputs']['Scenario']['Site']['Generator']['size_kw'] || 0) > 0) && !reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'].nil?
269
+ generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
265
270
  end
266
271
 
267
272
  $generation_timeseries_kwh = generation_timeseries_kwh.to_a[0] || [0] * (8760 * feature_report.timesteps_per_hour)
@@ -359,7 +364,6 @@ module URBANopt # :nodoc:
359
364
  feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToLoad(kw)')
360
365
  end
361
366
 
362
-
363
367
  $pv_to_grid_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToGrid(kw)')
364
368
  if $pv_to_grid_col.nil?
365
369
  $pv_to_grid_col = feature_report.timeseries_csv.column_names.length
@@ -441,14 +445,14 @@ module URBANopt # :nodoc:
441
445
  start_ts = (
442
446
  (
443
447
  ((start_date.yday - 1) * 60.0 * 60.0 * 24) +
444
- (((start_date.hour) - 1) * 60.0 * 60.0) +
445
- (start_date.min * 60.0) + start_date.sec ) /
446
- (( 60 / feature_report.timesteps_per_hour ) * 60)
448
+ ((start_date.hour - 1) * 60.0 * 60.0) +
449
+ (start_date.min * 60.0) + start_date.sec) /
450
+ ((60 / feature_report.timesteps_per_hour) * 60)
447
451
  ).to_int
448
452
 
449
453
  mod_data = old_data.map.with_index do |x, i|
450
454
  if i > 0
451
- modrow(x, start_ts + i -1)
455
+ modrow(x, start_ts + i - 1)
452
456
  else
453
457
  x
454
458
  end
@@ -97,6 +97,7 @@ module URBANopt # :nodoc:
97
97
  if @use_localhost
98
98
  return URI.parse("http://127.0.0.1:8000/v1/job/#{run_uuid}/results")
99
99
  end
100
+
100
101
  return URI.parse("https://developer.nrel.gov/api/reopt/v1/job/#{run_uuid}/results?api_key=#{@nrel_developer_key}")
101
102
  end
102
103
 
@@ -114,6 +115,7 @@ module URBANopt # :nodoc:
114
115
  if @use_localhost
115
116
  return URI.parse("http://127.0.0.1:8000/v1/job/#{run_uuid}/resilience_stats")
116
117
  end
118
+
117
119
  return URI.parse("https://developer.nrel.gov/api/reopt/v1/job/#{run_uuid}/resilience_stats?api_key=#{@nrel_developer_key}")
118
120
  end
119
121
 
@@ -122,11 +124,34 @@ module URBANopt # :nodoc:
122
124
  tries = 0
123
125
  while tries < max_tries
124
126
  begin
125
- result = http.request(r)
126
- tries = 4
127
- rescue StandardError
128
- tries += 1
129
- end
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. The URBANopt CLI flag --reopt-keep-existing can be used to resume the optimization')
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
+ # display error messages
137
+ json_res = JSON.parse(result.body, allow_nan: true)
138
+ json_res['messages'].delete('warnings') if json_res['messages']['warnings']
139
+ json_res['messages'].delete('Deprecations') if json_res['messages']['Deprecations']
140
+ if json_res['messages']
141
+ @@logger.error("MESSAGES: #{json_res['messages']}")
142
+ end
143
+ end
144
+ tries = max_tries
145
+ rescue StandardError => e
146
+ @@logger.debug("error from REopt lite API: #{e}")
147
+ if tries + 1 < max_tries
148
+ @@logger.debug('trying again...')
149
+ else
150
+ @@logger.debug('max tries reached!')
151
+ return
152
+ end
153
+ tries += 1
154
+ end
130
155
  end
131
156
  return result
132
157
  end
@@ -148,11 +173,11 @@ module URBANopt # :nodoc:
148
173
  http.use_ssl = true
149
174
  end
150
175
 
151
- request = Net::HTTP::Post.new(@uri_submit, header)
152
- request.body = ::JSON.generate(data, allow_nan: true)
176
+ post_request = Net::HTTP::Post.new(@uri_submit, header)
177
+ post_request.body = ::JSON.generate(data, allow_nan: true)
153
178
 
154
179
  # Send the request
155
- response = make_request(http, request)
180
+ response = make_request(http, post_request)
156
181
 
157
182
  if !response.is_a?(Net::HTTPSuccess)
158
183
  @@logger.error('Check_connection Failed')
@@ -175,7 +200,6 @@ module URBANopt # :nodoc:
175
200
  # [*return:*] _Bool_ - Returns true if the post succeeeds. Otherwise returns false.
176
201
  ##
177
202
  def resilience_request(run_uuid, filename)
178
-
179
203
  if File.directory? filename
180
204
  if run_uuid.nil?
181
205
  run_uuid = 'error'
@@ -187,54 +211,59 @@ module URBANopt # :nodoc:
187
211
  @@logger.info("REopt results saved to #{filename}")
188
212
  end
189
213
 
190
- #Submit Job
214
+ # Submit Job
191
215
  @@logger.info("Submitting Resilience Statistics job for #{run_uuid}")
192
216
  header = { 'Content-Type' => 'application/json' }
193
217
  http = Net::HTTP.new(@uri_submit_outagesimjob.host, @uri_submit_outagesimjob.port)
194
218
  if !@use_localhost
195
219
  http.use_ssl = true
196
220
  end
197
- request = Net::HTTP::Post.new(@uri_submit_outagesimjob, header)
198
- request.body = ::JSON.generate({"run_uuid" => run_uuid, "bau" => false }, allow_nan: true)
199
- submit_response = make_request(http, request)
200
- @@logger.info(submit_response.body)
221
+ post_request = Net::HTTP::Post.new(@uri_submit_outagesimjob, header)
222
+ post_request.body = ::JSON.generate({ 'run_uuid' => run_uuid, 'bau' => false }, allow_nan: true)
223
+ submit_response = make_request(http, post_request)
224
+ @@logger.debug(submit_response.body)
201
225
 
202
- #Fetch Results
226
+ # Fetch Results
203
227
  uri = uri_resilience(run_uuid)
204
228
  http = Net::HTTP.new(uri.host, uri.port)
205
229
  if !@use_localhost
206
230
  http.use_ssl = true
207
231
  end
208
232
 
233
+ # Wait a few seconds for the REopt database to update before GETing results
234
+ sleep 5
235
+ get_request = Net::HTTP::Get.new(uri.request_uri)
236
+ response = make_request(http, get_request, 8)
237
+
238
+ # Set a limit on retries when 404s are returned from REopt API
209
239
  elapsed_time = 0
210
240
  max_elapsed_time = 60 * 5
211
241
 
212
- request = Net::HTTP::Get.new(uri.request_uri)
213
- response = make_request(http, request)
214
-
215
- while (elapsed_time < max_elapsed_time) & (response.code == "404")
216
- response = make_request(http, request)
242
+ # If database still hasn't updated, wait a little longer and try again
243
+ while (elapsed_time < max_elapsed_time) & (response.code == '404')
244
+ response = make_request(http, get_request)
245
+ @@logger.warn('GET request was too fast for REOpt-Lite API. Retrying...')
217
246
  elapsed_time += 5
218
247
  sleep 5
219
248
  end
220
249
 
221
- data = JSON.parse(response.body)
222
- text = ::JSON.generate(data, allow_nan: true)
250
+ data = JSON.parse(response.body, allow_nan: true)
251
+ text = JSON.pretty_generate(data)
223
252
  begin
224
253
  File.open(filename, 'w+') do |f|
225
254
  f.puts(text)
226
255
  end
227
- rescue
228
- @@logger.info("Cannot write - #{filename}")
256
+ rescue StandardError => e
257
+ @@logger.error("Cannot write - #{filename}")
258
+ @@logger.error("ERROR: #{e}")
229
259
  end
230
260
 
231
- if response.code == "200"
261
+ if response.code == '200'
232
262
  return data
233
263
  end
234
264
 
235
- @@logger.info("Error from REopt API - #{data['Error']}")
265
+ @@logger.error("Error from REopt API - #{data['Error']}")
236
266
  return {}
237
-
238
267
  end
239
268
 
240
269
  ##
@@ -261,14 +290,18 @@ module URBANopt # :nodoc:
261
290
  if !@use_localhost
262
291
  http.use_ssl = true
263
292
  end
264
- request = Net::HTTP::Post.new(@uri_submit, header)
265
- request.body = ::JSON.generate(reopt_input, allow_nan: true)
293
+ post_request = Net::HTTP::Post.new(@uri_submit, header)
294
+ post_request.body = ::JSON.generate(reopt_input, allow_nan: true)
266
295
 
267
296
  # Send the request
268
- response = make_request(http, request)
297
+ response = make_request(http, post_request)
298
+ if !response.is_a?(Net::HTTPSuccess)
299
+ @@logger.error('make_request Failed')
300
+ raise 'Check_connection Failed'
301
+ end
269
302
 
270
303
  # Get UUID
271
- run_uuid = JSON.parse(response.body, allow_nan:true)['run_uuid']
304
+ run_uuid = JSON.parse(response.body, allow_nan: true)['run_uuid']
272
305
 
273
306
  if File.directory? filename
274
307
  if run_uuid.nil?
@@ -281,12 +314,11 @@ module URBANopt # :nodoc:
281
314
  @@logger.info("REopt results saved to #{filename}")
282
315
  end
283
316
 
284
- text = ::JSON.generate(response.body, allow_nan: true)
317
+ text = JSON.parse(response.body, allow_nan: true)
285
318
  if response.code != '201'
286
319
  File.open(filename, 'w+') do |f|
287
- f.puts(text)
320
+ f.puts(JSON.pretty_generate(text))
288
321
  end
289
- @@logger.info("Cannot write - #{filename}")
290
322
  raise "Error in REopt optimization post - see #{filename}"
291
323
  end
292
324
 
@@ -298,17 +330,17 @@ module URBANopt # :nodoc:
298
330
  http.use_ssl = true
299
331
  end
300
332
 
301
- request = Net::HTTP::Get.new(uri.request_uri)
333
+ get_request = Net::HTTP::Get.new(uri.request_uri)
302
334
 
303
335
  while status == 'Optimizing...'
304
- response = make_request(http, request)
336
+ response = make_request(http, get_request)
305
337
 
306
- data = JSON.parse(response.body, allow_nan:true)
338
+ data = JSON.parse(response.body, allow_nan: true)
307
339
 
308
- if data['outputs']['Scenario']['Site']['PV'].kind_of?(Array)
340
+ if data['outputs']['Scenario']['Site']['PV'].is_a?(Array)
309
341
  pv_sizes = 0
310
342
  data['outputs']['Scenario']['Site']['PV'].each do |x|
311
- pv_sizes = pv_sizes + x['size_kw'].to_f
343
+ pv_sizes += x['size_kw'].to_f
312
344
  end
313
345
  else
314
346
  pv_sizes = data['outputs']['Scenario']['Site']['PV']['size_kw'] || 0
@@ -323,13 +355,13 @@ module URBANopt # :nodoc:
323
355
  _tries = 0
324
356
  (check_complete = sizes == 0) && ((data['outputs']['Scenario']['Site']['Financial']['npv_us_dollars'] || 0) > 0)
325
357
  while (_tries < _max_retry) && check_complete
326
- sleep 1
327
- response = make_request(http, request)
328
- data = JSON.parse(response.body, allow_nan:true)
329
- if data['outputs']['Scenario']['Site']['PV'].kind_of?(Array)
358
+ sleep 3
359
+ response = make_request(http, get_request)
360
+ data = JSON.parse(response.body, allow_nan: true)
361
+ if data['outputs']['Scenario']['Site']['PV'].is_a?(Array)
330
362
  pv_sizes = 0
331
363
  data['outputs']['Scenario']['Site']['PV'].each do |x|
332
- pv_sizes = pv_sizes + x['size_kw'].to_f
364
+ pv_sizes += x['size_kw'].to_f
333
365
  end
334
366
  else
335
367
  pv_sizes = data['outputs']['Scenario']['Site']['PV']['size_kw'] || 0
@@ -339,14 +371,14 @@ module URBANopt # :nodoc:
339
371
  _tries += 1
340
372
  end
341
373
 
342
- data = JSON.parse(response.body)
343
- text = ::JSON.generate(data, allow_nan: true)
374
+ data = JSON.parse(response.body, allow_nan: true)
375
+ text = JSON.pretty_generate(data)
344
376
  begin
345
377
  File.open(filename, 'w+') do |f|
346
378
  f.puts(text)
347
379
  end
348
- rescue
349
- @@logger.info("Cannot write - #{filename}")
380
+ rescue StandardError
381
+ @@logger.error("Cannot write - #{filename}")
350
382
  end
351
383
 
352
384
  if status == 'optimal'
@@ -42,7 +42,7 @@ require 'logger'
42
42
 
43
43
  module URBANopt
44
44
  module REopt
45
- @@reopt_logger = Logger.new(STDOUT)
45
+ @@reopt_logger = Logger.new($stdout)
46
46
  ##
47
47
  # Definining class variable "@@logger" to log errors, info and warning messages.
48
48
  def self.reopt_logger