urbanopt-reopt 0.1.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -28,10 +28,11 @@
28
28
  # OF THE POSSIBILITY OF SUCH DAMAGE.
29
29
  # *********************************************************************************
30
30
 
31
- require 'urbanopt/scenario/default_reports'
31
+ require 'urbanopt/reporting/default_reports'
32
32
  require 'urbanopt/reopt/reopt_logger'
33
-
33
+ require 'matrix'
34
34
  require 'csv'
35
+ require 'time'
35
36
 
36
37
  module URBANopt # :nodoc:
37
38
  module REopt # :nodoc:
@@ -50,7 +51,7 @@ module URBANopt # :nodoc:
50
51
  #
51
52
  # [*parameters:*]
52
53
  #
53
- # * +scenario_report+ - _URBANopt::Scenario::DefaultReports::ScenarioReport_ - ScenarioReport to use in converting the +reopt_assumptions_hash+, if provided, to a \REopt Lite post. Otherwise, if the +reopt_assumptions_hash+ is nil a default post will be updated from this ScenarioReport and submitted to the \REopt Lite API.
54
+ # * +scenario_report+ - _URBANopt::Reporting::DefaultReports::ScenarioReport_ - ScenarioReport to use in converting the +reopt_assumptions_hash+, if provided, to a \REopt Lite post. Otherwise, if the +reopt_assumptions_hash+ is nil a default post will be updated from this ScenarioReport and submitted to the \REopt Lite API.
54
55
  # * +reopt_assumptions_hash+ - _Hash_ - Optional. A hash formatted for submittal to the \REopt Lite API containing default values. Values will be overwritten from the ScenarioReport where available (i.e. latitude, roof_squarefeet). Missing optional parameters will be filled in with default values by the API.
55
56
  #
56
57
  # [*return:*] _Hash_ - Returns hash formatted for submittal to the \REopt Lite API
@@ -114,25 +115,29 @@ module URBANopt # :nodoc:
114
115
  reopt_inputs[:Scenario][:Site][:land_acres] = scenario_report.program.site_area * 1.0 / 43560 # acres/sqft
115
116
  end
116
117
 
118
+ unless scenario_report.timesteps_per_hour.nil?
119
+ reopt_inputs[:Scenario][:time_steps_per_hour] = scenario_report.timesteps_per_hour
120
+ end
121
+
117
122
  # Update load profile info
118
123
  begin
119
- col_num = scenario_report.timeseries_csv.column_names.index('Electricity:Facility')
124
+ col_num = scenario_report.timeseries_csv.column_names.index('Electricity:Facility(kWh)')
120
125
  t = CSV.read(scenario_report.timeseries_csv.path, headers: true, converters: :numeric)
121
- energy_timeseries_kwh = t.by_col[col_num].map { |e| ((e || 0) * 0.293071) } # convert kBTU to KWH
122
-
123
- if (scenario_report.timesteps_per_hour || 1) > 1
124
- energy_timeseries_kwh = energy_timeseries_kwh.each_slice(scenario_report.timesteps_per_hour).to_a.map { |x| x.inject(0, :+) / x.length.to_f }
125
- end
126
-
127
- if energy_timeseries_kwh.length < scenario_report.timesteps_per_hour * 8760
128
- energy_timeseries_kwh += [0] * ((scenario_report.timesteps_per_hour * 8760) - energy_timeseries_kwh.length)
129
- @@logger.info("Assuming load profile for Scenario Report #{scenario_report.name} #{scenario_report.id} starts January 1 - filling in rest with zeros")
126
+ energy_timeseries_kw = t.by_col[col_num].map { |e| ((e * scenario_report.timesteps_per_hour || 0) ) }
127
+ if energy_timeseries_kw.length < (scenario_report.timesteps_per_hour * 8760)
128
+ start_date = Time.parse(t.by_col["Datetime"][0])
129
+ 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) / \
130
+ (( 60 / scenario_report.timesteps_per_hour ) * 60)).to_int
131
+ end_date = Time.parse(t.by_col["Datetime"][-1])
132
+ 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) / \
133
+ (( 60 / scenario_report.timesteps_per_hour ) * 60)).to_int
134
+ energy_timeseries_kw = [0.0]*(start_ts-1) + energy_timeseries_kw + [0.0]*((scenario_report.timesteps_per_hour * 8760) - end_ts)
130
135
  end
131
- reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw] = energy_timeseries_kwh
136
+ reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw] = energy_timeseries_kw.map { |e| e ? e : 0 }[0,(scenario_report.timesteps_per_hour * 8760)]
132
137
  rescue StandardError
138
+ @@logger.error("Could not parse the annual electric load from the timeseries csv - #{scenario_report.timeseries_csv.path}")
133
139
  raise "Could not parse the annual electric load from the timeseries csv - #{scenario_report.timeseries_csv.path}"
134
140
  end
135
-
136
141
  return reopt_inputs
137
142
  end
138
143
 
@@ -141,7 +146,7 @@ module URBANopt # :nodoc:
141
146
  #
142
147
  # [*parameters:*]
143
148
  #
144
- # * +scenario_report+ - _URBANopt::Scenario::DefaultReports::ScenarioReport_ - ScenarioReport to use in converting FeatureReports and respecitive +reopt_assumptions_hashes+, if provided, to a \REopt Lite post. If no +reopt_assumptions_hashes+ are provided default posts will be updated from these FeatureReports and submitted to the \REopt Lite API.
149
+ # * +scenario_report+ - _URBANopt::Reporting::DefaultReports::ScenarioReport_ - ScenarioReport to use in converting FeatureReports and respecitive +reopt_assumptions_hashes+, if provided, to a \REopt Lite post. If no +reopt_assumptions_hashes+ are provided default posts will be updated from these FeatureReports and submitted to the \REopt Lite API.
145
150
  # * +reopt_assumptions_hashes+ - _Array_ - Optional. An array of hashes formatted for submittal to the \REopt Lite API containing default values. Values will be overwritten from the ScenarioReport where available (i.e. latitude, roof_squarefeet). Missing optional parameters will be filled in with default values by the API. The order should match the list in ScenarioReport.feature_reports.
146
151
  #
147
152
  # [*return:*] _Array_ - Returns an array of hashes formatted for submittal to the \REopt Lite API in the order of the FeatureReports lited in ScenarioReport.feature_reports.
@@ -163,18 +168,38 @@ module URBANopt # :nodoc:
163
168
  #
164
169
  # [*parameters:*]
165
170
  #
166
- # * +scenario_report+ - _URBANopt::Scenario::DefaultReports::ScenarioReport_ - ScenarioReport to update from a \REopt Lite response.
171
+ # * +scenario_report+ - _URBANopt::Reporting::DefaultReports::ScenarioReport_ - ScenarioReport to update from a \REopt Lite response.
167
172
  # * +reopt_output+ - _Hash_ - A hash response from the \REopt Lite API.
168
173
  # * +timeseries_csv_path+ - _String_ - Optional. The path to a file at which new timeseries data will be written. If not provided a file is created based on the run_uuid of the \REopt Lite optimization task.
169
174
  #
170
- # [*return:*] _URBANopt::Scenario::DefaultReports::ScenarioReport_ - Returns an updated ScenarioReport
175
+ # [*return:*] _URBANopt::Reporting::DefaultReports::ScenarioReport_ - Returns an updated ScenarioReport
171
176
  ##
172
- def update_scenario_report(scenario_report, reopt_output, timeseries_csv_path = nil)
177
+ def update_scenario_report(scenario_report, reopt_output, timeseries_csv_path=nil, resilience_stats=nil)
173
178
  if reopt_output['outputs']['Scenario']['status'] != 'optimal'
174
179
  @@logger.info("Warning cannot Feature Report #{scenario_report.name} #{scenario_report.id} - REopt optimization was non-optimal")
175
180
  return scenario_report
176
181
  end
177
182
 
183
+ $ts_per_hour = scenario_report.timesteps_per_hour
184
+ def scale_timeseries(input, ts_per_hr=$ts_per_hour)
185
+ if input.nil?
186
+ return nil
187
+ end
188
+ if input.length ==0
189
+ return nil
190
+ end
191
+ if input.length == (8760 * ts_per_hr)
192
+ return input
193
+ end
194
+ result = []
195
+ input.each do |val|
196
+ (1..ts_per_hr).each do |x|
197
+ result.push(val/ts_per_hr.to_f)
198
+ end
199
+ end
200
+ return result
201
+ end
202
+
178
203
  # Update location
179
204
  scenario_report.location.latitude = reopt_output['inputs']['Scenario']['Site']['latitude']
180
205
  scenario_report.location.longitude = reopt_output['inputs']['Scenario']['Site']['longitude']
@@ -183,36 +208,71 @@ module URBANopt # :nodoc:
183
208
  scenario_report.timesteps_per_hour = reopt_output['inputs']['Scenario']['time_steps_per_hour']
184
209
 
185
210
  # Update distributed generation sizing and financials
186
- (scenario_report.distributed_generation.lcc_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['lcc_us_dollars']) || 0
187
- (scenario_report.distributed_generation.npv_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['npv_us_dollars']) || 0
188
- (scenario_report.distributed_generation.year_one_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_energy_cost_us_dollars']) || 0
189
- (scenario_report.distributed_generation.year_one_demand_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_demand_cost_us_dollars']) || 0
190
- (scenario_report.distributed_generation.year_one_bill_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_bill_us_dollars']) || 0
191
- (scenario_report.distributed_generation.total_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['total_energy_cost_us_dollars']) || 0
192
-
193
- (scenario_report.distributed_generation.solar_pv.size_kw = reopt_output['outputs']['Scenario']['Site']['PV']['size_kw']) || 0
194
- (scenario_report.distributed_generation.wind.size_kw = reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw']) || 0
195
- (scenario_report.distributed_generation.generator.size_kw = reopt_output['outputs']['Scenario']['Site']['Generator']['size_kw']) || 0
196
- (scenario_report.distributed_generation.storage.size_kw = reopt_output['outputs']['Scenario']['Site']['Storage']['size_kw']) || 0
197
- (scenario_report.distributed_generation.storage.size_kwh = reopt_output['outputs']['Scenario']['Site']['Storage']['size_kwh']) || 0
198
-
199
- # Update dispatch
200
- generation_timeseries_kwh = Matrix[[0] * 8760]
201
- unless reopt_output['outputs']['Scenario']['Site']['PV'].nil?
202
- if (reopt_output['outputs']['Scenario']['Site']['PV']['size_kw'] || 0) > 0
203
- if !reopt_output['outputs']['Scenario']['Site']['PV']['year_one_power_production_series_kw'].nil?
204
- generation_timeseries_kwh += Matrix[reopt_output['outputs']['Scenario']['Site']['PV']['year_one_power_production_series_kw']]
211
+
212
+ scenario_report.distributed_generation.lcc_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['lcc_us_dollars'] || 0
213
+ scenario_report.distributed_generation.npv_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['npv_us_dollars'] || 0
214
+ scenario_report.distributed_generation.year_one_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_energy_cost_us_dollars'] || 0
215
+ scenario_report.distributed_generation.year_one_demand_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_demand_cost_us_dollars'] || 0
216
+ scenario_report.distributed_generation.year_one_bill_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_bill_us_dollars'] || 0
217
+ scenario_report.distributed_generation.total_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['total_energy_cost_us_dollars'] || 0
218
+ scenario_report.distributed_generation.total_demand_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['total_demand_cost_us_dollars'] || 0
219
+ scenario_report.distributed_generation.year_one_energy_cost_bau_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_energy_cost_bau_us_dollars'] || 0
220
+ scenario_report.distributed_generation.year_one_demand_cost_bau_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_demand_cost_bau_us_dollars'] || 0
221
+ scenario_report.distributed_generation.year_one_bill_bau_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_bill_bau_us_dollars'] || 0
222
+ scenario_report.distributed_generation.total_demand_cost_bau_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['total_demand_cost_bau_us_dollars'] || 0
223
+ scenario_report.distributed_generation.total_energy_cost_bau_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['total_energy_cost_bau_us_dollars'] || 0
224
+ if !resilience_stats.nil?
225
+ scenario_report.distributed_generation.resilience_hours_min = resilience_stats['resilience_hours_min']
226
+ scenario_report.distributed_generation.resilience_hours_max = resilience_stats['resilience_hours_max']
227
+ scenario_report.distributed_generation.resilience_hours_avg = resilience_stats['resilience_hours_avg']
228
+ scenario_report.distributed_generation.probs_of_surviving = resilience_stats['probs_of_surviving']
229
+ scenario_report.distributed_generation.probs_of_surviving_by_month = resilience_stats['probs_of_surviving_by_month']
230
+ scenario_report.distributed_generation.probs_of_surviving_by_hour_of_the_day = resilience_stats['probs_of_surviving_by_hour_of_the_day']
231
+ end
232
+
233
+ if reopt_output['outputs']['Scenario']['Site']['PV'].class == Hash
234
+ reopt_output['outputs']['Scenario']['Site']['PV'] = [reopt_output['outputs']['Scenario']['Site']['PV']]
235
+ elsif reopt_output['outputs']['Scenario']['Site']['PV'].nil?
236
+ reopt_output['outputs']['Scenario']['Site']['PV'] = []
237
+ end
238
+
239
+ reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
240
+ scenario_report.distributed_generation.add_tech 'solar_pv', URBANopt::Reporting::DefaultReports::SolarPV.new( {size_kw: (pv['size_kw'] || 0), id: i })
241
+ end
242
+
243
+ wind = reopt_output['outputs']['Scenario']['Site']['Wind']
244
+ if !wind['size_kw'].nil? and wind['size_kw'] != 0
245
+ scenario_report.distributed_generation.add_tech 'wind', URBANopt::Reporting::DefaultReports::Wind.new( {size_kw: (wind['size_kw'] || 0) })
246
+ end
247
+
248
+ generator = reopt_output['outputs']['Scenario']['Site']['Generator']
249
+ if !generator['size_kw'].nil? and generator['size_kw'] != 0
250
+ scenario_report.distributed_generation.add_tech 'generator', URBANopt::Reporting::DefaultReports::Generator.new( {size_kw: (generator['size_kw'] || 0) })
251
+ end
252
+
253
+ storage = reopt_output['outputs']['Scenario']['Site']['Storage']
254
+ if !storage['size_kw'].nil? and storage['size_kw'] != 0
255
+ scenario_report.distributed_generation.add_tech 'storage', URBANopt::Reporting::DefaultReports::Storage.new( {size_kwh: (storage['size_kwh'] || 0), size_kw: (storage['size_kw'] || 0) })
256
+ end
257
+
258
+ generation_timeseries_kwh = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
259
+
260
+
261
+ reopt_output['outputs']['Scenario']['Site']['PV'].each do |pv|
262
+ if (pv['size_kw'] || 0) > 0
263
+ if !pv['year_one_power_production_series_kw'].nil?
264
+ generation_timeseries_kwh += Matrix[pv['year_one_power_production_series_kw']]
205
265
  end
206
266
  end
207
- end
267
+ end
208
268
 
209
- # unless reopt_output['outputs']['Scenario']['Site']['Storage'].nil?
210
- # if (reopt_output['outputs']['Scenario']['Site']['Storage']['size_kw'] or 0) > 0
211
- # if !reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'].nil?
212
- # generation_timeseries_kwh = generation_timeseries_kwh + Matrix[reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']]
213
- # end
214
- # end
215
- # end
269
+ unless reopt_output['outputs']['Scenario']['Site']['Storage'].nil?
270
+ if (reopt_output['outputs']['Scenario']['Site']['Storage']['size_kw'] or 0) > 0
271
+ if !reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'].nil?
272
+ generation_timeseries_kwh = generation_timeseries_kwh + Matrix[reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']]
273
+ end
274
+ end
275
+ end
216
276
 
217
277
  unless reopt_output['outputs']['Scenario']['Site']['Wind'].nil?
218
278
  if (reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) > 0
@@ -230,137 +290,152 @@ module URBANopt # :nodoc:
230
290
  end
231
291
  end
232
292
 
233
- $generation_timeseries_kwh = generation_timeseries_kwh.to_a[0]
234
- $generation_timeseries_kwh_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Total')
293
+ $generation_timeseries_kwh = generation_timeseries_kwh.to_a[0] || [0] * (8760 * scenario_report.timesteps_per_hour)
294
+ $generation_timeseries_kwh_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Total(kw)')
235
295
  if $generation_timeseries_kwh_col.nil?
236
296
  $generation_timeseries_kwh_col = scenario_report.timeseries_csv.column_names.length
237
- scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Total')
297
+ scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Total(kw)')
238
298
  end
239
299
 
240
- $load = reopt_output['outputs']['Scenario']['Site']['LoadProfile']['year_one_electric_load_series_kw'] || [0] * 8760
241
- $load_col = scenario_report.timeseries_csv.column_names.index('Electricity:Load:Total')
300
+ $load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['LoadProfile']['year_one_electric_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
301
+ $load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Load:Total(kw)')
242
302
  if $load_col.nil?
243
303
  $load_col = scenario_report.timeseries_csv.column_names.length
244
- scenario_report.timeseries_csv.column_names.push('Electricity:Load:Total')
304
+ scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Load:Total(kw)')
245
305
  end
246
306
 
247
- $utility_to_load = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_load_series_kw'] || [0] * 8760
248
- $utility_to_load_col = scenario_report.timeseries_csv.column_names.index('Electricity:Grid:ToLoad')
307
+ $utility_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
308
+ $utility_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToLoad(kw)')
249
309
  if $utility_to_load_col.nil?
250
310
  $utility_to_load_col = scenario_report.timeseries_csv.column_names.length
251
- scenario_report.timeseries_csv.column_names.push('Electricity:Grid:ToLoad')
311
+ scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToLoad(kw)')
252
312
  end
253
313
 
254
- $utility_to_battery = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_battery_series_kw'] || [0] * 8760
255
- $utility_to_battery_col = scenario_report.timeseries_csv.column_names.index('Electricity:Grid:ToBattery')
314
+ $utility_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
315
+ $utility_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToBattery(kw)')
256
316
  if $utility_to_battery_col.nil?
257
317
  $utility_to_battery_col = scenario_report.timeseries_csv.column_names.length
258
- scenario_report.timeseries_csv.column_names.push('Electricity:Grid:ToBattery')
318
+ scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToBattery(kw)')
259
319
  end
260
320
 
261
- $storage_to_load = reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw'] || [0] * 8760
262
- $storage_to_load_col = scenario_report.timeseries_csv.column_names.index('Electricity:Storage:ToLoad')
321
+ $storage_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
322
+ $storage_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToLoad(kw)')
263
323
  if $storage_to_load_col.nil?
264
324
  $storage_to_load_col = scenario_report.timeseries_csv.column_names.length
265
- scenario_report.timeseries_csv.column_names.push('Electricity:Storage:ToLoad')
325
+ scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToLoad(kw)')
266
326
  end
267
327
 
268
- $storage_to_grid = reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'] || [0] * 8760
269
- $storage_to_grid_col = scenario_report.timeseries_csv.column_names.index('Electricity:Storage:ToGrid')
328
+ $storage_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
329
+ $storage_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToGrid(kw)')
270
330
  if $storage_to_grid_col.nil?
271
331
  $storage_to_grid_col = scenario_report.timeseries_csv.column_names.length
272
- scenario_report.timeseries_csv.column_names.push('Electricity:Storage:ToGrid')
332
+ scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToGrid(kw)')
273
333
  end
274
334
 
275
- $storage_soc = reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct'] || [0] * 8760
276
- $storage_soc_col = scenario_report.timeseries_csv.column_names.index('Electricity:Storage:StateOfCharge')
335
+ $storage_soc = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct']) || [0] * (8760 * scenario_report.timesteps_per_hour)
336
+ $storage_soc_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:StateOfCharge(pct)')
277
337
  if $storage_soc_col.nil?
278
338
  $storage_soc_col = scenario_report.timeseries_csv.column_names.length
279
- scenario_report.timeseries_csv.column_names.push('Electricity:Storage:StateOfCharge')
339
+ scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:StateOfCharge(pct)')
280
340
  end
281
341
 
282
- $generator_total = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'] || [0] * 8760
283
- $generator_total_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:Total')
342
+ $generator_total = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
343
+ $generator_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:Total(kw)')
284
344
  if $generator_total_col.nil?
285
345
  $generator_total_col = scenario_report.timeseries_csv.column_names.length
286
- scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:Total')
346
+ scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:Total(kw)')
287
347
  end
288
348
 
289
- $generator_to_battery = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_battery_series_kw'] || [0] * 8760
290
- $generator_to_battery_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:ToBattery')
349
+ $generator_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
350
+ $generator_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToBattery(kw)')
291
351
  if $generator_to_battery_col.nil?
292
352
  $generator_to_battery_col = scenario_report.timeseries_csv.column_names.length
293
- scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToBattery')
353
+ scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToBattery(kw)')
294
354
  end
295
355
 
296
- $generator_to_load = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw'] || [0] * 8760
297
- $generator_to_load_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:ToLoad')
356
+ $generator_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
357
+ $generator_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToLoad(kw)')
298
358
  if $generator_to_load_col.nil?
299
359
  $generator_to_load_col = scenario_report.timeseries_csv.column_names.length
300
- scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToLoad')
360
+ scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToLoad(kw)')
301
361
  end
302
362
 
303
- $generator_to_grid = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_grid_series_kw'] || [0] * 8760
304
- $generator_to_grid_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:ToGrid')
363
+ $generator_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
364
+ $generator_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToGrid(kw)')
305
365
  if $generator_to_grid_col.nil?
306
366
  $generator_to_grid_col = scenario_report.timeseries_csv.column_names.length
307
- scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToGrid')
367
+ scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToGrid(kw)')
308
368
  end
309
369
 
310
- $pv_total = reopt_output['outputs']['Scenario']['Site']['PV']['year_one_power_production_series_kw'] || [0] * 8760
311
- $pv_total_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:PV:Total')
370
+ $pv_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:Total(kw)')
312
371
  if $pv_total_col.nil?
313
372
  $pv_total_col = scenario_report.timeseries_csv.column_names.length
314
- scenario_report.timeseries_csv.column_names.push('ElectricityProduced:PV:Total')
373
+ scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:Total(kw)')
315
374
  end
316
375
 
317
- $pv_to_battery = reopt_output['outputs']['Scenario']['Site']['PV']['year_one_to_battery_series_kw'] || [0] * 8760
318
- $pv_to_battery_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToBattery')
376
+ $pv_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToBattery(kw)')
319
377
  if $pv_to_battery_col.nil?
320
378
  $pv_to_battery_col = scenario_report.timeseries_csv.column_names.length
321
- scenario_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToBattery')
379
+ scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToBattery(kw)')
322
380
  end
323
381
 
324
- $pv_to_load = reopt_output['outputs']['Scenario']['Site']['PV']['year_one_to_load_series_kw'] || [0] * 8760
325
- $pv_to_load_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToLoad')
382
+ $pv_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToLoad(kw)')
326
383
  if $pv_to_load_col.nil?
327
384
  $pv_to_load_col = scenario_report.timeseries_csv.column_names.length
328
- scenario_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToLoad')
385
+ scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToLoad(kw)')
329
386
  end
330
387
 
331
- $pv_to_grid = reopt_output['outputs']['Scenario']['Site']['PV']['year_one_to_grid_series_kw'] || [0] * 8760
332
- $pv_to_grid_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToGrid')
388
+ $pv_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToGrid(kw)')
333
389
  if $pv_to_grid_col.nil?
334
390
  $pv_to_grid_col = scenario_report.timeseries_csv.column_names.length
335
- scenario_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToGrid')
391
+ scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToGrid(kw)')
336
392
  end
337
393
 
338
- $wind_total = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'] || [0] * 8760
339
- $wind_total_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:Total')
394
+ $pv_total = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
395
+ $pv_to_battery = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
396
+ $pv_to_load = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
397
+ $pv_to_grid = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
398
+
399
+ reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
400
+ if (pv['size_kw'] || 0) > 0
401
+ $pv_total += Matrix[scale_timeseries(pv['year_one_power_production_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
402
+ $pv_to_battery += Matrix[scale_timeseries(pv['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
403
+ $pv_to_load += Matrix[scale_timeseries(pv['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
404
+ $pv_to_grid += Matrix[scale_timeseries(pv['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
405
+ end
406
+ end
407
+
408
+ $pv_total = $pv_total.to_a[0]
409
+ $pv_to_battery = $pv_to_battery.to_a[0]
410
+ $pv_to_load = $pv_to_load.to_a[0]
411
+ $pv_to_grid = $pv_to_grid.to_a[0]
412
+
413
+ $wind_total = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
414
+ $wind_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:Total(kw)')
340
415
  if $wind_total_col.nil?
341
416
  $wind_total_col = scenario_report.timeseries_csv.column_names.length
342
- scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:Total')
417
+ scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:Total(kw)')
343
418
  end
344
419
 
345
- $wind_to_battery = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_battery_series_kw'] || [0] * 8760
346
- $wind_to_battery_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:ToBattery')
420
+ $wind_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
421
+ $wind_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToBattery(kw)')
347
422
  if $wind_to_battery_col.nil?
348
423
  $wind_to_battery_col = scenario_report.timeseries_csv.column_names.length
349
- scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToBattery')
424
+ scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToBattery(kw)')
350
425
  end
351
426
 
352
- $wind_to_load = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_load_series_kw'] || [0] * 8760
353
- $wind_to_load_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:ToLoad')
427
+ $wind_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
428
+ $wind_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToLoad(kw)')
354
429
  if $wind_to_load_col.nil?
355
430
  $wind_to_load_col = scenario_report.timeseries_csv.column_names.length
356
- scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToLoad')
431
+ scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToLoad(kw)')
357
432
  end
358
433
 
359
- $wind_to_grid = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_grid_series_kw'] || [0] * 8760
360
- $wind_to_grid_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:ToGrid')
434
+ $wind_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
435
+ $wind_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToGrid(kw)')
361
436
  if $wind_to_grid_col.nil?
362
437
  $wind_to_grid_col = scenario_report.timeseries_csv.column_names.length
363
- scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToGrid')
438
+ scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToGrid(kw)')
364
439
  end
365
440
 
366
441
  def modrow(x, i) # :nodoc:
@@ -387,9 +462,11 @@ module URBANopt # :nodoc:
387
462
  end
388
463
 
389
464
  old_data = CSV.open(scenario_report.timeseries_csv.path).read
465
+ start_date = Time.parse(old_data[1][0])
466
+ 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) / (( 60 / scenario_report.timesteps_per_hour ) * 60)).to_int
390
467
  mod_data = old_data.map.with_index do |x, i|
391
468
  if i > 0
392
- modrow(x, i)
469
+ modrow(x, start_ts + i -2)
393
470
  else
394
471
  x
395
472
  end
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -30,6 +30,6 @@
30
30
 
31
31
  module URBANopt # :nodoc:
32
32
  module REopt # :nodoc:
33
- VERSION = '0.1.0'.freeze
33
+ VERSION = '0.4.0'.freeze
34
34
  end
35
35
  end