urbanopt-reopt 0.4.0 → 0.5.6

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