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.
- checksums.yaml +4 -4
- data/.github/workflows/nightly_ci_build.yml +1 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +1 -1
- data/RDOC_MAIN.md +6 -6
- data/README.md +6 -6
- data/docs/README.md +6 -6
- data/docs/schemas/reopt-input-schema.md +25 -23
- data/docs/schemas/reopt-output-schema.md +7 -7
- data/index.md +9 -9
- data/lib/urbanopt/reopt/feature_report_adapter.rb +229 -196
- data/lib/urbanopt/reopt/reopt_lite_api.rb +76 -37
- data/lib/urbanopt/reopt/reopt_post_processor.rb +11 -10
- data/lib/urbanopt/reopt/reopt_schema/reopt_input_schema.json +1125 -1105
- data/lib/urbanopt/reopt/reopt_schema/reopt_output_schema.json +448 -523
- data/lib/urbanopt/reopt/scenario_report_adapter.rb +260 -225
- data/lib/urbanopt/reopt/version.rb +1 -1
- data/urbanopt-reopt.gemspec +1 -1
- metadata +4 -4
@@ -38,11 +38,20 @@ module URBANopt # :nodoc:
|
|
38
38
|
description = "scenario_report_#{name}_#{scenario_id}"
|
39
39
|
|
40
40
|
# Create base REpopt post
|
41
|
-
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 } } } }
|
42
41
|
if !reopt_assumptions_json.nil?
|
43
42
|
reopt_inputs = reopt_assumptions_json
|
44
43
|
else
|
45
44
|
@@logger.info('Using default REopt assumptions')
|
45
|
+
reopt_inputs = {
|
46
|
+
Settings:{},
|
47
|
+
Site: {},
|
48
|
+
Financial:{},
|
49
|
+
ElectricTariff: {
|
50
|
+
monthly_demand_rates: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
51
|
+
monthly_energy_rates: [0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13]
|
52
|
+
},
|
53
|
+
ElectricLoad: {}
|
54
|
+
}
|
46
55
|
end
|
47
56
|
|
48
57
|
# Update required info
|
@@ -76,26 +85,26 @@ module URBANopt # :nodoc:
|
|
76
85
|
end
|
77
86
|
end
|
78
87
|
|
79
|
-
reopt_inputs[:
|
88
|
+
reopt_inputs[:description] = description
|
80
89
|
|
81
|
-
reopt_inputs[:
|
82
|
-
reopt_inputs[:
|
90
|
+
reopt_inputs[:Site][:latitude] = scenario_report.location.latitude_deg
|
91
|
+
reopt_inputs[:Site][:longitude] = scenario_report.location.longitude_deg
|
83
92
|
|
84
93
|
# Update optional info
|
85
94
|
# REK: attribute names should be updated
|
86
|
-
if reopt_inputs[:
|
87
|
-
reopt_inputs[:
|
95
|
+
if reopt_inputs[:Site][:roof_squarefeet].nil? && !scenario_report.program.roof_area_sqft.nil?
|
96
|
+
reopt_inputs[:Site][:roof_squarefeet] = scenario_report.program.roof_area_sqft[:available_roof_area_sqft]
|
88
97
|
end
|
89
98
|
|
90
99
|
begin
|
91
|
-
if reopt_inputs[:
|
92
|
-
reopt_inputs[:
|
100
|
+
if reopt_inputs[:Site][:land_acres].nil? && !community_photovoltaic[0][:properties][:footprint_area].nil?
|
101
|
+
reopt_inputs[:Site][:land_acres] = community_photovoltaic[0][:properties][:footprint_area] * 1.0 / 43560 # acres/sqft
|
93
102
|
end
|
94
103
|
rescue StandardError
|
95
104
|
end
|
96
105
|
|
97
|
-
if reopt_inputs[:
|
98
|
-
reopt_inputs[:
|
106
|
+
if reopt_inputs[:Settings][:time_steps_per_hour].nil?
|
107
|
+
reopt_inputs[:Settings][:time_steps_per_hour] = 1
|
99
108
|
end
|
100
109
|
|
101
110
|
# Update load profile info
|
@@ -120,25 +129,27 @@ module URBANopt # :nodoc:
|
|
120
129
|
|
121
130
|
# Convert load to REopt Resolution
|
122
131
|
begin
|
123
|
-
reopt_inputs[:
|
132
|
+
reopt_inputs[:ElectricLoad][:loads_kw] = convert_powerflow_resolution(energy_timeseries_kw, scenario_report.timesteps_per_hour, reopt_inputs[:Settings][:time_steps_per_hour])
|
124
133
|
rescue StandardError
|
125
|
-
@@logger.error("Could not convert the annual electric load from a resolution of #{scenario_report.timesteps_per_hour} to #{reopt_inputs[:
|
126
|
-
raise "Could not convert the annual electric load from a resolution of #{scenario_report.timesteps_per_hour} to #{reopt_inputs[:
|
127
|
-
end
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
134
|
+
@@logger.error("Could not convert the annual electric load from a resolution of #{scenario_report.timesteps_per_hour} to #{reopt_inputs[:Settings][:time_steps_per_hour]}")
|
135
|
+
raise "Could not convert the annual electric load from a resolution of #{scenario_report.timesteps_per_hour} to #{reopt_inputs[:Settings][:time_steps_per_hour]}"
|
136
|
+
end
|
137
|
+
|
138
|
+
# REMOVE COINCIDENT PEAKS STUFF JUST FOR TESTING
|
139
|
+
# if reopt_inputs[:ElectricTariff][:coincident_peak_load_active_time_steps].nil?
|
140
|
+
# n_top_values = 10
|
141
|
+
# tmp1 = reopt_inputs[:ElectricLoad][:loads_kw]
|
142
|
+
# tmp2 = tmp1.each_index.max_by(n_top_values * reopt_inputs[:Settings][:time_steps_per_hour]) { |i| tmp1[i] }
|
143
|
+
# for i in (0...tmp2.count)
|
144
|
+
# tmp2[i] += 1
|
145
|
+
# end
|
146
|
+
# # this needs to be a 2D array
|
147
|
+
# reopt_inputs[:ElectricTariff][:coincident_peak_load_active_time_steps] = [tmp2]
|
148
|
+
# end
|
149
|
+
|
150
|
+
# if reopt_inputs[:ElectricTariff][:coincident_peak_load_charge_per_kw].nil?
|
151
|
+
# reopt_inputs[:ElectricTariff][:coincident_peak_load_charge_per_kw] = 0
|
152
|
+
# end
|
142
153
|
|
143
154
|
return reopt_inputs
|
144
155
|
end
|
@@ -165,29 +176,6 @@ module URBANopt # :nodoc:
|
|
165
176
|
return results
|
166
177
|
end
|
167
178
|
|
168
|
-
def modrow(data, idx) # :nodoc:
|
169
|
-
data[$generation_timeseries_kwh_col] = $generation_timeseries_kwh[idx] || 0
|
170
|
-
data[$load_col] = $load[idx] || 0
|
171
|
-
data[$utility_to_load_col] = $utility_to_load[idx] || 0
|
172
|
-
data[$utility_to_battery_col] = $utility_to_battery[idx] || 0
|
173
|
-
data[$storage_to_load_col] = $storage_to_load[idx] || 0
|
174
|
-
data[$storage_to_grid_col] = $storage_to_grid[idx] || 0
|
175
|
-
data[$storage_soc_col] = $storage_soc[idx] || 0
|
176
|
-
data[$generator_total_col] = $generator_total[idx] || 0
|
177
|
-
data[$generator_to_battery_col] = $generator_to_battery[idx] || 0
|
178
|
-
data[$generator_to_load_col] = $generator_to_load[idx] || 0
|
179
|
-
data[$generator_to_grid_col] = $generator_to_grid[idx] || 0
|
180
|
-
data[$pv_total_col] = $pv_total[idx] || 0
|
181
|
-
data[$pv_to_battery_col] = $pv_to_battery[idx] || 0
|
182
|
-
data[$pv_to_load_col] = $pv_to_load[idx] || 0
|
183
|
-
data[$pv_to_grid_col] = $pv_to_grid[idx] || 0
|
184
|
-
data[$wind_total_col] = $wind_total[idx] || 0
|
185
|
-
data[$wind_to_battery_col] = $wind_to_battery[idx] || 0
|
186
|
-
data[$wind_to_load_col] = $wind_to_load[idx] || 0
|
187
|
-
data[$wind_to_grid_col] = $wind_to_grid[idx] || 0
|
188
|
-
return data
|
189
|
-
end
|
190
|
-
|
191
179
|
##
|
192
180
|
# Updates a ScenarioReport from a \REopt response
|
193
181
|
#
|
@@ -200,29 +188,29 @@ module URBANopt # :nodoc:
|
|
200
188
|
# [*return:*] _URBANopt::Reporting::DefaultReports::ScenarioReport_ - Returns an updated ScenarioReport
|
201
189
|
##
|
202
190
|
def update_scenario_report(scenario_report, reopt_output, timeseries_csv_path = nil, resilience_stats = nil)
|
203
|
-
if reopt_output['
|
191
|
+
if reopt_output['status'] != 'optimal'
|
204
192
|
@@logger.info("Warning cannot Feature Report #{scenario_report.name} #{scenario_report.id} - REopt optimization was non-optimal")
|
205
193
|
return scenario_report
|
206
194
|
end
|
207
195
|
|
208
196
|
# Update location
|
209
|
-
scenario_report.location.latitude_deg = reopt_output['inputs']['
|
210
|
-
scenario_report.location.longitude_deg = reopt_output['inputs']['
|
197
|
+
scenario_report.location.latitude_deg = reopt_output['inputs']['Site']['latitude']
|
198
|
+
scenario_report.location.longitude_deg = reopt_output['inputs']['Site']['longitude']
|
211
199
|
|
212
200
|
# Update distributed generation sizing and financials
|
213
|
-
scenario_report.distributed_generation.
|
214
|
-
scenario_report.distributed_generation.
|
215
|
-
scenario_report.distributed_generation.
|
216
|
-
scenario_report.distributed_generation.
|
217
|
-
scenario_report.distributed_generation.
|
218
|
-
scenario_report.distributed_generation.
|
219
|
-
scenario_report.distributed_generation.
|
220
|
-
scenario_report.distributed_generation.
|
221
|
-
scenario_report.distributed_generation.
|
222
|
-
scenario_report.distributed_generation.
|
223
|
-
scenario_report.distributed_generation.
|
224
|
-
scenario_report.distributed_generation.
|
225
|
-
scenario_report.distributed_generation.
|
201
|
+
scenario_report.distributed_generation.renewable_electricity_fraction = reopt_output['outputs']['Site']['renewable_electricity_fraction'] || 0
|
202
|
+
scenario_report.distributed_generation.lcc = reopt_output['outputs']['Financial']['lcc'] || 0
|
203
|
+
scenario_report.distributed_generation.npv = reopt_output['outputs']['Financial']['npv'] || 0
|
204
|
+
scenario_report.distributed_generation.year_one_energy_cost_before_tax = reopt_output['outputs']['ElectricTariff']['year_one_energy_cost_before_tax'] || 0
|
205
|
+
scenario_report.distributed_generation.year_one_demand_cost_before_tax = reopt_output['outputs']['ElectricTariff']['year_one_demand_cost_before_tax'] || 0
|
206
|
+
scenario_report.distributed_generation.year_one_bill_before_tax = reopt_output['outputs']['ElectricTariff']['year_one_bill_before_tax'] || 0
|
207
|
+
scenario_report.distributed_generation.lifecycle_energy_cost_after_tax = reopt_output['outputs']['ElectricTariff']['lifecycle_energy_cost_after_tax'] || 0
|
208
|
+
scenario_report.distributed_generation.lifecycle_demand_cost_after_tax = reopt_output['outputs']['ElectricTariff']['lifecycle_demand_cost_after_tax'] || 0
|
209
|
+
scenario_report.distributed_generation.year_one_energy_cost_before_tax_bau = reopt_output['outputs']['ElectricTariff']['year_one_energy_cost_before_tax_bau'] || 0
|
210
|
+
scenario_report.distributed_generation.year_one_demand_cost_before_tax_bau = reopt_output['outputs']['ElectricTariff']['year_one_demand_cost_before_tax_bau'] || 0
|
211
|
+
scenario_report.distributed_generation.year_one_bill_before_tax_bau = reopt_output['outputs']['ElectricTariff']['year_one_bill_before_tax_bau'] || 0
|
212
|
+
scenario_report.distributed_generation.lifecycle_demand_cost_after_tax_bau = reopt_output['outputs']['ElectricTariff']['lifecycle_demand_cost_after_tax_bau'] || 0
|
213
|
+
scenario_report.distributed_generation.lifecycle_energy_cost_after_tax_bau = reopt_output['outputs']['ElectricTariff']['lifecycle_energy_cost_after_tax_bau'] || 0
|
226
214
|
if !resilience_stats.nil?
|
227
215
|
scenario_report.distributed_generation.resilience_hours_min = resilience_stats['resilience_hours_min']
|
228
216
|
scenario_report.distributed_generation.resilience_hours_max = resilience_stats['resilience_hours_max']
|
@@ -232,10 +220,10 @@ module URBANopt # :nodoc:
|
|
232
220
|
scenario_report.distributed_generation.probs_of_surviving_by_hour_of_the_day = resilience_stats['probs_of_surviving_by_hour_of_the_day']
|
233
221
|
end
|
234
222
|
|
235
|
-
if reopt_output['outputs']['
|
236
|
-
reopt_output['outputs']['
|
237
|
-
elsif reopt_output['outputs']['
|
238
|
-
reopt_output['outputs']['
|
223
|
+
if reopt_output['outputs']['PV'].is_a?(Hash)
|
224
|
+
reopt_output['outputs']['PV'] = [reopt_output['outputs']['PV']]
|
225
|
+
elsif reopt_output['outputs']['PV'].nil?
|
226
|
+
reopt_output['outputs']['PV'] = []
|
239
227
|
end
|
240
228
|
|
241
229
|
# Store the PV name and location in a hash
|
@@ -245,81 +233,85 @@ module URBANopt # :nodoc:
|
|
245
233
|
module_type = {}
|
246
234
|
gcr = {}
|
247
235
|
# Check whether multi PV assumption input file is used or single PV
|
248
|
-
if reopt_output['inputs']
|
249
|
-
reopt_output['inputs']['
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
else
|
257
|
-
location[reopt_output['inputs']['Scenario']['Site']['PV']['pv_name']] = reopt_output['inputs']['Scenario']['Site']['PV']['location']
|
258
|
-
azimuth[reopt_output['inputs']['Scenario']['Site']['PV']['pv_name']] = reopt_output['inputs']['Scenario']['Site']['PV']['azimuth']
|
259
|
-
tilt[reopt_output['inputs']['Scenario']['Site']['PV']['pv_name']] = reopt_output['inputs']['Scenario']['Site']['PV']['tilt']
|
260
|
-
module_type[reopt_output['inputs']['Scenario']['Site']['PV']['pv_name']] = reopt_output['inputs']['Scenario']['Site']['PV']['module_type']
|
261
|
-
gcr[reopt_output['inputs']['Scenario']['Site']['PV']['pv_name']] = reopt_output['inputs']['Scenario']['Site']['PV']['gcr']
|
262
|
-
end
|
263
|
-
pv_inputs = reopt_output['inputs']['Scenario']['Site']['PV']
|
264
|
-
if pv_inputs.is_a?(Hash)
|
265
|
-
pv_inputs = [pv_inputs]
|
266
|
-
end
|
267
|
-
pv_outputs = reopt_output['outputs']['Scenario']['Site']['PV']
|
268
|
-
if pv_outputs.is_a?(Hash)
|
269
|
-
pv_outputs = [pv_outputs]
|
270
|
-
end
|
271
|
-
pv_outputs.each_with_index do |pv, i|
|
272
|
-
if pv_inputs[i]
|
273
|
-
if pv_inputs[i]['tilt']
|
274
|
-
tilt[pv['pv_name']] = pv_inputs[i]['tilt']
|
275
|
-
end
|
276
|
-
if pv_inputs[i]['azimuth']
|
277
|
-
azimuth[pv['pv_name']] = pv_inputs[i]['azimuth']
|
236
|
+
if reopt_output['inputs'].key?('PV')
|
237
|
+
if reopt_output['inputs']['PV'].is_a?(Array)
|
238
|
+
reopt_output['inputs']['PV'].each do |pv|
|
239
|
+
location[pv['name']] = pv['location']
|
240
|
+
azimuth[pv['name']] = pv['azimuth']
|
241
|
+
tilt[pv['name']] = pv['tilt']
|
242
|
+
module_type[pv['name']] = pv['module_type']
|
243
|
+
gcr[pv['name']] = pv['gcr']
|
278
244
|
end
|
279
|
-
|
280
|
-
|
245
|
+
else
|
246
|
+
location[reopt_output['inputs']['PV']['name']] = reopt_output['inputs']['PV']['location']
|
247
|
+
azimuth[reopt_output['inputs']['PV']['name']] = reopt_output['inputs']['PV']['azimuth']
|
248
|
+
tilt[reopt_output['inputs']['PV']['name']] = reopt_output['inputs']['PV']['tilt']
|
249
|
+
module_type[reopt_output['inputs']['PV']['name']] = reopt_output['inputs']['PV']['module_type']
|
250
|
+
gcr[reopt_output['inputs']['PV']['name']] = reopt_output['inputs']['PV']['gcr']
|
251
|
+
end
|
252
|
+
pv_inputs = reopt_output['inputs']['PV']
|
253
|
+
if pv_inputs.is_a?(Hash)
|
254
|
+
pv_inputs = [pv_inputs]
|
255
|
+
end
|
256
|
+
pv_outputs = reopt_output['outputs']['PV']
|
257
|
+
if pv_outputs.is_a?(Hash)
|
258
|
+
pv_outputs = [pv_outputs]
|
259
|
+
end
|
260
|
+
pv_outputs.each_with_index do |pv, i|
|
261
|
+
if pv_inputs[i]
|
262
|
+
if pv_inputs[i]['tilt']
|
263
|
+
tilt[pv['name']] = pv_inputs[i]['tilt']
|
264
|
+
end
|
265
|
+
if pv_inputs[i]['azimuth']
|
266
|
+
azimuth[pv['name']] = pv_inputs[i]['azimuth']
|
267
|
+
end
|
268
|
+
if pv_inputs[i]['module_type']
|
269
|
+
module_type[pv['name']] = pv_inputs[i]['module_type']
|
270
|
+
end
|
281
271
|
end
|
272
|
+
scenario_report.distributed_generation.add_tech 'solar_pv', URBANopt::Reporting::DefaultReports::SolarPV.new({ size_kw: (pv['size_kw'] || 0), id: i, location: location[pv['name']], average_yearly_energy_produced_kwh: pv['average_yearly_energy_produced_kwh'], azimuth: azimuth[pv['name']], tilt: tilt[pv['name']], module_type: module_type[pv['name']], gcr: gcr[pv['name']] })
|
282
273
|
end
|
283
|
-
scenario_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']], average_yearly_energy_produced_kwh: pv['average_yearly_energy_produced_kwh'], azimuth: azimuth[pv['pv_name']], tilt: tilt[pv['pv_name']], module_type: module_type[pv['pv_name']], gcr: gcr[pv['pv_name']] })
|
284
274
|
end
|
285
275
|
|
286
|
-
|
287
|
-
|
276
|
+
if reopt_output['outputs'].key?('Wind')
|
277
|
+
wind = reopt_output['outputs']['Wind']
|
288
278
|
# find size_class
|
289
279
|
size_class = nil
|
290
|
-
if reopt_output['inputs']['
|
291
|
-
size_class = reopt_output['inputs']['
|
280
|
+
if reopt_output['inputs']['Wind']['size_class']
|
281
|
+
size_class = reopt_output['inputs']['Wind']['size_class']
|
292
282
|
else
|
293
283
|
size_class = 'commercial' # default
|
294
284
|
end
|
295
285
|
scenario_report.distributed_generation.add_tech 'wind', URBANopt::Reporting::DefaultReports::Wind.new({ size_kw: (wind['size_kw'] || 0), size_class: size_class, average_yearly_energy_produced_kwh: (wind['average_yearly_energy_produced_kwh'] || 0) })
|
296
286
|
end
|
297
287
|
|
298
|
-
|
299
|
-
|
288
|
+
if reopt_output['outputs'].key?('Generator')
|
289
|
+
generator = reopt_output['outputs']['Generator']
|
300
290
|
scenario_report.distributed_generation.add_tech 'generator', URBANopt::Reporting::DefaultReports::Generator.new({ size_kw: (generator['size_kw'] || 0) })
|
301
291
|
end
|
302
292
|
|
303
|
-
|
304
|
-
|
293
|
+
if reopt_output['outputs'].key?('ElectricStorage')
|
294
|
+
storage = reopt_output['outputs']['ElectricStorage']
|
305
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) })
|
306
296
|
end
|
307
297
|
|
308
|
-
reopt_resolution = reopt_output['inputs']['
|
298
|
+
reopt_resolution = reopt_output['inputs']['Settings']['time_steps_per_hour']
|
309
299
|
generation_timeseries_kwh = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
|
310
300
|
|
311
|
-
reopt_output['outputs']
|
312
|
-
|
313
|
-
|
301
|
+
if reopt_output['outputs'].key?('PV') && !reopt_output['outputs']['PV'].nil?
|
302
|
+
reopt_output['outputs']['PV'].each do |pv|
|
303
|
+
if (pv['size_kw'] || 0) > 0 && !pv['year_one_power_production_series_kw'].nil?
|
304
|
+
generation_timeseries_kwh += Matrix[convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)]
|
305
|
+
end
|
314
306
|
end
|
315
307
|
end
|
316
308
|
|
317
|
-
if
|
318
|
-
generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['
|
309
|
+
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?
|
310
|
+
generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Wind']['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)]
|
319
311
|
end
|
320
312
|
|
321
|
-
if
|
322
|
-
generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['
|
313
|
+
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?
|
314
|
+
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
315
|
end
|
324
316
|
|
325
317
|
$generation_timeseries_kwh = generation_timeseries_kwh.to_a[0] || [0] * (8760 * scenario_report.timesteps_per_hour)
|
@@ -329,145 +321,188 @@ module URBANopt # :nodoc:
|
|
329
321
|
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Total(kw)')
|
330
322
|
end
|
331
323
|
|
332
|
-
$load = convert_powerflow_resolution(reopt_output['outputs']['
|
324
|
+
$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)
|
333
325
|
$load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Load:Total(kw)')
|
334
326
|
if $load_col.nil?
|
335
327
|
$load_col = scenario_report.timeseries_csv.column_names.length
|
336
328
|
scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Load:Total(kw)')
|
337
329
|
end
|
338
330
|
|
339
|
-
$utility_to_load = convert_powerflow_resolution(reopt_output['outputs']['
|
331
|
+
$utility_to_load = convert_powerflow_resolution(reopt_output['outputs']['ElectricUtility']['electric_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
340
332
|
$utility_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToLoad(kw)')
|
341
333
|
if $utility_to_load_col.nil?
|
342
334
|
$utility_to_load_col = scenario_report.timeseries_csv.column_names.length
|
343
335
|
scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToLoad(kw)')
|
344
336
|
end
|
345
337
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
$utility_to_battery_col
|
350
|
-
|
351
|
-
|
338
|
+
if !storage.nil?
|
339
|
+
$utility_to_battery = convert_powerflow_resolution(reopt_output['outputs']['ElectricUtility']['electric_to_storage_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
340
|
+
$utility_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToBattery(kw)')
|
341
|
+
if $utility_to_battery_col.nil?
|
342
|
+
$utility_to_battery_col = scenario_report.timeseries_csv.column_names.length
|
343
|
+
scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToBattery(kw)')
|
344
|
+
end
|
352
345
|
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
346
|
+
$storage_to_load = convert_powerflow_resolution(reopt_output['outputs']['ElectricStorage']['storage_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
347
|
+
$storage_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToLoad(kw)')
|
348
|
+
if $storage_to_load_col.nil?
|
349
|
+
$storage_to_load_col = scenario_report.timeseries_csv.column_names.length
|
350
|
+
scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToLoad(kw)')
|
351
|
+
end
|
359
352
|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
353
|
+
$storage_to_grid = convert_powerflow_resolution(reopt_output['outputs']['ElectricStorage']['electric_to_grid_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
354
|
+
$storage_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToGrid(kw)')
|
355
|
+
if $storage_to_grid_col.nil?
|
356
|
+
$storage_to_grid_col = scenario_report.timeseries_csv.column_names.length
|
357
|
+
scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToGrid(kw)')
|
358
|
+
end
|
366
359
|
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
360
|
+
$storage_soc = convert_powerflow_resolution(reopt_output['outputs']['ElectricStorage']['soc_series_fraction'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
361
|
+
$storage_soc_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:StateOfCharge(pct)')
|
362
|
+
if $storage_soc_col.nil?
|
363
|
+
$storage_soc_col = scenario_report.timeseries_csv.column_names.length
|
364
|
+
scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:StateOfCharge(pct)')
|
365
|
+
end
|
372
366
|
end
|
373
367
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
$generator_total_col
|
378
|
-
|
379
|
-
|
368
|
+
if !generator.nil?
|
369
|
+
# $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)
|
370
|
+
$generator_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:Total(kw)')
|
371
|
+
if $generator_total_col.nil?
|
372
|
+
$generator_total_col = scenario_report.timeseries_csv.column_names.length
|
373
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:Total(kw)')
|
374
|
+
end
|
380
375
|
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
376
|
+
if !storage.nil?
|
377
|
+
$generator_to_battery = convert_powerflow_resolution(reopt_output['outputs']['Generator']['electric_to_storage_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
378
|
+
$generator_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToBattery(kw)')
|
379
|
+
if $generator_to_battery_col.nil?
|
380
|
+
$generator_to_battery_col = scenario_report.timeseries_csv.column_names.length
|
381
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToBattery(kw)')
|
382
|
+
end
|
383
|
+
end
|
387
384
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
385
|
+
$generator_to_load = convert_powerflow_resolution(reopt_output['outputs']['Generator']['electric_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
386
|
+
$generator_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToLoad(kw)')
|
387
|
+
if $generator_to_load_col.nil?
|
388
|
+
$generator_to_load_col = scenario_report.timeseries_csv.column_names.length
|
389
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToLoad(kw)')
|
390
|
+
end
|
394
391
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
392
|
+
$generator_to_grid = convert_powerflow_resolution(reopt_output['outputs']['Generator']['electric_to_grid_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
393
|
+
$generator_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToGrid(kw)')
|
394
|
+
if $generator_to_grid_col.nil?
|
395
|
+
$generator_to_grid_col = scenario_report.timeseries_csv.column_names.length
|
396
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToGrid(kw)')
|
397
|
+
end
|
400
398
|
end
|
401
399
|
|
402
|
-
|
403
|
-
|
404
|
-
$pv_total_col
|
405
|
-
|
406
|
-
|
400
|
+
if reopt_output['outputs'].key?('PV') && !reopt_output['outputs']['PV'].nil?
|
401
|
+
$pv_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:Total(kw)')
|
402
|
+
if $pv_total_col.nil?
|
403
|
+
$pv_total_col = scenario_report.timeseries_csv.column_names.length
|
404
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:Total(kw)')
|
405
|
+
end
|
407
406
|
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
407
|
+
if !storage.nil?
|
408
|
+
$pv_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToBattery(kw)')
|
409
|
+
if $pv_to_battery_col.nil?
|
410
|
+
$pv_to_battery_col = scenario_report.timeseries_csv.column_names.length
|
411
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToBattery(kw)')
|
412
|
+
end
|
413
|
+
end
|
413
414
|
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
415
|
+
$pv_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToLoad(kw)')
|
416
|
+
if $pv_to_load_col.nil?
|
417
|
+
$pv_to_load_col = scenario_report.timeseries_csv.column_names.length
|
418
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToLoad(kw)')
|
419
|
+
end
|
419
420
|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
421
|
+
$pv_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToGrid(kw)')
|
422
|
+
if $pv_to_grid_col.nil?
|
423
|
+
$pv_to_grid_col = scenario_report.timeseries_csv.column_names.length
|
424
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToGrid(kw)')
|
425
|
+
end
|
425
426
|
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
427
|
+
$pv_total = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
|
428
|
+
if !storage.nil?
|
429
|
+
$pv_to_battery = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
|
430
|
+
end
|
431
|
+
$pv_to_load = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
|
432
|
+
$pv_to_grid = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
|
433
|
+
|
434
|
+
reopt_output['outputs']['PV'].each_with_index do |pv, i|
|
435
|
+
if (pv['size_kw'] || 0) > 0
|
436
|
+
# $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)]
|
437
|
+
if !storage.nil?
|
438
|
+
$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)]
|
439
|
+
end
|
440
|
+
$pv_to_load += Matrix[convert_powerflow_resolution(pv['electric_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)]
|
441
|
+
$pv_to_grid += Matrix[convert_powerflow_resolution(pv['electric_to_grid_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)]
|
442
|
+
end
|
437
443
|
end
|
444
|
+
|
445
|
+
$pv_total = $pv_total.to_a[0]
|
446
|
+
if !storage.nil?
|
447
|
+
$pv_to_battery = $pv_to_battery.to_a[0]
|
448
|
+
end
|
449
|
+
$pv_to_load = $pv_to_load.to_a[0]
|
450
|
+
$pv_to_grid = $pv_to_grid.to_a[0]
|
438
451
|
end
|
439
452
|
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
453
|
+
if !wind.nil?
|
454
|
+
# $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)
|
455
|
+
$wind_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:Total(kw)')
|
456
|
+
if $wind_total_col.nil?
|
457
|
+
$wind_total_col = scenario_report.timeseries_csv.column_names.length
|
458
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:Total(kw)')
|
459
|
+
end
|
444
460
|
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
461
|
+
if !storage.nil?
|
462
|
+
$wind_to_battery = convert_powerflow_resolution(reopt_output['outputs']['Wind']['electric_to_storage_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
463
|
+
$wind_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToBattery(kw)')
|
464
|
+
if $wind_to_battery_col.nil?
|
465
|
+
$wind_to_battery_col = scenario_report.timeseries_csv.column_names.length
|
466
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToBattery(kw)')
|
467
|
+
end
|
468
|
+
end
|
451
469
|
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
470
|
+
$wind_to_load = convert_powerflow_resolution(reopt_output['outputs']['Wind']['electric_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
471
|
+
$wind_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToLoad(kw)')
|
472
|
+
if $wind_to_load_col.nil?
|
473
|
+
$wind_to_load_col = scenario_report.timeseries_csv.column_names.length
|
474
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToLoad(kw)')
|
475
|
+
end
|
458
476
|
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
477
|
+
$wind_to_grid = convert_powerflow_resolution(reopt_output['outputs']['Wind']['electric_to_grid_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
478
|
+
$wind_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToGrid(kw)')
|
479
|
+
if $wind_to_grid_col.nil?
|
480
|
+
$wind_to_grid_col = scenario_report.timeseries_csv.column_names.length
|
481
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToGrid(kw)')
|
482
|
+
end
|
464
483
|
end
|
465
484
|
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
$
|
470
|
-
|
485
|
+
def modrow(data, idx) # :nodoc:
|
486
|
+
data[$generation_timeseries_kwh_col] = $generation_timeseries_kwh[idx] || 0
|
487
|
+
data[$load_col] = $load[idx] || 0
|
488
|
+
data[$utility_to_load_col] = $utility_to_load[idx] || 0
|
489
|
+
data[$utility_to_battery_col] = $utility_to_battery[idx] || 0 if defined?(storage)
|
490
|
+
data[$storage_to_load_col] = $storage_to_load[idx] || 0 if defined?(storage)
|
491
|
+
data[$storage_to_grid_col] = $storage_to_grid[idx] || 0 if defined?(storage)
|
492
|
+
data[$storage_soc_col] = $storage_soc[idx] || 0 if defined?(storage)
|
493
|
+
data[$generator_total_col] = $generator_total[idx] || 0 if defined?(generator)
|
494
|
+
data[$generator_to_battery_col] = $generator_to_battery[idx] || 0 if (defined?(generator) && defined?(storage))
|
495
|
+
data[$generator_to_load_col] = $generator_to_load[idx] || 0 if defined?(generator)
|
496
|
+
data[$generator_to_grid_col] = $generator_to_grid[idx] || 0 if defined?(generator)
|
497
|
+
data[$pv_total_col] = $pv_total[idx] || 0
|
498
|
+
data[$pv_to_battery_col] = $pv_to_battery[idx] || 0 if defined?(storage)
|
499
|
+
data[$pv_to_load_col] = $pv_to_load[idx] || 0
|
500
|
+
data[$pv_to_grid_col] = $pv_to_grid[idx] || 0
|
501
|
+
data[$wind_total_col] = $wind_total[idx] || 0 if defined?(wind)
|
502
|
+
data[$wind_to_battery_col] = $wind_to_battery[idx] || 0 if (defined?(wind) && defined?(storage))
|
503
|
+
data[$wind_to_load_col] = $wind_to_load[idx] || 0 if defined?(wind)
|
504
|
+
data[$wind_to_grid_col] = $wind_to_grid[idx] || 0 if defined?(wind)
|
505
|
+
return data
|
471
506
|
end
|
472
507
|
|
473
508
|
old_data = CSV.open(scenario_report.timeseries_csv.path).read
|