urbanopt-reopt 0.5.4 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,21 +1,31 @@
1
1
  # *********************************************************************************
2
- # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2021, 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,
6
6
  # are permitted provided that the following conditions are met:
7
- #
7
+
8
8
  # Redistributions of source code must retain the above copyright notice, this list
9
9
  # of conditions and the following disclaimer.
10
- #
10
+
11
11
  # Redistributions in binary form must reproduce the above copyright notice, this
12
12
  # list of conditions and the following disclaimer in the documentation and/or other
13
13
  # materials provided with the distribution.
14
- #
14
+
15
15
  # Neither the name of the copyright holder nor the names of its contributors may be
16
16
  # used to endorse or promote products derived from this software without specific
17
17
  # prior written permission.
18
- #
18
+
19
+ # Redistribution of this software, without modification, must refer to the software
20
+ # by the same designation. Redistribution of a modified version of this software
21
+ # (i) may not refer to the modified version by the same designation, or by any
22
+ # confusingly similar designation, and (ii) must refer to the underlying software
23
+ # originally provided by Alliance as “URBANopt”. Except to comply with the foregoing,
24
+ # the term “URBANopt”, or any confusingly similar designation may not be used to
25
+ # refer to any modified version of this software or any modified version of the
26
+ # underlying software originally provided by Alliance without the prior written
27
+ # consent of Alliance.
28
+
19
29
  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
30
  # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
31
  # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
@@ -34,8 +44,10 @@ require 'urbanopt/scenario/simulation_dir_osw'
34
44
  require 'csv'
35
45
  require 'fileutils'
36
46
 
37
- module URBANopt # nodoc:
38
- module Scenario # nodoc:
47
+ # nodoc:
48
+ module URBANopt
49
+ # nodoc:
50
+ module Scenario
39
51
  class REoptScenarioCSV < ScenarioCSV
40
52
  ##
41
53
  # REoptScenarioCSV is an extension of ScenarioCSV which assigns a Simulation Mapper to each Feature in a FeatureFile using a simple CSV format.
@@ -91,10 +103,8 @@ module URBANopt # nodoc:
91
103
  mapper_class = row[2].chomp
92
104
  # Assume fourth columns, if exists, contains the name of the JSON file in the reopt_files_dir to use when running \REopt Lite for the feature report
93
105
 
94
- if row.length > 3
95
- if !@reopt_files_dir.nil?
96
- @reopt_feature_assumptions[idx - 1] = File.join(@reopt_files_dir, row[3].chomp)
97
- end
106
+ if row.length > 3 && !@reopt_files_dir.nil?
107
+ @reopt_feature_assumptions[idx - 1] = File.join(@reopt_files_dir, row[3].chomp)
98
108
  end
99
109
 
100
110
  # gets +features+ from the feature_file.
@@ -110,6 +120,6 @@ module URBANopt # nodoc:
110
120
  end
111
121
  return result
112
122
  end
113
- end
123
+ end
114
124
  end
115
125
  end
@@ -1,21 +1,31 @@
1
1
  # *********************************************************************************
2
- # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2021, 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,
6
6
  # are permitted provided that the following conditions are met:
7
- #
7
+
8
8
  # Redistributions of source code must retain the above copyright notice, this list
9
9
  # of conditions and the following disclaimer.
10
- #
10
+
11
11
  # Redistributions in binary form must reproduce the above copyright notice, this
12
12
  # list of conditions and the following disclaimer in the documentation and/or other
13
13
  # materials provided with the distribution.
14
- #
14
+
15
15
  # Neither the name of the copyright holder nor the names of its contributors may be
16
16
  # used to endorse or promote products derived from this software without specific
17
17
  # prior written permission.
18
- #
18
+
19
+ # Redistribution of this software, without modification, must refer to the software
20
+ # by the same designation. Redistribution of a modified version of this software
21
+ # (i) may not refer to the modified version by the same designation, or by any
22
+ # confusingly similar designation, and (ii) must refer to the underlying software
23
+ # originally provided by Alliance as “URBANopt”. Except to comply with the foregoing,
24
+ # the term “URBANopt”, or any confusingly similar designation may not be used to
25
+ # refer to any modified version of this software or any modified version of the
26
+ # underlying software originally provided by Alliance without the prior written
27
+ # consent of Alliance.
28
+
19
29
  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
30
  # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
31
  # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
@@ -71,22 +81,20 @@ module URBANopt # :nodoc:
71
81
  end
72
82
 
73
83
  # Update required info
74
- if scenario_report.location.latitude_deg.nil? || scenario_report.location.longitude_deg.nil? || (scenario_report.location.latitude_deg == 0) || (scenario_report.location.longitude_deg == 0)
75
- if !scenario_report.feature_reports.nil? && (scenario_report.feature_reports != [])
76
- lats = []
77
- longs = []
78
- scenario_report.feature_reports.each do |x|
79
- puts " ERROR: #{x.location.latitude_deg}"
80
- if ![nil].include?(x.location.latitude_deg) && ![nil].include?(x.location.longitude_deg)
81
- lats.push(x.location.latitude_deg)
82
- longs.push(x.location.longitude_deg)
83
- end
84
+ if (scenario_report.location.latitude_deg.nil? || scenario_report.location.longitude_deg.nil? || (scenario_report.location.latitude_deg == 0) || (scenario_report.location.longitude_deg == 0)) && (!scenario_report.feature_reports.nil? && (scenario_report.feature_reports != []))
85
+ lats = []
86
+ longs = []
87
+ scenario_report.feature_reports.each do |x|
88
+ puts " ERROR: #{x.location.latitude_deg}"
89
+ if ![nil].include?(x.location.latitude_deg) && ![nil].include?(x.location.longitude_deg)
90
+ lats.push(x.location.latitude_deg)
91
+ longs.push(x.location.longitude_deg)
84
92
  end
93
+ end
85
94
 
86
- if !lats.empty? && !longs.empty?
87
- scenario_report.location.latitude_deg = lats.reduce(:+) / lats.size.to_f
88
- scenario_report.location.longitude_deg = longs.reduce(:+) / longs.size.to_f
89
- end
95
+ if !lats.empty? && !longs.empty?
96
+ scenario_report.location.latitude_deg = lats.reduce(:+) / lats.size.to_f
97
+ scenario_report.location.longitude_deg = longs.reduce(:+) / longs.size.to_f
90
98
  end
91
99
  end
92
100
 
@@ -110,16 +118,12 @@ module URBANopt # :nodoc:
110
118
 
111
119
  # Update optional info
112
120
  # REK: attribute names should be updated
113
- if reopt_inputs[:Scenario][:Site][:roof_squarefeet].nil?
114
- if !scenario_report.program.roof_area_sqft.nil?
115
- reopt_inputs[:Scenario][:Site][:roof_squarefeet] = scenario_report.program.roof_area_sqft[:available_roof_area_sqft]
116
- end
121
+ if reopt_inputs[:Scenario][:Site][:roof_squarefeet].nil? && !scenario_report.program.roof_area_sqft.nil?
122
+ reopt_inputs[:Scenario][:Site][:roof_squarefeet] = scenario_report.program.roof_area_sqft[:available_roof_area_sqft]
117
123
  end
118
124
 
119
- if reopt_inputs[:Scenario][:Site][:land_acres].nil?
120
- if !scenario_report.program.site_area_sqft.nil?
121
- reopt_inputs[:Scenario][:Site][:land_acres] = scenario_report.program.site_area_sqft * 1.0 / 43560 # acres/sqft
122
- end
125
+ if reopt_inputs[:Scenario][:Site][:land_acres].nil? && !scenario_report.program.site_area_sqft.nil?
126
+ reopt_inputs[:Scenario][:Site][:land_acres] = scenario_report.program.site_area_sqft * 1.0 / 43560 # acres/sqft
123
127
  end
124
128
 
125
129
  if reopt_inputs[:Scenario][:time_steps_per_hour].nil?
@@ -130,17 +134,17 @@ module URBANopt # :nodoc:
130
134
  begin
131
135
  col_num = scenario_report.timeseries_csv.column_names.index('Electricity:Facility(kWh)')
132
136
  t = CSV.read(scenario_report.timeseries_csv.path, headers: true, converters: :numeric)
133
- energy_timeseries_kw = t.by_col[col_num].map { |e| ((e * scenario_report.timesteps_per_hour || 0) ) }
137
+ energy_timeseries_kw = t.by_col[col_num].map { |e| ((e * scenario_report.timesteps_per_hour || 0)) }
134
138
  if energy_timeseries_kw.length < (scenario_report.timesteps_per_hour * 8760)
135
- start_date = Time.parse(t.by_col["Datetime"][0])
139
+ start_date = Time.parse(t.by_col['Datetime'][0])
136
140
  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) / \
137
- (( 60 / scenario_report.timesteps_per_hour ) * 60)).to_int
138
- end_date = Time.parse(t.by_col["Datetime"][-1])
141
+ ((60 / scenario_report.timesteps_per_hour) * 60)).to_int
142
+ end_date = Time.parse(t.by_col['Datetime'][-1])
139
143
  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) / \
140
- (( 60 / scenario_report.timesteps_per_hour ) * 60)).to_int
141
- energy_timeseries_kw = [0.0]*(start_ts-1) + energy_timeseries_kw + [0.0]*((scenario_report.timesteps_per_hour * 8760) - end_ts)
144
+ ((60 / scenario_report.timesteps_per_hour) * 60)).to_int
145
+ energy_timeseries_kw = [0.0] * (start_ts - 1) + energy_timeseries_kw + [0.0] * ((scenario_report.timesteps_per_hour * 8760) - end_ts)
142
146
  end
143
- energy_timeseries_kw = energy_timeseries_kw.map { |e| e ? e : 0 }[0,(scenario_report.timesteps_per_hour * 8760)]
147
+ energy_timeseries_kw = energy_timeseries_kw.map { |e| e || 0 }[0, (scenario_report.timesteps_per_hour * 8760)]
144
148
  rescue StandardError
145
149
  @@logger.error("Could not parse the annual electric load from the timeseries csv - #{scenario_report.timeseries_csv.path}")
146
150
  raise "Could not parse the annual electric load from the timeseries csv - #{scenario_report.timeseries_csv.path}"
@@ -149,7 +153,7 @@ module URBANopt # :nodoc:
149
153
  # Convert load to REopt Resolution
150
154
  begin
151
155
  reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw] = convert_powerflow_resolution(energy_timeseries_kw, scenario_report.timesteps_per_hour, reopt_inputs[:Scenario][:time_steps_per_hour])
152
- rescue
156
+ rescue StandardError
153
157
  @@logger.error("Could not convert the annual electric load from a resolution of #{scenario_report.timesteps_per_hour} to #{reopt_inputs[:Scenario][:time_steps_per_hour]}")
154
158
  raise "Could not convert the annual electric load from a resolution of #{scenario_report.timesteps_per_hour} to #{reopt_inputs[:Scenario][:time_steps_per_hour]}"
155
159
  end
@@ -157,9 +161,9 @@ module URBANopt # :nodoc:
157
161
  if reopt_inputs[:Scenario][:Site][:ElectricTariff][:coincident_peak_load_active_timesteps].nil?
158
162
  n_top_values = 100
159
163
  tmp1 = reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw]
160
- tmp2 = tmp1.each_index.max_by(n_top_values*reopt_inputs[:Scenario][:time_steps_per_hour]){|i| tmp1[i]}
164
+ tmp2 = tmp1.each_index.max_by(n_top_values * reopt_inputs[:Scenario][:time_steps_per_hour]) { |i| tmp1[i] }
161
165
  for i in (0...tmp2.count)
162
- tmp2[i] += 1
166
+ tmp2[i] += 1
163
167
  end
164
168
  reopt_inputs[:Scenario][:Site][:ElectricTariff][:coincident_peak_load_active_timesteps] = tmp2
165
169
  end
@@ -171,7 +175,6 @@ module URBANopt # :nodoc:
171
175
  return reopt_inputs
172
176
  end
173
177
 
174
-
175
178
  ##
176
179
  # Converts a FeatureReport list from a ScenarioReport into an array of \REopt Lite posts
177
180
  #
@@ -205,32 +208,12 @@ module URBANopt # :nodoc:
205
208
  #
206
209
  # [*return:*] _URBANopt::Reporting::DefaultReports::ScenarioReport_ - Returns an updated ScenarioReport
207
210
  ##
208
- def update_scenario_report(scenario_report, reopt_output, timeseries_csv_path=nil, resilience_stats=nil)
211
+ def update_scenario_report(scenario_report, reopt_output, timeseries_csv_path = nil, resilience_stats = nil)
209
212
  if reopt_output['outputs']['Scenario']['status'] != 'optimal'
210
213
  @@logger.info("Warning cannot Feature Report #{scenario_report.name} #{scenario_report.id} - REopt optimization was non-optimal")
211
214
  return scenario_report
212
215
  end
213
216
 
214
- $ts_per_hour = scenario_report.timesteps_per_hour
215
- def scale_timeseries(input, ts_per_hr=$ts_per_hour)
216
- if input.nil?
217
- return nil
218
- end
219
- if input.length ==0
220
- return nil
221
- end
222
- if input.length == (8760 * ts_per_hr)
223
- return input
224
- end
225
- result = []
226
- input.each do |val|
227
- (1..ts_per_hr).each do |x|
228
- result.push(val/ts_per_hr.to_f)
229
- end
230
- end
231
- return result
232
- end
233
-
234
217
  # Update location
235
218
  scenario_report.location.latitude_deg = reopt_output['inputs']['Scenario']['Site']['latitude']
236
219
  scenario_report.location.longitude_deg = reopt_output['inputs']['Scenario']['Site']['longitude']
@@ -255,59 +238,49 @@ module URBANopt # :nodoc:
255
238
  scenario_report.distributed_generation.resilience_hours_avg = resilience_stats['resilience_hours_avg']
256
239
  scenario_report.distributed_generation.probs_of_surviving = resilience_stats['probs_of_surviving']
257
240
  scenario_report.distributed_generation.probs_of_surviving_by_month = resilience_stats['probs_of_surviving_by_month']
258
- scenario_report.distributed_generation.probs_of_surviving_by_hour_of_the_day = resilience_stats['probs_of_surviving_by_hour_of_the_day']
241
+ scenario_report.distributed_generation.probs_of_surviving_by_hour_of_the_day = resilience_stats['probs_of_surviving_by_hour_of_the_day']
259
242
  end
260
243
 
261
- if reopt_output['outputs']['Scenario']['Site']['PV'].class == Hash
244
+ if reopt_output['outputs']['Scenario']['Site']['PV'].instance_of?(Hash)
262
245
  reopt_output['outputs']['Scenario']['Site']['PV'] = [reopt_output['outputs']['Scenario']['Site']['PV']]
263
246
  elsif reopt_output['outputs']['Scenario']['Site']['PV'].nil?
264
247
  reopt_output['outputs']['Scenario']['Site']['PV'] = []
265
248
  end
266
249
 
267
250
  reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
268
- scenario_report.distributed_generation.add_tech 'solar_pv', URBANopt::Reporting::DefaultReports::SolarPV.new( {size_kw: (pv['size_kw'] || 0), id: i })
251
+ scenario_report.distributed_generation.add_tech 'solar_pv', URBANopt::Reporting::DefaultReports::SolarPV.new({ size_kw: (pv['size_kw'] || 0), id: i })
269
252
  end
270
253
 
271
254
  wind = reopt_output['outputs']['Scenario']['Site']['Wind']
272
- if !wind['size_kw'].nil? and wind['size_kw'] != 0
273
- scenario_report.distributed_generation.add_tech 'wind', URBANopt::Reporting::DefaultReports::Wind.new( {size_kw: (wind['size_kw'] || 0) })
255
+ if !wind['size_kw'].nil? && (wind['size_kw'] != 0)
256
+ scenario_report.distributed_generation.add_tech 'wind', URBANopt::Reporting::DefaultReports::Wind.new({ size_kw: (wind['size_kw'] || 0) })
274
257
  end
275
258
 
276
259
  generator = reopt_output['outputs']['Scenario']['Site']['Generator']
277
- if !generator['size_kw'].nil? and generator['size_kw'] != 0
278
- scenario_report.distributed_generation.add_tech 'generator', URBANopt::Reporting::DefaultReports::Generator.new( {size_kw: (generator['size_kw'] || 0) })
260
+ if !generator['size_kw'].nil? && (generator['size_kw'] != 0)
261
+ scenario_report.distributed_generation.add_tech 'generator', URBANopt::Reporting::DefaultReports::Generator.new({ size_kw: (generator['size_kw'] || 0) })
279
262
  end
280
263
 
281
264
  storage = reopt_output['outputs']['Scenario']['Site']['Storage']
282
- if !storage['size_kw'].nil? and storage['size_kw'] != 0
283
- scenario_report.distributed_generation.add_tech 'storage', URBANopt::Reporting::DefaultReports::Storage.new( {size_kwh: (storage['size_kwh'] || 0), size_kw: (storage['size_kw'] || 0) })
265
+ if !storage['size_kw'].nil? && (storage['size_kw'] != 0)
266
+ scenario_report.distributed_generation.add_tech 'storage', URBANopt::Reporting::DefaultReports::Storage.new({ size_kwh: (storage['size_kwh'] || 0), size_kw: (storage['size_kw'] || 0) })
284
267
  end
285
-
268
+
286
269
  reopt_resolution = reopt_output['inputs']['Scenario']['time_steps_per_hour']
287
270
  generation_timeseries_kwh = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
288
-
271
+
289
272
  reopt_output['outputs']['Scenario']['Site']['PV'].each do |pv|
290
- if (pv['size_kw'] || 0) > 0
291
- if !pv['year_one_power_production_series_kw'].nil?
292
- generation_timeseries_kwh += Matrix[convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)]
293
- end
273
+ if (pv['size_kw'] || 0) > 0 && !pv['year_one_power_production_series_kw'].nil?
274
+ generation_timeseries_kwh += Matrix[convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)]
294
275
  end
295
- end
276
+ end
296
277
 
297
- unless reopt_output['outputs']['Scenario']['Site']['Wind'].nil?
298
- if (reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) > 0
299
- if !reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'].nil?
300
- generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)]
301
- end
302
- end
278
+ if !reopt_output['outputs']['Scenario']['Site']['Wind'].nil? && ((reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) > 0) && !reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'].nil?
279
+ generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)]
303
280
  end
304
281
 
305
- unless reopt_output['outputs']['Scenario']['Site']['Generator'].nil?
306
- if (reopt_output['outputs']['Scenario']['Site']['Generator']['size_kw'] || 0) > 0
307
- if !reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'].nil?
308
- generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)]
309
- end
310
- end
282
+ if !reopt_output['outputs']['Scenario']['Site']['Generator'].nil? && ((reopt_output['outputs']['Scenario']['Site']['Generator']['size_kw'] || 0) > 0) && !reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'].nil?
283
+ generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)]
311
284
  end
312
285
 
313
286
  $generation_timeseries_kwh = generation_timeseries_kwh.to_a[0] || [0] * (8760 * scenario_report.timesteps_per_hour)
@@ -317,70 +290,70 @@ module URBANopt # :nodoc:
317
290
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Total(kw)')
318
291
  end
319
292
 
320
- $load = scale_timeseries(convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['LoadProfile']['year_one_electric_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)
293
+ $load = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['LoadProfile']['year_one_electric_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
321
294
  $load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Load:Total(kw)')
322
295
  if $load_col.nil?
323
296
  $load_col = scenario_report.timeseries_csv.column_names.length
324
297
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Load:Total(kw)')
325
298
  end
326
299
 
327
- $utility_to_load = scale_timeseries(convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)
300
+ $utility_to_load = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
328
301
  $utility_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToLoad(kw)')
329
302
  if $utility_to_load_col.nil?
330
303
  $utility_to_load_col = scenario_report.timeseries_csv.column_names.length
331
304
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToLoad(kw)')
332
305
  end
333
306
 
334
- $utility_to_battery = scale_timeseries(convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_battery_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)
307
+ $utility_to_battery = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_battery_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
335
308
  $utility_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToBattery(kw)')
336
309
  if $utility_to_battery_col.nil?
337
310
  $utility_to_battery_col = scenario_report.timeseries_csv.column_names.length
338
311
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToBattery(kw)')
339
312
  end
340
313
 
341
- $storage_to_load = scale_timeseries(convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)
314
+ $storage_to_load = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
342
315
  $storage_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToLoad(kw)')
343
316
  if $storage_to_load_col.nil?
344
317
  $storage_to_load_col = scenario_report.timeseries_csv.column_names.length
345
318
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToLoad(kw)')
346
319
  end
347
320
 
348
- $storage_to_grid = scale_timeseries(convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)
321
+ $storage_to_grid = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
349
322
  $storage_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToGrid(kw)')
350
323
  if $storage_to_grid_col.nil?
351
324
  $storage_to_grid_col = scenario_report.timeseries_csv.column_names.length
352
325
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToGrid(kw)')
353
326
  end
354
327
 
355
- $storage_soc = scale_timeseries(convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)
328
+ $storage_soc = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
356
329
  $storage_soc_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:StateOfCharge(pct)')
357
330
  if $storage_soc_col.nil?
358
331
  $storage_soc_col = scenario_report.timeseries_csv.column_names.length
359
332
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:StateOfCharge(pct)')
360
333
  end
361
334
 
362
- $generator_total = scale_timeseries(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)
335
+ $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)
363
336
  $generator_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:Total(kw)')
364
337
  if $generator_total_col.nil?
365
338
  $generator_total_col = scenario_report.timeseries_csv.column_names.length
366
339
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:Total(kw)')
367
340
  end
368
341
 
369
- $generator_to_battery = scale_timeseries(convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_battery_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)
342
+ $generator_to_battery = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_battery_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
370
343
  $generator_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToBattery(kw)')
371
344
  if $generator_to_battery_col.nil?
372
345
  $generator_to_battery_col = scenario_report.timeseries_csv.column_names.length
373
346
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToBattery(kw)')
374
347
  end
375
348
 
376
- $generator_to_load = scale_timeseries(convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)
349
+ $generator_to_load = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
377
350
  $generator_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToLoad(kw)')
378
351
  if $generator_to_load_col.nil?
379
352
  $generator_to_load_col = scenario_report.timeseries_csv.column_names.length
380
353
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToLoad(kw)')
381
354
  end
382
355
 
383
- $generator_to_grid = scale_timeseries(convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_grid_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)
356
+ $generator_to_grid = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_grid_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
384
357
  $generator_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToGrid(kw)')
385
358
  if $generator_to_grid_col.nil?
386
359
  $generator_to_grid_col = scenario_report.timeseries_csv.column_names.length
@@ -418,10 +391,10 @@ module URBANopt # :nodoc:
418
391
 
419
392
  reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
420
393
  if (pv['size_kw'] || 0) > 0
421
- $pv_total += Matrix[scale_timeseries(convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)]
422
- $pv_to_battery += Matrix[scale_timeseries(convert_powerflow_resolution(pv['year_one_to_battery_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)]
423
- $pv_to_load += Matrix[scale_timeseries(convert_powerflow_resolution(pv['year_one_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)]
424
- $pv_to_grid += Matrix[scale_timeseries(convert_powerflow_resolution(pv['year_one_to_grid_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)]
394
+ $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)]
395
+ $pv_to_battery += Matrix[convert_powerflow_resolution(pv['year_one_to_battery_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)]
396
+ $pv_to_load += Matrix[convert_powerflow_resolution(pv['year_one_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)]
397
+ $pv_to_grid += Matrix[convert_powerflow_resolution(pv['year_one_to_grid_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)]
425
398
  end
426
399
  end
427
400
 
@@ -430,28 +403,28 @@ module URBANopt # :nodoc:
430
403
  $pv_to_load = $pv_to_load.to_a[0]
431
404
  $pv_to_grid = $pv_to_grid.to_a[0]
432
405
 
433
- $wind_total = scale_timeseries(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)
406
+ $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)
434
407
  $wind_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:Total(kw)')
435
408
  if $wind_total_col.nil?
436
409
  $wind_total_col = scenario_report.timeseries_csv.column_names.length
437
410
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:Total(kw)')
438
411
  end
439
412
 
440
- $wind_to_battery = scale_timeseries(convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_battery_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)
413
+ $wind_to_battery = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_battery_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
441
414
  $wind_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToBattery(kw)')
442
415
  if $wind_to_battery_col.nil?
443
416
  $wind_to_battery_col = scenario_report.timeseries_csv.column_names.length
444
417
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToBattery(kw)')
445
418
  end
446
419
 
447
- $wind_to_load = scale_timeseries(convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)
420
+ $wind_to_load = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_load_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
448
421
  $wind_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToLoad(kw)')
449
422
  if $wind_to_load_col.nil?
450
423
  $wind_to_load_col = scenario_report.timeseries_csv.column_names.length
451
424
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToLoad(kw)')
452
425
  end
453
426
 
454
- $wind_to_grid = scale_timeseries(convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_grid_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)) || [0] * (8760 * scenario_report.timesteps_per_hour)
427
+ $wind_to_grid = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_grid_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour) || [0] * (8760 * scenario_report.timesteps_per_hour)
455
428
  $wind_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToGrid(kw)')
456
429
  if $wind_to_grid_col.nil?
457
430
  $wind_to_grid_col = scenario_report.timeseries_csv.column_names.length
@@ -482,17 +455,22 @@ module URBANopt # :nodoc:
482
455
  end
483
456
 
484
457
  old_data = CSV.open(scenario_report.timeseries_csv.path).read
485
- start_date = Time.parse(old_data[1][0])
486
- 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
458
+ start_date = Time.parse(old_data[1][0]) # Time is the end of the timestep
459
+ start_ts = (
460
+ (
461
+ ((start_date.yday - 1) * 60.0 * 60.0 * 24) +
462
+ ((start_date.hour - 1) * 60.0 * 60.0) +
463
+ (start_date.min * 60.0) + start_date.sec) /
464
+ ((60 / scenario_report.timesteps_per_hour) * 60)
465
+ ).to_int
487
466
  mod_data = old_data.map.with_index do |x, i|
488
467
  if i > 0
489
- modrow(x, start_ts + i -2)
468
+ modrow(x, start_ts + i - 1)
490
469
  else
491
470
  x
492
471
  end
493
472
  end
494
473
  mod_data[0] = scenario_report.timeseries_csv.column_names
495
-
496
474
  scenario_report.timeseries_csv.reload_data(mod_data)
497
475
  return scenario_report
498
476
  end