urbanopt-reopt 0.5.4 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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