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