urbanopt-reopt 0.4.0 → 0.5.6

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.
@@ -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.
@@ -31,7 +41,6 @@
31
41
  require 'bundler/setup'
32
42
  require 'urbanopt/reporting/default_reports'
33
43
  require 'urbanopt/reopt/reopt_logger'
34
- require 'urbanopt/reopt'
35
44
  require 'csv'
36
45
 
37
46
  module URBANopt # :nodoc:
@@ -141,7 +150,8 @@ module URBANopt # :nodoc:
141
150
  end
142
151
  result = adapter.update_feature_report(feature_report, reopt_output, timeseries_csv_path, resilience_stats)
143
152
  if !save_name.nil?
144
- result.save_feature_report save_name
153
+ #result.save_feature_report save_name
154
+ result.save_json_report(save_name)
145
155
  end
146
156
  return result
147
157
  end
@@ -251,7 +261,8 @@ module URBANopt # :nodoc:
251
261
  new_feature_reports.push(new_feature_report)
252
262
  if !save_names.nil?
253
263
  if save_names.length == feature_reports.length
254
- new_feature_report.save_feature_report save_names[idx]
264
+ #new_feature_report.save_feature_report save_names[idx]
265
+ new_feature_report.save_json_report save_names[idx]
255
266
  else
256
267
  warn "Could not save feature reports - the number of save names provided did not match the number of feature reports"
257
268
  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:
@@ -70,31 +81,32 @@ module URBANopt # :nodoc:
70
81
  end
71
82
 
72
83
  # Update required info
73
- if scenario_report.location.latitude.nil? || scenario_report.location.longitude.nil? || (scenario_report.location.latitude == 0) || (scenario_report.location.longitude == 0)
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)
74
85
  if !scenario_report.feature_reports.nil? && (scenario_report.feature_reports != [])
75
86
  lats = []
76
87
  longs = []
77
88
  scenario_report.feature_reports.each do |x|
78
- if ![nil, 0].include?(x[:location][:latitude]) && ![nil, 0].include?(x[:location][:longitude])
79
- lats.push(x[:location][:latitude])
80
- longs.push(x[:location][:longitude])
89
+ puts " ERROR: #{x.location.latitude_deg}"
90
+ if ![nil].include?(x.location.latitude_deg) && ![nil].include?(x.location.longitude_deg)
91
+ lats.push(x.location.latitude_deg)
92
+ longs.push(x.location.longitude_deg)
81
93
  end
82
94
  end
83
95
 
84
96
  if !lats.empty? && !longs.empty?
85
- scenario_report.location.latitude = lats.reduce(:+) / lats.size.to_f
86
- scenario_report.location.longitude = longs.reduce(:+) / longs.size.to_f
97
+ scenario_report.location.latitude_deg = lats.reduce(:+) / lats.size.to_f
98
+ scenario_report.location.longitude_deg = longs.reduce(:+) / longs.size.to_f
87
99
  end
88
100
  end
89
101
  end
90
102
 
91
103
  # Update required info
92
104
  requireds_names = ['latitude', 'longitude']
93
- requireds = [scenario_report.location.latitude, scenario_report.location.longitude]
105
+ requireds = [scenario_report.location.latitude_deg, scenario_report.location.longitude_deg]
94
106
 
95
107
  if requireds.include?(nil) || requireds.include?(0)
96
- requireds.each_with_index do |i, x|
97
- if [nil, 0].include? x
108
+ requireds.each_with_index do |x, i|
109
+ if [nil].include? x
98
110
  n = requireds_names[i]
99
111
  raise "Missing value for #{n} - this is a required input"
100
112
  end
@@ -103,20 +115,25 @@ module URBANopt # :nodoc:
103
115
 
104
116
  reopt_inputs[:Scenario][:description] = description
105
117
 
106
- reopt_inputs[:Scenario][:Site][:latitude] = scenario_report.location.latitude
107
- reopt_inputs[:Scenario][:Site][:longitude] = scenario_report.location.longitude
118
+ reopt_inputs[:Scenario][:Site][:latitude] = scenario_report.location.latitude_deg
119
+ reopt_inputs[:Scenario][:Site][:longitude] = scenario_report.location.longitude_deg
108
120
 
109
121
  # Update optional info
110
- if !scenario_report.program.roof_area.nil?
111
- reopt_inputs[:Scenario][:Site][:roof_squarefeet] = scenario_report.program.roof_area[:available_roof_area]
122
+ # REK: attribute names should be updated
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
112
127
  end
113
128
 
114
- if !scenario_report.program.site_area.nil?
115
- reopt_inputs[:Scenario][:Site][:land_acres] = scenario_report.program.site_area * 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
116
133
  end
117
134
 
118
- unless scenario_report.timesteps_per_hour.nil?
119
- 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
120
137
  end
121
138
 
122
139
  # Update load profile info
@@ -133,14 +150,38 @@ module URBANopt # :nodoc:
133
150
  (( 60 / scenario_report.timesteps_per_hour ) * 60)).to_int
134
151
  energy_timeseries_kw = [0.0]*(start_ts-1) + energy_timeseries_kw + [0.0]*((scenario_report.timesteps_per_hour * 8760) - end_ts)
135
152
  end
136
- 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)]
137
154
  rescue StandardError
138
155
  @@logger.error("Could not parse the annual electric load from the timeseries csv - #{scenario_report.timeseries_csv.path}")
139
156
  raise "Could not parse the annual electric load from the timeseries csv - #{scenario_report.timeseries_csv.path}"
140
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
+
141
181
  return reopt_inputs
142
182
  end
143
183
 
184
+
144
185
  ##
145
186
  # Converts a FeatureReport list from a ScenarioReport into an array of \REopt Lite posts
146
187
  #
@@ -180,32 +221,9 @@ module URBANopt # :nodoc:
180
221
  return scenario_report
181
222
  end
182
223
 
183
- $ts_per_hour = scenario_report.timesteps_per_hour
184
- def scale_timeseries(input, ts_per_hr=$ts_per_hour)
185
- if input.nil?
186
- return nil
187
- end
188
- if input.length ==0
189
- return nil
190
- end
191
- if input.length == (8760 * ts_per_hr)
192
- return input
193
- end
194
- result = []
195
- input.each do |val|
196
- (1..ts_per_hr).each do |x|
197
- result.push(val/ts_per_hr.to_f)
198
- end
199
- end
200
- return result
201
- end
202
-
203
224
  # Update location
204
- scenario_report.location.latitude = reopt_output['inputs']['Scenario']['Site']['latitude']
205
- scenario_report.location.longitude = reopt_output['inputs']['Scenario']['Site']['longitude']
206
-
207
- # Update timeseries csv from \REopt Lite dispatch data
208
- scenario_report.timesteps_per_hour = reopt_output['inputs']['Scenario']['time_steps_per_hour']
225
+ scenario_report.location.latitude_deg = reopt_output['inputs']['Scenario']['Site']['latitude']
226
+ scenario_report.location.longitude_deg = reopt_output['inputs']['Scenario']['Site']['longitude']
209
227
 
210
228
  # Update distributed generation sizing and financials
211
229
 
@@ -227,7 +245,7 @@ module URBANopt # :nodoc:
227
245
  scenario_report.distributed_generation.resilience_hours_avg = resilience_stats['resilience_hours_avg']
228
246
  scenario_report.distributed_generation.probs_of_surviving = resilience_stats['probs_of_surviving']
229
247
  scenario_report.distributed_generation.probs_of_surviving_by_month = resilience_stats['probs_of_surviving_by_month']
230
- scenario_report.distributed_generation.probs_of_surviving_by_hour_of_the_day = resilience_stats['probs_of_surviving_by_hour_of_the_day']
248
+ scenario_report.distributed_generation.probs_of_surviving_by_hour_of_the_day = resilience_stats['probs_of_surviving_by_hour_of_the_day']
231
249
  end
232
250
 
233
251
  if reopt_output['outputs']['Scenario']['Site']['PV'].class == Hash
@@ -255,29 +273,21 @@ module URBANopt # :nodoc:
255
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) })
256
274
  end
257
275
 
276
+ reopt_resolution = reopt_output['inputs']['Scenario']['time_steps_per_hour']
258
277
  generation_timeseries_kwh = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
259
278
 
260
-
261
279
  reopt_output['outputs']['Scenario']['Site']['PV'].each do |pv|
262
280
  if (pv['size_kw'] || 0) > 0
263
281
  if !pv['year_one_power_production_series_kw'].nil?
264
- 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)]
265
283
  end
266
284
  end
267
285
  end
268
286
 
269
- unless reopt_output['outputs']['Scenario']['Site']['Storage'].nil?
270
- if (reopt_output['outputs']['Scenario']['Site']['Storage']['size_kw'] or 0) > 0
271
- if !reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'].nil?
272
- generation_timeseries_kwh = generation_timeseries_kwh + Matrix[reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']]
273
- end
274
- end
275
- end
276
-
277
287
  unless reopt_output['outputs']['Scenario']['Site']['Wind'].nil?
278
288
  if (reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) > 0
279
289
  if !reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'].nil?
280
- 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)]
281
291
  end
282
292
  end
283
293
  end
@@ -285,7 +295,7 @@ module URBANopt # :nodoc:
285
295
  unless reopt_output['outputs']['Scenario']['Site']['Generator'].nil?
286
296
  if (reopt_output['outputs']['Scenario']['Site']['Generator']['size_kw'] || 0) > 0
287
297
  if !reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'].nil?
288
- 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)]
289
299
  end
290
300
  end
291
301
  end
@@ -297,70 +307,70 @@ module URBANopt # :nodoc:
297
307
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Total(kw)')
298
308
  end
299
309
 
300
- $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)
301
311
  $load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Load:Total(kw)')
302
312
  if $load_col.nil?
303
313
  $load_col = scenario_report.timeseries_csv.column_names.length
304
314
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Load:Total(kw)')
305
315
  end
306
316
 
307
- $utility_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
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)
308
318
  $utility_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToLoad(kw)')
309
319
  if $utility_to_load_col.nil?
310
320
  $utility_to_load_col = scenario_report.timeseries_csv.column_names.length
311
321
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToLoad(kw)')
312
322
  end
313
323
 
314
- $utility_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
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)
315
325
  $utility_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToBattery(kw)')
316
326
  if $utility_to_battery_col.nil?
317
327
  $utility_to_battery_col = scenario_report.timeseries_csv.column_names.length
318
328
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToBattery(kw)')
319
329
  end
320
330
 
321
- $storage_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
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)
322
332
  $storage_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToLoad(kw)')
323
333
  if $storage_to_load_col.nil?
324
334
  $storage_to_load_col = scenario_report.timeseries_csv.column_names.length
325
335
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToLoad(kw)')
326
336
  end
327
337
 
328
- $storage_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
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)
329
339
  $storage_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToGrid(kw)')
330
340
  if $storage_to_grid_col.nil?
331
341
  $storage_to_grid_col = scenario_report.timeseries_csv.column_names.length
332
342
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToGrid(kw)')
333
343
  end
334
344
 
335
- $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)
336
346
  $storage_soc_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:StateOfCharge(pct)')
337
347
  if $storage_soc_col.nil?
338
348
  $storage_soc_col = scenario_report.timeseries_csv.column_names.length
339
349
  scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:StateOfCharge(pct)')
340
350
  end
341
351
 
342
- $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)
343
353
  $generator_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:Total(kw)')
344
354
  if $generator_total_col.nil?
345
355
  $generator_total_col = scenario_report.timeseries_csv.column_names.length
346
356
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:Total(kw)')
347
357
  end
348
358
 
349
- $generator_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
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)
350
360
  $generator_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToBattery(kw)')
351
361
  if $generator_to_battery_col.nil?
352
362
  $generator_to_battery_col = scenario_report.timeseries_csv.column_names.length
353
363
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToBattery(kw)')
354
364
  end
355
365
 
356
- $generator_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
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)
357
367
  $generator_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToLoad(kw)')
358
368
  if $generator_to_load_col.nil?
359
369
  $generator_to_load_col = scenario_report.timeseries_csv.column_names.length
360
370
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToLoad(kw)')
361
371
  end
362
372
 
363
- $generator_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
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)
364
374
  $generator_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToGrid(kw)')
365
375
  if $generator_to_grid_col.nil?
366
376
  $generator_to_grid_col = scenario_report.timeseries_csv.column_names.length
@@ -398,10 +408,10 @@ module URBANopt # :nodoc:
398
408
 
399
409
  reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
400
410
  if (pv['size_kw'] || 0) > 0
401
- $pv_total += Matrix[scale_timeseries(pv['year_one_power_production_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
402
- $pv_to_battery += Matrix[scale_timeseries(pv['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
403
- $pv_to_load += Matrix[scale_timeseries(pv['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
404
- $pv_to_grid += Matrix[scale_timeseries(pv['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
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)]
405
415
  end
406
416
  end
407
417
 
@@ -410,28 +420,28 @@ module URBANopt # :nodoc:
410
420
  $pv_to_load = $pv_to_load.to_a[0]
411
421
  $pv_to_grid = $pv_to_grid.to_a[0]
412
422
 
413
- $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)
414
424
  $wind_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:Total(kw)')
415
425
  if $wind_total_col.nil?
416
426
  $wind_total_col = scenario_report.timeseries_csv.column_names.length
417
427
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:Total(kw)')
418
428
  end
419
429
 
420
- $wind_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
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)
421
431
  $wind_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToBattery(kw)')
422
432
  if $wind_to_battery_col.nil?
423
433
  $wind_to_battery_col = scenario_report.timeseries_csv.column_names.length
424
434
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToBattery(kw)')
425
435
  end
426
436
 
427
- $wind_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
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)
428
438
  $wind_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToLoad(kw)')
429
439
  if $wind_to_load_col.nil?
430
440
  $wind_to_load_col = scenario_report.timeseries_csv.column_names.length
431
441
  scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToLoad(kw)')
432
442
  end
433
443
 
434
- $wind_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
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)
435
445
  $wind_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToGrid(kw)')
436
446
  if $wind_to_grid_col.nil?
437
447
  $wind_to_grid_col = scenario_report.timeseries_csv.column_names.length
@@ -462,17 +472,22 @@ module URBANopt # :nodoc:
462
472
  end
463
473
 
464
474
  old_data = CSV.open(scenario_report.timeseries_csv.path).read
465
- start_date = Time.parse(old_data[1][0])
466
- start_ts = (((start_date.yday * 60.0 * 60.0 * 24) + (start_date.hour * 60.0 * 60.0) + (start_date.min * 60.0) + start_date.sec) / (( 60 / scenario_report.timesteps_per_hour ) * 60)).to_int
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
467
483
  mod_data = old_data.map.with_index do |x, i|
468
484
  if i > 0
469
- modrow(x, start_ts + i -2)
485
+ modrow(x, start_ts + i -1)
470
486
  else
471
487
  x
472
488
  end
473
489
  end
474
490
  mod_data[0] = scenario_report.timeseries_csv.column_names
475
-
476
491
  scenario_report.timeseries_csv.reload_data(mod_data)
477
492
  return scenario_report
478
493
  end