urbanopt-reopt 1.3.0 → 1.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56b147451f96d95e26e2ea20dfb9b408b4677dae6ae8d9233008ce7a07f4cb2d
4
- data.tar.gz: 93660c184fdd2dcdfc20386c7230a96b3627ea38b751f08c8774b440fe4794dd
3
+ metadata.gz: 16f2855f1542984a58e3c18227c04edd4ed17e6a7a363989b38ca51b930824c1
4
+ data.tar.gz: b968cf095c32503e8ddba6bfde6a4a7d781bff5326108da9ed87fd69f4a6385e
5
5
  SHA512:
6
- metadata.gz: 502fabf84a4d43b93ba7b91ebe206f55eb7b117b310809592dc5190821bc7e36804feab7bee916b38ee9b7a66781cd23c0db95f8d373b03f68baff96ab9a8f52
7
- data.tar.gz: 8049c39934e712e76db8d9dd6c4ac54b0c7788bc6f0129ec92cab1d929b15e253f6ff2df51893e995578107a91975e86f742a06a6d145aebd7ba1747c7487059
6
+ metadata.gz: 5c6c52124fb29ca5c298d61377f95b0d060bd066bfe1ebd254f09f9c47ba870e050c34c4f395b3e23b0823879af60699a1fa0e24985dba87c02ea78fcada2cd8
7
+ data.tar.gz: 0cc3b7e46f640af234307a8b62e6665067d8a4ec3a303ffda482d2b3c0bb488dd3fb0062ab4507d26f2e72281b2274a47987050a23f9f43f949d9f4350c90802
data/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # URBANopt REopt Gem
2
2
 
3
+ ## Version 1.3.1
4
+
5
+ * Fix showing the battery and PV columns in scenario_optimization in https://github.com/urbanopt/urbanopt-reopt-gem/pull/176
6
+ * Update error handling for ghp LCCA in https://github.com/urbanopt/urbanopt-reopt-gem/pull/177
7
+
3
8
  ## Version 1.3.0
9
+
4
10
  * Updates for developer.nlr.gov URL change
5
11
  * Timeseries shift bug fix
6
12
  * Added Domestic Hot Water to baseline load
@@ -14,7 +20,7 @@
14
20
 
15
21
  ## Version 1.1.0
16
22
 
17
- * Upgrade to OpenStudio 3.10
23
+ * Upgrade to OpenStudio 3.10
18
24
 
19
25
  ## Version 1.0.0
20
26
 
@@ -226,6 +226,10 @@ module URBANopt # :nodoc:
226
226
  end
227
227
  end
228
228
 
229
+ wind = nil
230
+ generator = nil
231
+ storage = nil
232
+
229
233
  if reopt_output['outputs'].key?('Wind')
230
234
  wind = reopt_output['outputs']['Wind']
231
235
  feature_report.distributed_generation.add_tech 'wind', URBANopt::Reporting::DefaultReports::Wind.new({ size_kw: (wind['size_kw'] || 0) })
@@ -235,29 +239,49 @@ module URBANopt # :nodoc:
235
239
  generator = reopt_output['outputs']['Generator']
236
240
  feature_report.distributed_generation.add_tech 'generator', URBANopt::Reporting::DefaultReports::Generator.new({ size_kw: (generator['size_kw'] || 0) })
237
241
  end
242
+ $has_generator = !generator.nil?
238
243
 
239
244
  if reopt_output['outputs'].key?('ElectricStorage')
240
245
  storage = reopt_output['outputs']['ElectricStorage']
241
246
  feature_report.distributed_generation.add_tech 'storage', URBANopt::Reporting::DefaultReports::Storage.new({ size_kwh: (storage['size_kwh'] || 0), size_kw: (storage['size_kw'] || 0) })
242
247
  end
248
+ $has_storage = !storage.nil?
249
+ $has_wind = !wind.nil?
243
250
 
244
251
  generation_timeseries_kwh = Matrix[[0] * (8760 * feature_report.timesteps_per_hour)]
245
252
  reopt_resolution = reopt_output['inputs']['Settings']['time_steps_per_hour']
246
253
 
247
254
  if reopt_output['outputs'].key?('PV') && !reopt_output['outputs']['PV'].nil?
248
255
  reopt_output['outputs']['PV'].each do |pv|
249
- if (pv['size_kw'] || 0) > 0 && !pv['year_one_power_production_series_kw'].nil?
250
- generation_timeseries_kwh += Matrix[convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
256
+ next unless (pv['size_kw'] || 0) > 0
257
+
258
+ pv_production_series = pv['year_one_power_production_series_kw']
259
+ pv_production_series ||= pv['production_factor_series']&.map { |v| v * pv['size_kw'] }
260
+ if !pv_production_series.nil?
261
+ generation_timeseries_kwh += Matrix[convert_powerflow_resolution(pv_production_series, reopt_resolution, feature_report.timesteps_per_hour)]
251
262
  end
252
263
  end
253
264
  end
254
265
 
255
- if reopt_output['outputs'].key?('Wind') && !reopt_output['outputs']['Wind'].nil? && ((reopt_output['outputs']['Wind']['size_kw'] || 0) > 0) && !reopt_output['outputs']['Wind']['year_one_power_production_series_kw'].nil?
256
- generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Wind']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
266
+ if reopt_output['outputs'].key?('Wind') && !reopt_output['outputs']['Wind'].nil? && ((reopt_output['outputs']['Wind']['size_kw'] || 0) > 0)
267
+ wind_production_series = reopt_output['outputs']['Wind']['year_one_power_production_series_kw']
268
+ wind_production_series ||= reopt_output['outputs']['Wind']['production_factor_series']&.map { |v| v * reopt_output['outputs']['Wind']['size_kw'] }
269
+ if !wind_production_series.nil?
270
+ generation_timeseries_kwh += Matrix[convert_powerflow_resolution(wind_production_series, reopt_resolution, feature_report.timesteps_per_hour)]
271
+ end
257
272
  end
258
273
 
259
- if reopt_output['outputs'].key?('Generator') && !reopt_output['outputs']['Generator'].nil? && ((reopt_output['outputs']['Generator']['size_kw'] || 0) > 0) && !reopt_output['outputs']['Generator']['year_one_power_production_series_kw'].nil?
260
- generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Generator']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
274
+ if reopt_output['outputs'].key?('Generator') && !reopt_output['outputs']['Generator'].nil? && ((reopt_output['outputs']['Generator']['size_kw'] || 0) > 0)
275
+ generator_production_series = reopt_output['outputs']['Generator']['year_one_power_production_series_kw']
276
+ if generator_production_series.nil?
277
+ eto_load = reopt_output['outputs']['Generator']['electric_to_load_series_kw']
278
+ eto_storage = reopt_output['outputs']['Generator']['electric_to_storage_series_kw']
279
+ eto_grid = reopt_output['outputs']['Generator']['electric_to_grid_series_kw']
280
+ generator_production_series = eto_load.zip(eto_storage, eto_grid).map { |vals| vals.compact.sum } if eto_load && eto_storage && eto_grid
281
+ end
282
+ if !generator_production_series.nil?
283
+ generation_timeseries_kwh += Matrix[convert_powerflow_resolution(generator_production_series, reopt_resolution, feature_report.timesteps_per_hour)]
284
+ end
261
285
  end
262
286
 
263
287
  $generation_timeseries_kwh = generation_timeseries_kwh.to_a[0] || [0] * (8760 * feature_report.timesteps_per_hour)
@@ -312,7 +336,9 @@ module URBANopt # :nodoc:
312
336
  end
313
337
 
314
338
  if !generator.nil?
315
- # $generator_total = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
339
+ generator_production_series = reopt_output['outputs']['Generator']['year_one_power_production_series_kw']
340
+ generator_production_series ||= reopt_output['outputs']['Generator']['electric_to_storage_series_kw']&.zip(reopt_output['outputs']['Generator']['electric_to_load_series_kw'], reopt_output['outputs']['Generator']['electric_to_grid_series_kw'])&.map { |vals| vals.compact.sum }
341
+ $generator_total = convert_powerflow_resolution(generator_production_series, reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
316
342
  $generator_total_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:Total(kw)')
317
343
  if $generator_total_col.nil?
318
344
  $generator_total_col = feature_report.timeseries_csv.column_names.length
@@ -379,7 +405,9 @@ module URBANopt # :nodoc:
379
405
 
380
406
  reopt_output['outputs']['PV'].each_with_index do |pv, i|
381
407
  if (pv['size_kw'] || 0) > 0
382
- # $pv_total += Matrix[convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)]
408
+ pv_production_series = pv['year_one_power_production_series_kw']
409
+ pv_production_series ||= pv['production_factor_series']&.map { |v| v * pv['size_kw'] }
410
+ $pv_total += Matrix[convert_powerflow_resolution(pv_production_series, reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)]
383
411
  if !storage.nil?
384
412
  $pv_to_battery += Matrix[convert_powerflow_resolution(pv['electric_to_storage_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)]
385
413
  end
@@ -396,7 +424,6 @@ module URBANopt # :nodoc:
396
424
  $pv_to_grid = $pv_to_grid.to_a[0]
397
425
  end
398
426
 
399
- # $wind_total = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
400
427
  $wind_total_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:Total(kw)')
401
428
  if $wind_total_col.nil?
402
429
  $wind_total_col = feature_report.timeseries_csv.column_names.length
@@ -404,6 +431,10 @@ module URBANopt # :nodoc:
404
431
  end
405
432
 
406
433
  if !wind.nil?
434
+ wind_production_series = reopt_output['outputs']['Wind']['year_one_power_production_series_kw']
435
+ wind_production_series ||= reopt_output['outputs']['Wind']['production_factor_series']&.map { |v| v * reopt_output['outputs']['Wind']['size_kw'] }
436
+ $wind_total = convert_powerflow_resolution(wind_production_series, reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
437
+
407
438
  if !storage.nil?
408
439
  $wind_to_battery = convert_powerflow_resolution(reopt_output['outputs']['Wind']['electric_to_storage_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
409
440
  $wind_to_battery_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToBattery(kw)')
@@ -432,22 +463,22 @@ module URBANopt # :nodoc:
432
463
  x[$generation_timeseries_kwh_col] = $generation_timeseries_kwh[i] || 0
433
464
  x[$load_col] = $load[i] || 0
434
465
  x[$utility_to_load_col] = $utility_to_load[i] || 0
435
- x[$utility_to_battery_col] = $utility_to_battery[i] || 0 if defined?(storage)
436
- x[$storage_to_load_col] = $storage_to_load[i] || 0 if defined?(storage)
437
- x[$storage_to_grid_col] = $storage_to_grid[i] || 0 if defined?(storage)
438
- x[$storage_soc_col] = $storage_soc[i] || 0 if defined?(storage)
439
- x[$generator_total_col] = $generator_total[i] || 0 if defined?(generator)
440
- x[$generator_to_battery_col] = $generator_to_battery[i] || 0 if defined?(generator) && defined?(storage)
441
- x[$generator_to_load_col] = $generator_to_load[i] || 0 if defined?(generator)
442
- x[$generator_to_grid_col] = $generator_to_grid[i] || 0 if defined?(generator)
466
+ x[$utility_to_battery_col] = $utility_to_battery[i] || 0 if $has_storage
467
+ x[$storage_to_load_col] = $storage_to_load[i] || 0 if $has_storage
468
+ x[$storage_to_grid_col] = $storage_to_grid[i] || 0 if $has_storage
469
+ x[$storage_soc_col] = $storage_soc[i] || 0 if $has_storage
470
+ x[$generator_total_col] = $generator_total[i] || 0 if $has_generator
471
+ x[$generator_to_battery_col] = $generator_to_battery[i] || 0 if $has_generator && $has_storage
472
+ x[$generator_to_load_col] = $generator_to_load[i] || 0 if $has_generator
473
+ x[$generator_to_grid_col] = $generator_to_grid[i] || 0 if $has_generator
443
474
  x[$pv_total_col] = $pv_total[i] || 0
444
- x[$pv_to_battery_col] = $pv_to_battery[i] || 0 if defined?(storage)
475
+ x[$pv_to_battery_col] = $pv_to_battery[i] || 0 if $has_storage
445
476
  x[$pv_to_load_col] = $pv_to_load[i] || 0
446
477
  x[$pv_to_grid_col] = $pv_to_grid[i] || 0
447
- x[$wind_total_col] = $wind_total[i] || 0 if defined?(wind)
448
- x[$wind_to_battery_col] = $wind_to_battery[i] || 0 if defined?(wind) && defined?(storage)
449
- x[$wind_to_load_col] = $wind_to_load[i] || 0 if defined?(wind)
450
- x[$wind_to_grid_col] = $wind_to_grid[i] || 0 if defined?(wind)
478
+ x[$wind_total_col] = $wind_total[i] || 0 if $has_wind
479
+ x[$wind_to_battery_col] = $wind_to_battery[i] || 0 if $has_wind && $has_storage
480
+ x[$wind_to_load_col] = $wind_to_load[i] || 0 if $has_wind
481
+ x[$wind_to_grid_col] = $wind_to_grid[i] || 0 if $has_wind
451
482
  return x
452
483
  end
453
484
 
@@ -261,7 +261,7 @@ module URBANopt # :nodoc:
261
261
 
262
262
  end
263
263
 
264
- #save output report in reopt_ghp directory
264
+ # save output report in reopt_ghp directory
265
265
  reopt_ghp_dir = File.join(run_dir, "reopt_ghp", "reopt_ghp_inputs")
266
266
  json_file_path = File.join(reopt_ghp_dir, "GHP_building_#{building_id}.json")
267
267
  pretty_json = JSON.pretty_generate(reopt_inputs_building)
@@ -333,38 +333,36 @@ module URBANopt # :nodoc:
333
333
 
334
334
 
335
335
  # Read GHX sizes from system parameter hash
336
- ghe_specific_params = system_parameter_hash[:district_system][:fifth_generation][:ghe_parameters][:borefields]
337
-
338
- ghe_specific_params.each do |ghe|
339
- if ghe[:ghe_id] == ghp_id
340
- unless ghe[:pre_designed_borefield]
341
- if ghe[:autosized_rectangle_borefield]
342
- borefield = ghe[:autosized_rectangle_borefield]
343
-
344
- elsif ghe[:autosized_rectangle_constrained_borefield]
345
- borefield = ghe[:autosized_rectangle_constrained_borefield]
336
+ ghe_specific_params = system_parameter_hash.dig(:district_system, :fifth_generation, :ghe_parameters, :borefields)
346
337
 
347
- elsif ghe[:autosized_birectangle_borefield]
348
- borefield = ghe[:autosized_birectangle_borefield]
338
+ # Initialize outputs; validation below will raise if borefield sizing is missing.
339
+ ghpghx_output[:outputs][:number_of_boreholes] = 0
340
+ ghpghx_output[:outputs][:length_boreholes_ft] = 0
349
341
 
350
- elsif ghe[:autosized_birectangle_constrained_borefield]
351
- borefield = ghe[:autosized_birectangle_constrained_borefield]
352
-
353
- elsif ghe[:autosized_bizoned_rectangle_borefield]
354
- borefield = ghe[:autosized_bizoned_rectangle_borefield]
355
-
356
- elsif ghe[:autosized_near_square_borefield]
357
- borefield = ghe[:autosized_near_square_borefield]
342
+ if ghe_specific_params.nil? || ghe_specific_params.empty?
343
+ raise 'No borefields found at district_system.fifth_generation.ghe_parameters.borefields in the system parameters file. Run `uo ghe_size` to size your GHE before running this workflow.'
344
+ else
345
+ ghe = ghe_specific_params.find { |candidate| candidate[:ghe_id] == ghp_id }
358
346
 
359
- elsif ghe[:autosized_rowwise_borefield]
360
- borefield = ghe[:autosized_rowwise_borefield]
361
- end
347
+ if ghe.nil?
348
+ raise "No borefield found with ghe_id '#{ghp_id}' in the system parameters file. Make sure your ghe_id matches one of the sized GHE entries from the uo ghe_size command"
349
+ else
350
+ borefield = ghe[:pre_designed_borefield] ||
351
+ ghe[:autosized_rectangle_borefield] ||
352
+ ghe[:autosized_rectangle_constrained_borefield] ||
353
+ ghe[:autosized_birectangle_borefield] ||
354
+ ghe[:autosized_birectangle_constrained_borefield] ||
355
+ ghe[:autosized_bizoned_rectangle_borefield] ||
356
+ ghe[:autosized_near_square_borefield] ||
357
+ ghe[:autosized_rowwise_borefield]
358
+
359
+ if borefield.nil?
360
+ raise "No borefield sizing found for ghe_id '#{ghp_id}'. Expected one of: pre_designed_borefield, autosized_rectangle_borefield, autosized_rectangle_constrained_borefield, autosized_birectangle_borefield, autosized_birectangle_constrained_borefield, autosized_bizoned_rectangle_borefield, autosized_near_square_borefield, autosized_rowwise_borefield. Run `uo ghe_size` or provide a pre_designed_borefield."
361
+ else
362
+ ghpghx_output[:outputs][:number_of_boreholes] = borefield[:number_of_boreholes].to_i
363
+ # convert meters to feet by multiplying with 3.28084
364
+ ghpghx_output[:outputs][:length_boreholes_ft] = borefield[:borehole_length].to_f * 3.28084
362
365
  end
363
-
364
- ghpghx_output[:outputs][:number_of_boreholes] = borefield[:number_of_boreholes]
365
- # convert meters to feet by multiplying with 3.28084
366
- ghpghx_output[:outputs][:length_boreholes_ft] = (borefield[:borehole_length])*3.28084
367
-
368
366
  end
369
367
  end
370
368
 
@@ -53,7 +53,7 @@ module URBANopt # :nodoc:
53
53
  reopt_output_file = @reopt_output_file
54
54
 
55
55
  if run_id.nil?
56
- run_id = get_run_uuid(reopt_input_file, api_key, reopt_output_file)
56
+ run_id = get_run_uuid
57
57
  end
58
58
  if !run_id.nil?
59
59
  results_url = @url_config.url_for('job', run_uuid: run_id)
@@ -71,13 +71,8 @@ module URBANopt # :nodoc:
71
71
  results
72
72
  end
73
73
 
74
- def get_run_uuid(reopt_input_file, api_key, root_url)
75
-
76
- reopt_input_file = @reopt_input_file
77
- api_key = @api_key
78
- root_url = @root_url
74
+ def get_run_uuid
79
75
  post_url = @url_config.url_for('job')
80
- puts "This is URL: #{post_url}"
81
76
  @@logger.info("Connecting to #{post_url}")
82
77
 
83
78
  # Parse the URL and prepare the HTTP request
@@ -86,7 +81,7 @@ module URBANopt # :nodoc:
86
81
  request.content_type = 'application/json'
87
82
 
88
83
  # Add the JSON payload (assuming 'post' is the body data)
89
- request.body = reopt_input_file.to_json
84
+ request.body = @reopt_input_file.to_json
90
85
 
91
86
  # Send the HTTP request
92
87
  response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
@@ -272,6 +272,10 @@ module URBANopt # :nodoc:
272
272
  end
273
273
  end
274
274
 
275
+ wind = nil
276
+ generator = nil
277
+ storage = nil
278
+
275
279
  if reopt_output['outputs'].key?('Wind')
276
280
  wind = reopt_output['outputs']['Wind']
277
281
  # find size_class
@@ -284,29 +288,49 @@ module URBANopt # :nodoc:
284
288
  generator = reopt_output['outputs']['Generator']
285
289
  scenario_report.distributed_generation.add_tech 'generator', URBANopt::Reporting::DefaultReports::Generator.new({ size_kw: (generator['size_kw'] || 0) })
286
290
  end
291
+ $has_generator = !generator.nil?
287
292
 
288
293
  if reopt_output['outputs'].key?('ElectricStorage')
289
294
  storage = reopt_output['outputs']['ElectricStorage']
290
295
  scenario_report.distributed_generation.add_tech 'storage', URBANopt::Reporting::DefaultReports::Storage.new({ size_kwh: (storage['size_kwh'] || 0), size_kw: (storage['size_kw'] || 0) })
291
296
  end
297
+ $has_storage = !storage.nil?
298
+ $has_wind = !wind.nil?
292
299
 
293
300
  reopt_resolution = reopt_output['inputs']['Settings']['time_steps_per_hour']
294
301
  generation_timeseries_kwh = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
295
302
 
296
303
  if reopt_output['outputs'].key?('PV') && !reopt_output['outputs']['PV'].nil?
297
304
  reopt_output['outputs']['PV'].each do |pv|
298
- if (pv['size_kw'] || 0) > 0 && !pv['year_one_power_production_series_kw'].nil?
299
- generation_timeseries_kwh += Matrix[convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)]
305
+ next unless (pv['size_kw'] || 0) > 0
306
+
307
+ pv_production_series = pv['year_one_power_production_series_kw']
308
+ pv_production_series ||= pv['production_factor_series']&.map { |v| v * pv['size_kw'] }
309
+ if !pv_production_series.nil?
310
+ generation_timeseries_kwh += Matrix[convert_powerflow_resolution(pv_production_series, reopt_resolution, scenario_report.timesteps_per_hour)]
300
311
  end
301
312
  end
302
313
  end
303
314
 
304
- if reopt_output['outputs'].key?('Wind') && !reopt_output['outputs']['Wind'].nil? && ((reopt_output['outputs']['Wind']['size_kw'] || 0) > 0) && !reopt_output['outputs']['Wind']['year_one_power_production_series_kw'].nil?
305
- generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Wind']['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)]
315
+ if reopt_output['outputs'].key?('Wind') && !reopt_output['outputs']['Wind'].nil? && ((reopt_output['outputs']['Wind']['size_kw'] || 0) > 0)
316
+ wind_production_series = reopt_output['outputs']['Wind']['year_one_power_production_series_kw']
317
+ wind_production_series ||= reopt_output['outputs']['Wind']['production_factor_series']&.map { |v| v * reopt_output['outputs']['Wind']['size_kw'] }
318
+ if !wind_production_series.nil?
319
+ generation_timeseries_kwh += Matrix[convert_powerflow_resolution(wind_production_series, reopt_resolution, scenario_report.timesteps_per_hour)]
320
+ end
306
321
  end
307
322
 
308
- if reopt_output['outputs'].key?('Generator') && !reopt_output['outputs']['Generator'].nil? && ((reopt_output['outputs']['Generator']['size_kw'] || 0) > 0) && !reopt_output['outputs']['Generator']['year_one_power_production_series_kw'].nil?
309
- generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Generator']['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)]
323
+ if reopt_output['outputs'].key?('Generator') && !reopt_output['outputs']['Generator'].nil? && ((reopt_output['outputs']['Generator']['size_kw'] || 0) > 0)
324
+ generator_production_series = reopt_output['outputs']['Generator']['year_one_power_production_series_kw']
325
+ if generator_production_series.nil?
326
+ eto_load = reopt_output['outputs']['Generator']['electric_to_load_series_kw']
327
+ eto_storage = reopt_output['outputs']['Generator']['electric_to_storage_series_kw']
328
+ eto_grid = reopt_output['outputs']['Generator']['electric_to_grid_series_kw']
329
+ generator_production_series = eto_load.zip(eto_storage, eto_grid).map { |vals| vals.compact.sum } if eto_load && eto_storage && eto_grid
330
+ end
331
+ if !generator_production_series.nil?
332
+ generation_timeseries_kwh += Matrix[convert_powerflow_resolution(generator_production_series, reopt_resolution, scenario_report.timesteps_per_hour)]
333
+ end
310
334
  end
311
335
 
312
336
  $generation_timeseries_kwh = generation_timeseries_kwh.to_a[0] || [0] * (8760 * scenario_report.timesteps_per_hour)
@@ -316,7 +340,8 @@ module URBANopt # :nodoc:
316
340
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Total(kw)')
317
341
  end
318
342
 
319
- $load = convert_powerflow_resolution(reopt_output['outputs']['ElectricLoad']['year_one_electric_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
343
+ electric_load_series = reopt_output['outputs']['ElectricLoad']['year_one_electric_load_series_kw'] || reopt_output['outputs']['ElectricLoad']['load_series_kw']
344
+ $load = convert_powerflow_resolution(electric_load_series, reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
320
345
  $load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Load:Total(kw)')
321
346
  if $load_col.nil?
322
347
  $load_col = scenario_report.timeseries_csv.column_names.length
@@ -361,7 +386,9 @@ module URBANopt # :nodoc:
361
386
  end
362
387
 
363
388
  if !generator.nil?
364
- # $generator_total = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
389
+ generator_production_series = reopt_output['outputs']['Generator']['year_one_power_production_series_kw']
390
+ generator_production_series ||= reopt_output['outputs']['Generator']['electric_to_load_series_kw']&.zip(reopt_output['outputs']['Generator']['electric_to_storage_series_kw'], reopt_output['outputs']['Generator']['electric_to_grid_series_kw'])&.map { |vals| vals.compact.sum }
391
+ $generator_total = convert_powerflow_resolution(generator_production_series, reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
365
392
  $generator_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:Total(kw)')
366
393
  if $generator_total_col.nil?
367
394
  $generator_total_col = scenario_report.timeseries_csv.column_names.length
@@ -428,7 +455,9 @@ module URBANopt # :nodoc:
428
455
 
429
456
  reopt_output['outputs']['PV'].each_with_index do |pv, i|
430
457
  if (pv['size_kw'] || 0) > 0
431
- # $pv_total += Matrix[convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)]
458
+ pv_production_series = pv['year_one_power_production_series_kw']
459
+ pv_production_series ||= pv['production_factor_series']&.map { |v| v * pv['size_kw'] }
460
+ $pv_total += Matrix[convert_powerflow_resolution(pv_production_series, reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)]
432
461
  if !storage.nil?
433
462
  $pv_to_battery += Matrix[convert_powerflow_resolution(pv['electric_to_storage_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)]
434
463
  end
@@ -446,7 +475,9 @@ module URBANopt # :nodoc:
446
475
  end
447
476
 
448
477
  if !wind.nil?
449
- # $wind_total = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
478
+ wind_production_series = reopt_output['outputs']['Wind']['year_one_power_production_series_kw']
479
+ wind_production_series ||= reopt_output['outputs']['Wind']['production_factor_series']&.map { |v| v * reopt_output['outputs']['Wind']['size_kw'] }
480
+ $wind_total = convert_powerflow_resolution(wind_production_series, reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
450
481
  $wind_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:Total(kw)')
451
482
  if $wind_total_col.nil?
452
483
  $wind_total_col = scenario_report.timeseries_csv.column_names.length
@@ -481,22 +512,22 @@ module URBANopt # :nodoc:
481
512
  data[$generation_timeseries_kwh_col] = $generation_timeseries_kwh[idx] || 0
482
513
  data[$load_col] = $load[idx] || 0
483
514
  data[$utility_to_load_col] = $utility_to_load[idx] || 0
484
- data[$utility_to_battery_col] = $utility_to_battery[idx] || 0 if defined?(storage)
485
- data[$storage_to_load_col] = $storage_to_load[idx] || 0 if defined?(storage)
486
- data[$storage_to_grid_col] = $storage_to_grid[idx] || 0 if defined?(storage)
487
- data[$storage_soc_col] = $storage_soc[idx] || 0 if defined?(storage)
488
- data[$generator_total_col] = $generator_total[idx] || 0 if defined?(generator)
489
- data[$generator_to_battery_col] = $generator_to_battery[idx] || 0 if defined?(generator) && defined?(storage)
490
- data[$generator_to_load_col] = $generator_to_load[idx] || 0 if defined?(generator)
491
- data[$generator_to_grid_col] = $generator_to_grid[idx] || 0 if defined?(generator)
515
+ data[$utility_to_battery_col] = $utility_to_battery[idx] || 0 if $has_storage
516
+ data[$storage_to_load_col] = $storage_to_load[idx] || 0 if $has_storage
517
+ data[$storage_to_grid_col] = $storage_to_grid[idx] || 0 if $has_storage
518
+ data[$storage_soc_col] = $storage_soc[idx] || 0 if $has_storage
519
+ data[$generator_total_col] = $generator_total[idx] || 0 if $has_generator
520
+ data[$generator_to_battery_col] = $generator_to_battery[idx] || 0 if $has_generator && $has_storage
521
+ data[$generator_to_load_col] = $generator_to_load[idx] || 0 if $has_generator
522
+ data[$generator_to_grid_col] = $generator_to_grid[idx] || 0 if $has_generator
492
523
  data[$pv_total_col] = $pv_total[idx] || 0
493
- data[$pv_to_battery_col] = $pv_to_battery[idx] || 0 if defined?(storage)
524
+ data[$pv_to_battery_col] = $pv_to_battery[idx] || 0 if $has_storage
494
525
  data[$pv_to_load_col] = $pv_to_load[idx] || 0
495
526
  data[$pv_to_grid_col] = $pv_to_grid[idx] || 0
496
- data[$wind_total_col] = $wind_total[idx] || 0 if defined?(wind)
497
- data[$wind_to_battery_col] = $wind_to_battery[idx] || 0 if defined?(wind) && defined?(storage)
498
- data[$wind_to_load_col] = $wind_to_load[idx] || 0 if defined?(wind)
499
- data[$wind_to_grid_col] = $wind_to_grid[idx] || 0 if defined?(wind)
527
+ data[$wind_total_col] = $wind_total[idx] || 0 if $has_wind
528
+ data[$wind_to_battery_col] = $wind_to_battery[idx] || 0 if $has_wind && $has_storage
529
+ data[$wind_to_load_col] = $wind_to_load[idx] || 0 if $has_wind
530
+ data[$wind_to_grid_col] = $wind_to_grid[idx] || 0 if $has_wind
500
531
  return data
501
532
  end
502
533
 
@@ -5,6 +5,6 @@
5
5
 
6
6
  module URBANopt # :nodoc:
7
7
  module REopt # :nodoc:
8
- VERSION = '1.3.0'.freeze
8
+ VERSION = '1.3.1'.freeze
9
9
  end
10
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: urbanopt-reopt
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-06-08 00:00:00.000000000 Z
11
+ date: 2026-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: openstudio-extension