urbanopt-reopt 0.1.0 → 0.4.0

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.
@@ -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