urbanopt-reopt 0.5.0 → 0.6.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,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.
@@ -165,7 +175,7 @@ module URBANopt # :nodoc:
165
175
  # [*return:*] _Bool_ - Returns true if the post succeeeds. Otherwise returns false.
166
176
  ##
167
177
  def resilience_request(run_uuid, filename)
168
-
178
+
169
179
  if File.directory? filename
170
180
  if run_uuid.nil?
171
181
  run_uuid = 'error'
@@ -176,7 +186,7 @@ module URBANopt # :nodoc:
176
186
  filename = File.join(filename, "#{run_uuid}_resilience.json")
177
187
  @@logger.info("REopt results saved to #{filename}")
178
188
  end
179
-
189
+
180
190
  #Submit Job
181
191
  @@logger.info("Submitting Resilience Statistics job for #{run_uuid}")
182
192
  header = { 'Content-Type' => 'application/json' }
@@ -197,17 +207,17 @@ module URBANopt # :nodoc:
197
207
  end
198
208
 
199
209
  elapsed_time = 0
200
- max_elapsed_time = 60
201
-
210
+ max_elapsed_time = 60 * 5
211
+
202
212
  request = Net::HTTP::Get.new(uri.request_uri)
203
213
  response = make_request(http, request)
204
-
214
+
205
215
  while (elapsed_time < max_elapsed_time) & (response.code == "404")
206
216
  response = make_request(http, request)
207
- elapsed_time += 5
217
+ elapsed_time += 5
208
218
  sleep 5
209
219
  end
210
-
220
+
211
221
  data = JSON.parse(response.body)
212
222
  text = ::JSON.generate(data, allow_nan: true)
213
223
  begin
@@ -222,7 +232,9 @@ module URBANopt # :nodoc:
222
232
  return data
223
233
  end
224
234
 
225
- raise "Error from REopt API - #{data['Error']}"
235
+ @@logger.info("Error from REopt API - #{data['Error']}")
236
+ return {}
237
+
226
238
  end
227
239
 
228
240
  ##
@@ -290,14 +302,14 @@ module URBANopt # :nodoc:
290
302
 
291
303
  while status == 'Optimizing...'
292
304
  response = make_request(http, request)
293
-
305
+
294
306
  data = JSON.parse(response.body, allow_nan:true)
295
307
 
296
308
  if data['outputs']['Scenario']['Site']['PV'].kind_of?(Array)
297
309
  pv_sizes = 0
298
310
  data['outputs']['Scenario']['Site']['PV'].each do |x|
299
311
  pv_sizes = pv_sizes + x['size_kw'].to_f
300
- end
312
+ end
301
313
  else
302
314
  pv_sizes = data['outputs']['Scenario']['Site']['PV']['size_kw'] || 0
303
315
  end
@@ -318,7 +330,7 @@ module URBANopt # :nodoc:
318
330
  pv_sizes = 0
319
331
  data['outputs']['Scenario']['Site']['PV'].each do |x|
320
332
  pv_sizes = pv_sizes + x['size_kw'].to_f
321
- end
333
+ end
322
334
  else
323
335
  pv_sizes = data['outputs']['Scenario']['Site']['PV']['size_kw'] || 0
324
336
  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.
@@ -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.
@@ -140,8 +150,7 @@ module URBANopt # :nodoc:
140
150
  end
141
151
  result = adapter.update_feature_report(feature_report, reopt_output, timeseries_csv_path, resilience_stats)
142
152
  if !save_name.nil?
143
- #result.save_feature_report save_name
144
- result.save_json_report(save_name)
153
+ result.save save_name
145
154
  end
146
155
  return result
147
156
  end
@@ -251,8 +260,7 @@ module URBANopt # :nodoc:
251
260
  new_feature_reports.push(new_feature_report)
252
261
  if !save_names.nil?
253
262
  if save_names.length == feature_reports.length
254
- #new_feature_report.save_feature_report save_names[idx]
255
- new_feature_report.save_json_report save_names[idx]
263
+ new_feature_report.save save_names[idx]
256
264
  else
257
265
  warn "Could not save feature reports - the number of save names provided did not match the number of feature reports"
258
266
  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.
@@ -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.
@@ -33,6 +43,7 @@ require 'urbanopt/reopt/reopt_logger'
33
43
  require 'matrix'
34
44
  require 'csv'
35
45
  require 'time'
46
+ require_relative 'utilities'
36
47
 
37
48
  module URBANopt # :nodoc:
38
49
  module REopt # :nodoc:
@@ -93,7 +104,6 @@ module URBANopt # :nodoc:
93
104
  requireds_names = ['latitude', 'longitude']
94
105
  requireds = [scenario_report.location.latitude_deg, scenario_report.location.longitude_deg]
95
106
 
96
-
97
107
  if requireds.include?(nil) || requireds.include?(0)
98
108
  requireds.each_with_index do |x, i|
99
109
  if [nil].include? x
@@ -110,16 +120,20 @@ module URBANopt # :nodoc:
110
120
 
111
121
  # Update optional info
112
122
  # REK: attribute names should be updated
113
- if !scenario_report.program.roof_area_sqft.nil?
114
- reopt_inputs[:Scenario][:Site][:roof_squarefeet] = scenario_report.program.roof_area_sqft[:available_roof_area]
123
+ if reopt_inputs[:Scenario][:Site][:roof_squarefeet].nil?
124
+ if !scenario_report.program.roof_area_sqft.nil?
125
+ reopt_inputs[:Scenario][:Site][:roof_squarefeet] = scenario_report.program.roof_area_sqft[:available_roof_area_sqft]
126
+ end
115
127
  end
116
128
 
117
- if !scenario_report.program.site_area_sqft.nil?
118
- reopt_inputs[:Scenario][:Site][:land_acres] = scenario_report.program.site_area_sqft * 1.0 / 43560 # acres/sqft
129
+ if reopt_inputs[:Scenario][:Site][:land_acres].nil?
130
+ if !scenario_report.program.site_area_sqft.nil?
131
+ reopt_inputs[:Scenario][:Site][:land_acres] = scenario_report.program.site_area_sqft * 1.0 / 43560 # acres/sqft
132
+ end
119
133
  end
120
134
 
121
- unless scenario_report.timesteps_per_hour.nil?
122
- reopt_inputs[:Scenario][:time_steps_per_hour] = scenario_report.timesteps_per_hour
135
+ if reopt_inputs[:Scenario][:time_steps_per_hour].nil?
136
+ reopt_inputs[:Scenario][:time_steps_per_hour] = 1
123
137
  end
124
138
 
125
139
  # Update load profile info
@@ -136,14 +150,38 @@ module URBANopt # :nodoc:
136
150
  (( 60 / scenario_report.timesteps_per_hour ) * 60)).to_int
137
151
  energy_timeseries_kw = [0.0]*(start_ts-1) + energy_timeseries_kw + [0.0]*((scenario_report.timesteps_per_hour * 8760) - end_ts)
138
152
  end
139
- reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw] = energy_timeseries_kw.map { |e| e ? e : 0 }[0,(scenario_report.timesteps_per_hour * 8760)]
153
+ energy_timeseries_kw = energy_timeseries_kw.map { |e| e ? e : 0 }[0,(scenario_report.timesteps_per_hour * 8760)]
140
154
  rescue StandardError
141
155
  @@logger.error("Could not parse the annual electric load from the timeseries csv - #{scenario_report.timeseries_csv.path}")
142
156
  raise "Could not parse the annual electric load from the timeseries csv - #{scenario_report.timeseries_csv.path}"
143
157
  end
158
+
159
+ # Convert load to REopt Resolution
160
+ begin
161
+ 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])
162
+ rescue
163
+ @@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]}")
164
+ 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]}"
165
+ end
166
+
167
+ if reopt_inputs[:Scenario][:Site][:ElectricTariff][:coincident_peak_load_active_timesteps].nil?
168
+ n_top_values = 100
169
+ tmp1 = reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw]
170
+ tmp2 = tmp1.each_index.max_by(n_top_values*reopt_inputs[:Scenario][:time_steps_per_hour]){|i| tmp1[i]}
171
+ for i in (0...tmp2.count)
172
+ tmp2[i] += 1
173
+ end
174
+ reopt_inputs[:Scenario][:Site][:ElectricTariff][:coincident_peak_load_active_timesteps] = tmp2
175
+ end
176
+
177
+ if reopt_inputs[:Scenario][:Site][:ElectricTariff][:coincident_peak_load_charge_us_dollars_per_kw].nil?
178
+ reopt_inputs[:Scenario][:Site][:ElectricTariff][:coincident_peak_load_charge_us_dollars_per_kw] = 0
179
+ end
180
+
144
181
  return reopt_inputs
145
182
  end
146
183
 
184
+
147
185
  ##
148
186
  # Converts a FeatureReport list from a ScenarioReport into an array of \REopt Lite posts
149
187
  #
@@ -183,33 +221,10 @@ module URBANopt # :nodoc:
183
221
  return scenario_report
184
222
  end
185
223
 
186
- $ts_per_hour = scenario_report.timesteps_per_hour
187
- def scale_timeseries(input, ts_per_hr=$ts_per_hour)
188
- if input.nil?
189
- return nil
190
- end
191
- if input.length ==0
192
- return nil
193
- end
194
- if input.length == (8760 * ts_per_hr)
195
- return input
196
- end
197
- result = []
198
- input.each do |val|
199
- (1..ts_per_hr).each do |x|
200
- result.push(val/ts_per_hr.to_f)
201
- end
202
- end
203
- return result
204
- end
205
-
206
224
  # Update location
207
225
  scenario_report.location.latitude_deg = reopt_output['inputs']['Scenario']['Site']['latitude']
208
226
  scenario_report.location.longitude_deg = reopt_output['inputs']['Scenario']['Site']['longitude']
209
227
 
210
- # Update timeseries csv from \REopt Lite dispatch data
211
- scenario_report.timesteps_per_hour = reopt_output['inputs']['Scenario']['time_steps_per_hour']
212
-
213
228
  # Update distributed generation sizing and financials
214
229
 
215
230
  scenario_report.distributed_generation.lcc_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['lcc_us_dollars'] || 0
@@ -230,7 +245,7 @@ module URBANopt # :nodoc:
230
245
  scenario_report.distributed_generation.resilience_hours_avg = resilience_stats['resilience_hours_avg']
231
246
  scenario_report.distributed_generation.probs_of_surviving = resilience_stats['probs_of_surviving']
232
247
  scenario_report.distributed_generation.probs_of_surviving_by_month = resilience_stats['probs_of_surviving_by_month']
233
- scenario_report.distributed_generation.probs_of_surviving_by_hour_of_the_day = resilience_stats['probs_of_surviving_by_hour_of_the_day']
248
+ scenario_report.distributed_generation.probs_of_surviving_by_hour_of_the_day = resilience_stats['probs_of_surviving_by_hour_of_the_day']
234
249
  end
235
250
 
236
251
  if reopt_output['outputs']['Scenario']['Site']['PV'].class == Hash
@@ -258,29 +273,21 @@ module URBANopt # :nodoc:
258
273
  scenario_report.distributed_generation.add_tech 'storage', URBANopt::Reporting::DefaultReports::Storage.new( {size_kwh: (storage['size_kwh'] || 0), size_kw: (storage['size_kw'] || 0) })
259
274
  end
260
275
 
276
+ reopt_resolution = reopt_output['inputs']['Scenario']['time_steps_per_hour']
261
277
  generation_timeseries_kwh = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
262
278
 
263
-
264
279
  reopt_output['outputs']['Scenario']['Site']['PV'].each do |pv|
265
280
  if (pv['size_kw'] || 0) > 0
266
281
  if !pv['year_one_power_production_series_kw'].nil?
267
- generation_timeseries_kwh += Matrix[pv['year_one_power_production_series_kw']]
282
+ generation_timeseries_kwh += Matrix[convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, scenario_report.timesteps_per_hour)]
268
283
  end
269
284
  end
270
285
  end
271
286
 
272
- unless reopt_output['outputs']['Scenario']['Site']['Storage'].nil?
273
- if (reopt_output['outputs']['Scenario']['Site']['Storage']['size_kw'] or 0) > 0
274
- if !reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'].nil?
275
- generation_timeseries_kwh = generation_timeseries_kwh + Matrix[reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']]
276
- end
277
- end
278
- end
279
-
280
287
  unless reopt_output['outputs']['Scenario']['Site']['Wind'].nil?
281
288
  if (reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) > 0
282
289
  if !reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'].nil?
283
- generation_timeseries_kwh += Matrix[reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw']]
290
+ 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)]
284
291
  end
285
292
  end
286
293
  end
@@ -288,7 +295,7 @@ module URBANopt # :nodoc:
288
295
  unless reopt_output['outputs']['Scenario']['Site']['Generator'].nil?
289
296
  if (reopt_output['outputs']['Scenario']['Site']['Generator']['size_kw'] || 0) > 0
290
297
  if !reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'].nil?
291
- generation_timeseries_kwh += Matrix[reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw']]
298
+ 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)]
292
299
  end
293
300
  end
294
301
  end
@@ -300,70 +307,70 @@ module URBANopt # :nodoc:
300
307
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Total(kw)')
301
308
  end
302
309
 
303
- $load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['LoadProfile']['year_one_electric_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
310
+ $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)
304
311
  $load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Load:Total(kw)')
305
312
  if $load_col.nil?
306
313
  $load_col = scenario_report.timeseries_csv.column_names.length
307
314
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Load:Total(kw)')
308
315
  end
309
316
 
310
- $utility_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
317
+ $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)
311
318
  $utility_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToLoad(kw)')
312
319
  if $utility_to_load_col.nil?
313
320
  $utility_to_load_col = scenario_report.timeseries_csv.column_names.length
314
321
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToLoad(kw)')
315
322
  end
316
323
 
317
- $utility_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
324
+ $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)
318
325
  $utility_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToBattery(kw)')
319
326
  if $utility_to_battery_col.nil?
320
327
  $utility_to_battery_col = scenario_report.timeseries_csv.column_names.length
321
328
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToBattery(kw)')
322
329
  end
323
330
 
324
- $storage_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
331
+ $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)
325
332
  $storage_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToLoad(kw)')
326
333
  if $storage_to_load_col.nil?
327
334
  $storage_to_load_col = scenario_report.timeseries_csv.column_names.length
328
335
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToLoad(kw)')
329
336
  end
330
337
 
331
- $storage_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
338
+ $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)
332
339
  $storage_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToGrid(kw)')
333
340
  if $storage_to_grid_col.nil?
334
341
  $storage_to_grid_col = scenario_report.timeseries_csv.column_names.length
335
342
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToGrid(kw)')
336
343
  end
337
344
 
338
- $storage_soc = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct']) || [0] * (8760 * scenario_report.timesteps_per_hour)
345
+ $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)
339
346
  $storage_soc_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:StateOfCharge(pct)')
340
347
  if $storage_soc_col.nil?
341
348
  $storage_soc_col = scenario_report.timeseries_csv.column_names.length
342
349
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:StateOfCharge(pct)')
343
350
  end
344
351
 
345
- $generator_total = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
352
+ $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)
346
353
  $generator_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:Total(kw)')
347
354
  if $generator_total_col.nil?
348
355
  $generator_total_col = scenario_report.timeseries_csv.column_names.length
349
356
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:Total(kw)')
350
357
  end
351
358
 
352
- $generator_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
359
+ $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)
353
360
  $generator_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToBattery(kw)')
354
361
  if $generator_to_battery_col.nil?
355
362
  $generator_to_battery_col = scenario_report.timeseries_csv.column_names.length
356
363
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToBattery(kw)')
357
364
  end
358
365
 
359
- $generator_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
366
+ $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)
360
367
  $generator_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToLoad(kw)')
361
368
  if $generator_to_load_col.nil?
362
369
  $generator_to_load_col = scenario_report.timeseries_csv.column_names.length
363
370
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToLoad(kw)')
364
371
  end
365
372
 
366
- $generator_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
373
+ $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)
367
374
  $generator_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToGrid(kw)')
368
375
  if $generator_to_grid_col.nil?
369
376
  $generator_to_grid_col = scenario_report.timeseries_csv.column_names.length
@@ -401,10 +408,10 @@ module URBANopt # :nodoc:
401
408
 
402
409
  reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
403
410
  if (pv['size_kw'] || 0) > 0
404
- $pv_total += Matrix[scale_timeseries(pv['year_one_power_production_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
405
- $pv_to_battery += Matrix[scale_timeseries(pv['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
406
- $pv_to_load += Matrix[scale_timeseries(pv['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
407
- $pv_to_grid += Matrix[scale_timeseries(pv['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
411
+ $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)]
412
+ $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)]
413
+ $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)]
414
+ $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)]
408
415
  end
409
416
  end
410
417
 
@@ -413,28 +420,28 @@ module URBANopt # :nodoc:
413
420
  $pv_to_load = $pv_to_load.to_a[0]
414
421
  $pv_to_grid = $pv_to_grid.to_a[0]
415
422
 
416
- $wind_total = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
423
+ $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)
417
424
  $wind_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:Total(kw)')
418
425
  if $wind_total_col.nil?
419
426
  $wind_total_col = scenario_report.timeseries_csv.column_names.length
420
427
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:Total(kw)')
421
428
  end
422
429
 
423
- $wind_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
430
+ $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)
424
431
  $wind_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToBattery(kw)')
425
432
  if $wind_to_battery_col.nil?
426
433
  $wind_to_battery_col = scenario_report.timeseries_csv.column_names.length
427
434
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToBattery(kw)')
428
435
  end
429
436
 
430
- $wind_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
437
+ $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)
431
438
  $wind_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToLoad(kw)')
432
439
  if $wind_to_load_col.nil?
433
440
  $wind_to_load_col = scenario_report.timeseries_csv.column_names.length
434
441
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToLoad(kw)')
435
442
  end
436
443
 
437
- $wind_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
444
+ $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)
438
445
  $wind_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToGrid(kw)')
439
446
  if $wind_to_grid_col.nil?
440
447
  $wind_to_grid_col = scenario_report.timeseries_csv.column_names.length
@@ -465,17 +472,22 @@ module URBANopt # :nodoc:
465
472
  end
466
473
 
467
474
  old_data = CSV.open(scenario_report.timeseries_csv.path).read
468
- start_date = Time.parse(old_data[1][0])
469
- 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
475
+ start_date = Time.parse(old_data[1][0]) # Time is the end of the timestep
476
+ start_ts = (
477
+ (
478
+ ((start_date.yday - 1) * 60.0 * 60.0 * 24) +
479
+ (((start_date.hour) - 1) * 60.0 * 60.0) +
480
+ (start_date.min * 60.0) + start_date.sec ) /
481
+ (( 60 / scenario_report.timesteps_per_hour ) * 60)
482
+ ).to_int
470
483
  mod_data = old_data.map.with_index do |x, i|
471
484
  if i > 0
472
- modrow(x, start_ts + i -2)
485
+ modrow(x, start_ts + i -1)
473
486
  else
474
487
  x
475
488
  end
476
489
  end
477
490
  mod_data[0] = scenario_report.timeseries_csv.column_names
478
-
479
491
  scenario_report.timeseries_csv.reload_data(mod_data)
480
492
  return scenario_report
481
493
  end