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
data/docs/package.json
CHANGED
@@ -10,17 +10,21 @@
|
|
10
10
|
},
|
11
11
|
"author": "NREL",
|
12
12
|
"dependencies": {
|
13
|
-
"braces": "^3.0.2",
|
14
13
|
"highlight.js": "^10.4.1",
|
15
14
|
"json-schema-ref-parser": "^6.1.0",
|
16
15
|
"json-schema-view-js": "git+https://git@github.com/bgschiller/json-schema-view-js.git",
|
17
|
-
"
|
18
|
-
"
|
19
|
-
"webpack-dev-middleware": "^3.6.0",
|
20
|
-
"yargs-parser": "^18.1.1"
|
16
|
+
"vuepress": "^1.8.2",
|
17
|
+
"webpack-dev-middleware": "^3.6.0"
|
21
18
|
},
|
22
19
|
"devDependencies": {
|
20
|
+
"braces": "^3.0.2",
|
21
|
+
"chokidar": ">=3.5.1",
|
22
|
+
"fsevents": ">=2.3.2",
|
23
23
|
"gh-pages": "^2.0.1",
|
24
|
-
"ini": "^2.0.0"
|
24
|
+
"ini": "^2.0.0",
|
25
|
+
"is-svg": "4.3.1",
|
26
|
+
"serialize-javascript": "^5.0.1",
|
27
|
+
"ssri": "8.0.1",
|
28
|
+
"yargs-parser": "^18.1.1"
|
25
29
|
}
|
26
30
|
}
|
data/lib/urbanopt-reopt.rb
CHANGED
@@ -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.
|
data/lib/urbanopt/reopt.rb
CHANGED
@@ -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.
|
@@ -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.
|
@@ -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.
|
@@ -89,16 +99,12 @@ module URBANopt # :nodoc:
|
|
89
99
|
reopt_inputs[:Scenario][:Site][:longitude] = feature_report.location.longitude_deg
|
90
100
|
|
91
101
|
# Parse Optional FeatureReport metrics - do not overwrite from assumptions file
|
92
|
-
if reopt_inputs[:Scenario][:Site][:roof_squarefeet].nil?
|
93
|
-
|
94
|
-
reopt_inputs[:Scenario][:Site][:roof_squarefeet] = feature_report.program.roof_area_sqft[:available_roof_area_sqft]
|
95
|
-
end
|
102
|
+
if reopt_inputs[:Scenario][:Site][:roof_squarefeet].nil? && !feature_report.program.roof_area_sqft.nil?
|
103
|
+
reopt_inputs[:Scenario][:Site][:roof_squarefeet] = feature_report.program.roof_area_sqft[:available_roof_area_sqft]
|
96
104
|
end
|
97
105
|
|
98
|
-
if reopt_inputs[:Scenario][:Site][:land_acres].nil?
|
99
|
-
|
100
|
-
reopt_inputs[:Scenario][:Site][:land_acres] = feature_report.program.site_area_sqft * 1.0 / 43560 # acres/sqft
|
101
|
-
end
|
106
|
+
if reopt_inputs[:Scenario][:Site][:land_acres].nil? && !feature_report.program.site_area_sqft.nil?
|
107
|
+
reopt_inputs[:Scenario][:Site][:land_acres] = feature_report.program.site_area_sqft * 1.0 / 43560 # acres/sqft
|
102
108
|
end
|
103
109
|
|
104
110
|
if reopt_inputs[:Scenario][:time_steps_per_hour].nil?
|
@@ -107,43 +113,42 @@ module URBANopt # :nodoc:
|
|
107
113
|
|
108
114
|
# Parse Load Profile
|
109
115
|
begin
|
110
|
-
#Convert kWh values in the timeseries CSV to kW
|
116
|
+
# Convert kWh values in the timeseries CSV to kW
|
111
117
|
col_num = feature_report.timeseries_csv.column_names.index('Electricity:Facility(kWh)')
|
112
118
|
t = CSV.read(feature_report.timeseries_csv.path, headers: true, converters: :numeric)
|
113
|
-
energy_timeseries_kw = t.by_col[col_num].map { |e| ((e * feature_report.timesteps_per_hour || 0)
|
114
|
-
#Fill in missing timestep values with 0 if a full year is not provided
|
119
|
+
energy_timeseries_kw = t.by_col[col_num].map { |e| ((e * feature_report.timesteps_per_hour || 0)) }
|
120
|
+
# Fill in missing timestep values with 0 if a full year is not provided
|
115
121
|
if energy_timeseries_kw.length < (feature_report.timesteps_per_hour * 8760)
|
116
|
-
start_date = Time.parse(t.by_col[
|
122
|
+
start_date = Time.parse(t.by_col['Datetime'][0])
|
117
123
|
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) /
|
118
|
-
((
|
119
|
-
end_date = Time.parse(t.by_col[
|
124
|
+
((60 / feature_report.timesteps_per_hour) * 60)).to_int
|
125
|
+
end_date = Time.parse(t.by_col['Datetime'][-1])
|
120
126
|
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) /
|
121
|
-
((
|
122
|
-
energy_timeseries_kw = [0.0]*(start_ts-1) + energy_timeseries_kw + [0.0]*((feature_report.timesteps_per_hour * 8760) - end_ts)
|
123
|
-
end
|
124
|
-
#Clip to one non-leap year's worth of data
|
125
|
-
energy_timeseries_kw = energy_timeseries_kw.map { |e| e
|
126
|
-
#Convert from the OpenDSS resolution to the REopt Lite resolution, if necessary
|
127
|
+
((60 / feature_report.timesteps_per_hour) * 60)).to_int
|
128
|
+
energy_timeseries_kw = [0.0] * (start_ts - 1) + energy_timeseries_kw + [0.0] * ((feature_report.timesteps_per_hour * 8760) - end_ts)
|
129
|
+
end
|
130
|
+
# Clip to one non-leap year's worth of data
|
131
|
+
energy_timeseries_kw = energy_timeseries_kw.map { |e| e || 0 }[0, (feature_report.timesteps_per_hour * 8760)]
|
132
|
+
# Convert from the OpenDSS resolution to the REopt Lite resolution, if necessary
|
127
133
|
rescue StandardError
|
128
134
|
@@logger.error("Could not parse the annual electric load from the timeseries csv - #{feature_report.timeseries_csv.path}")
|
129
135
|
raise "Could not parse the annual electric load from the timeseries csv - #{feature_report.timeseries_csv.path}"
|
130
136
|
end
|
131
|
-
|
137
|
+
|
132
138
|
# Convert load to REopt Resolution
|
133
139
|
begin
|
134
140
|
reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw] = convert_powerflow_resolution(energy_timeseries_kw, feature_report.timesteps_per_hour, reopt_inputs[:Scenario][:time_steps_per_hour])
|
135
|
-
|
136
|
-
rescue
|
141
|
+
rescue StandardError
|
137
142
|
@@logger.error("Could not convert the annual electric load from a resolution of #{feature_report.timesteps_per_hour} to #{reopt_inputs[:Scenario][:time_steps_per_hour]}")
|
138
143
|
raise "Could not convert the annual electric load from a resolution of #{feature_report.timesteps_per_hour} to #{reopt_inputs[:Scenario][:time_steps_per_hour]}"
|
139
144
|
end
|
140
|
-
|
145
|
+
|
141
146
|
if reopt_inputs[:Scenario][:Site][:ElectricTariff][:coincident_peak_load_active_timesteps].nil?
|
142
147
|
n_top_values = 100
|
143
148
|
tmp1 = reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw]
|
144
|
-
tmp2 = tmp1.each_index.max_by(n_top_values*reopt_inputs[:Scenario][:time_steps_per_hour]){|i| tmp1[i]}
|
149
|
+
tmp2 = tmp1.each_index.max_by(n_top_values * reopt_inputs[:Scenario][:time_steps_per_hour]) { |i| tmp1[i] }
|
145
150
|
for i in (0...tmp2.count)
|
146
|
-
|
151
|
+
tmp2[i] += 1
|
147
152
|
end
|
148
153
|
reopt_inputs[:Scenario][:Site][:ElectricTariff][:coincident_peak_load_active_timesteps] = tmp2
|
149
154
|
end
|
@@ -151,11 +156,10 @@ module URBANopt # :nodoc:
|
|
151
156
|
if reopt_inputs[:Scenario][:Site][:ElectricTariff][:coincident_peak_load_charge_us_dollars_per_kw].nil?
|
152
157
|
reopt_inputs[:Scenario][:Site][:ElectricTariff][:coincident_peak_load_charge_us_dollars_per_kw] = 0
|
153
158
|
end
|
154
|
-
|
159
|
+
|
155
160
|
return reopt_inputs
|
156
161
|
end
|
157
162
|
|
158
|
-
|
159
163
|
##
|
160
164
|
# Update a FeatureReport from a \REopt Lite response
|
161
165
|
#
|
@@ -167,33 +171,13 @@ module URBANopt # :nodoc:
|
|
167
171
|
#
|
168
172
|
# [*return:*] _URBANopt::Reporting::DefaultReports::FeatureReport_ - Returns an updated FeatureReport.
|
169
173
|
##
|
170
|
-
def update_feature_report(feature_report, reopt_output, timeseries_csv_path=nil, resilience_stats=nil)
|
174
|
+
def update_feature_report(feature_report, reopt_output, timeseries_csv_path = nil, resilience_stats = nil)
|
171
175
|
# Check if the \REopt Lite response is valid
|
172
176
|
if reopt_output['outputs']['Scenario']['status'] != 'optimal'
|
173
177
|
@@logger.info("Warning cannot Feature Report #{feature_report.name} #{feature_report.id} - REopt optimization was non-optimal")
|
174
178
|
return feature_report
|
175
179
|
end
|
176
180
|
|
177
|
-
$ts_per_hour = feature_report.timesteps_per_hour
|
178
|
-
def scale_timeseries(input, ts_per_hr=$ts_per_hour)
|
179
|
-
if input.nil?
|
180
|
-
return nil
|
181
|
-
end
|
182
|
-
if input.length ==0
|
183
|
-
return nil
|
184
|
-
end
|
185
|
-
if input.length == (8760 * ts_per_hr)
|
186
|
-
return input
|
187
|
-
end
|
188
|
-
result = []
|
189
|
-
input.each do |val|
|
190
|
-
(1..ts_per_hr).each do |x|
|
191
|
-
result.push(val/ts_per_hr.to_f)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
return result
|
195
|
-
end
|
196
|
-
|
197
181
|
# Update location
|
198
182
|
feature_report.location.latitude_deg = reopt_output['inputs']['Scenario']['Site']['latitude']
|
199
183
|
feature_report.location.longitude_deg = reopt_output['inputs']['Scenario']['Site']['longitude']
|
@@ -217,32 +201,32 @@ module URBANopt # :nodoc:
|
|
217
201
|
feature_report.distributed_generation.resilience_hours_avg = resilience_stats['resilience_hours_avg']
|
218
202
|
feature_report.distributed_generation.probs_of_surviving = resilience_stats['probs_of_surviving']
|
219
203
|
feature_report.distributed_generation.probs_of_surviving_by_month = resilience_stats['probs_of_surviving_by_month']
|
220
|
-
feature_report.distributed_generation.probs_of_surviving_by_hour_of_the_day = resilience_stats['probs_of_surviving_by_hour_of_the_day']
|
204
|
+
feature_report.distributed_generation.probs_of_surviving_by_hour_of_the_day = resilience_stats['probs_of_surviving_by_hour_of_the_day']
|
221
205
|
end
|
222
|
-
|
223
|
-
if reopt_output['outputs']['Scenario']['Site']['PV'].
|
206
|
+
|
207
|
+
if reopt_output['outputs']['Scenario']['Site']['PV'].instance_of?(Hash)
|
224
208
|
reopt_output['outputs']['Scenario']['Site']['PV'] = [reopt_output['outputs']['Scenario']['Site']['PV']]
|
225
209
|
elsif reopt_output['outputs']['Scenario']['Site']['PV'].nil?
|
226
210
|
reopt_output['outputs']['Scenario']['Site']['PV'] = []
|
227
211
|
end
|
228
212
|
|
229
213
|
reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
|
230
|
-
feature_report.distributed_generation.add_tech 'solar_pv',
|
214
|
+
feature_report.distributed_generation.add_tech 'solar_pv', URBANopt::Reporting::DefaultReports::SolarPV.new({ size_kw: (pv['size_kw'] || 0), id: i })
|
231
215
|
end
|
232
216
|
|
233
217
|
wind = reopt_output['outputs']['Scenario']['Site']['Wind']
|
234
|
-
if !wind['size_kw'].nil?
|
235
|
-
feature_report.distributed_generation.add_tech 'wind',
|
218
|
+
if !wind['size_kw'].nil? && (wind['size_kw'] != 0)
|
219
|
+
feature_report.distributed_generation.add_tech 'wind', URBANopt::Reporting::DefaultReports::Wind.new({ size_kw: (wind['size_kw'] || 0) })
|
236
220
|
end
|
237
221
|
|
238
222
|
generator = reopt_output['outputs']['Scenario']['Site']['Generator']
|
239
|
-
if !generator['size_kw'].nil?
|
240
|
-
feature_report.distributed_generation.add_tech 'generator',
|
223
|
+
if !generator['size_kw'].nil? && (generator['size_kw'] != 0)
|
224
|
+
feature_report.distributed_generation.add_tech 'generator', URBANopt::Reporting::DefaultReports::Generator.new({ size_kw: (generator['size_kw'] || 0) })
|
241
225
|
end
|
242
226
|
|
243
227
|
storage = reopt_output['outputs']['Scenario']['Site']['Storage']
|
244
|
-
if !storage['size_kw'].nil?
|
245
|
-
feature_report.distributed_generation.add_tech 'storage',
|
228
|
+
if !storage['size_kw'].nil? && (storage['size_kw'] != 0)
|
229
|
+
feature_report.distributed_generation.add_tech 'storage', URBANopt::Reporting::DefaultReports::Storage.new({ size_kwh: (storage['size_kwh'] || 0), size_kw: (storage['size_kw'] || 0) })
|
246
230
|
end
|
247
231
|
|
248
232
|
generation_timeseries_kwh = Matrix[[0] * (8760 * feature_report.timesteps_per_hour)]
|
@@ -250,28 +234,18 @@ module URBANopt # :nodoc:
|
|
250
234
|
|
251
235
|
unless reopt_output['outputs']['Scenario']['Site']['PV'].nil?
|
252
236
|
reopt_output['outputs']['Scenario']['Site']['PV'].each do |pv|
|
253
|
-
if (pv['size_kw'] || 0) > 0
|
254
|
-
|
255
|
-
generation_timeseries_kwh += Matrix[convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
|
256
|
-
end
|
237
|
+
if (pv['size_kw'] || 0) > 0 && !pv['year_one_power_production_series_kw'].nil?
|
238
|
+
generation_timeseries_kwh += Matrix[convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
|
257
239
|
end
|
258
|
-
|
240
|
+
end
|
259
241
|
end
|
260
242
|
|
261
|
-
|
262
|
-
|
263
|
-
if !reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'].nil?
|
264
|
-
generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
|
265
|
-
end
|
266
|
-
end
|
243
|
+
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?
|
244
|
+
generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
|
267
245
|
end
|
268
246
|
|
269
|
-
|
270
|
-
|
271
|
-
if !reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'].nil?
|
272
|
-
generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
|
273
|
-
end
|
274
|
-
end
|
247
|
+
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?
|
248
|
+
generation_timeseries_kwh += Matrix[convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour)]
|
275
249
|
end
|
276
250
|
|
277
251
|
$generation_timeseries_kwh = generation_timeseries_kwh.to_a[0] || [0] * (8760 * feature_report.timesteps_per_hour)
|
@@ -281,70 +255,70 @@ module URBANopt # :nodoc:
|
|
281
255
|
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Total(kw)')
|
282
256
|
end
|
283
257
|
|
284
|
-
$load =
|
258
|
+
$load = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['LoadProfile']['year_one_electric_load_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
285
259
|
$load_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Load:Total(kw)')
|
286
260
|
if $load_col.nil?
|
287
261
|
$load_col = feature_report.timeseries_csv.column_names.length
|
288
262
|
feature_report.timeseries_csv.column_names.push('REopt:Electricity:Load:Total(kw)')
|
289
263
|
end
|
290
264
|
|
291
|
-
$utility_to_load =
|
265
|
+
$utility_to_load = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_load_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
292
266
|
$utility_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToLoad(kw)')
|
293
267
|
if $utility_to_load_col.nil?
|
294
268
|
$utility_to_load_col = feature_report.timeseries_csv.column_names.length
|
295
269
|
feature_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToLoad(kw)')
|
296
270
|
end
|
297
271
|
|
298
|
-
$utility_to_battery =
|
272
|
+
$utility_to_battery = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_battery_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
299
273
|
$utility_to_battery_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToBattery(kw)')
|
300
274
|
if $utility_to_battery_col.nil?
|
301
275
|
$utility_to_battery_col = feature_report.timeseries_csv.column_names.length
|
302
276
|
feature_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToBattery(kw)')
|
303
277
|
end
|
304
278
|
|
305
|
-
$storage_to_load =
|
279
|
+
$storage_to_load = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
306
280
|
$storage_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToLoad(kw)')
|
307
281
|
if $storage_to_load_col.nil?
|
308
282
|
$storage_to_load_col = feature_report.timeseries_csv.column_names.length
|
309
283
|
feature_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToLoad(kw)')
|
310
284
|
end
|
311
285
|
|
312
|
-
$storage_to_grid =
|
286
|
+
$storage_to_grid = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
313
287
|
$storage_to_grid_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToGrid(kw)')
|
314
288
|
if $storage_to_grid_col.nil?
|
315
289
|
$storage_to_grid_col = feature_report.timeseries_csv.column_names.length
|
316
290
|
feature_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToGrid(kw)')
|
317
291
|
end
|
318
292
|
|
319
|
-
$storage_soc =
|
293
|
+
$storage_soc = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
320
294
|
$storage_soc_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:StateOfCharge(pct)')
|
321
295
|
if $storage_soc_col.nil?
|
322
296
|
$storage_soc_col = feature_report.timeseries_csv.column_names.length
|
323
297
|
feature_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:StateOfCharge(pct)')
|
324
298
|
end
|
325
299
|
|
326
|
-
$generator_total =
|
300
|
+
$generator_total = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
327
301
|
$generator_total_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:Total(kw)')
|
328
302
|
if $generator_total_col.nil?
|
329
303
|
$generator_total_col = feature_report.timeseries_csv.column_names.length
|
330
304
|
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:Total(kw)')
|
331
305
|
end
|
332
306
|
|
333
|
-
$generator_to_battery =
|
307
|
+
$generator_to_battery = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_battery_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
334
308
|
$generator_to_battery_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToBattery(kw)')
|
335
309
|
if $generator_to_battery_col.nil?
|
336
310
|
$generator_to_battery_col = feature_report.timeseries_csv.column_names.length
|
337
311
|
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToBattery(kw)')
|
338
312
|
end
|
339
313
|
|
340
|
-
$generator_to_load =
|
314
|
+
$generator_to_load = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
341
315
|
$generator_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToLoad(kw)')
|
342
316
|
if $generator_to_load_col.nil?
|
343
317
|
$generator_to_load_col = feature_report.timeseries_csv.column_names.length
|
344
318
|
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToLoad(kw)')
|
345
319
|
end
|
346
320
|
|
347
|
-
$generator_to_grid =
|
321
|
+
$generator_to_grid = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_grid_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
348
322
|
$generator_to_grid_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToGrid(kw)')
|
349
323
|
if $generator_to_grid_col.nil?
|
350
324
|
$generator_to_grid_col = feature_report.timeseries_csv.column_names.length
|
@@ -369,7 +343,6 @@ module URBANopt # :nodoc:
|
|
369
343
|
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToLoad(kw)')
|
370
344
|
end
|
371
345
|
|
372
|
-
|
373
346
|
$pv_to_grid_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToGrid(kw)')
|
374
347
|
if $pv_to_grid_col.nil?
|
375
348
|
$pv_to_grid_col = feature_report.timeseries_csv.column_names.length
|
@@ -383,10 +356,10 @@ module URBANopt # :nodoc:
|
|
383
356
|
|
384
357
|
reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
|
385
358
|
if (pv['size_kw'] || 0) > 0
|
386
|
-
$pv_total += Matrix[
|
387
|
-
$pv_to_battery += Matrix[
|
388
|
-
$pv_to_load += Matrix[
|
389
|
-
$pv_to_grid += Matrix[
|
359
|
+
$pv_total += Matrix[convert_powerflow_resolution(pv['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)]
|
360
|
+
$pv_to_battery += Matrix[convert_powerflow_resolution(pv['year_one_to_battery_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)]
|
361
|
+
$pv_to_load += Matrix[convert_powerflow_resolution(pv['year_one_to_load_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)]
|
362
|
+
$pv_to_grid += Matrix[convert_powerflow_resolution(pv['year_one_to_grid_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)]
|
390
363
|
end
|
391
364
|
end
|
392
365
|
|
@@ -395,28 +368,28 @@ module URBANopt # :nodoc:
|
|
395
368
|
$pv_to_load = $pv_to_load.to_a[0]
|
396
369
|
$pv_to_grid = $pv_to_grid.to_a[0]
|
397
370
|
|
398
|
-
$wind_total =
|
371
|
+
$wind_total = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
399
372
|
$wind_total_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:Total(kw)')
|
400
373
|
if $wind_total_col.nil?
|
401
374
|
$wind_total_col = feature_report.timeseries_csv.column_names.length
|
402
375
|
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:Total(kw)')
|
403
376
|
end
|
404
377
|
|
405
|
-
$wind_to_battery =
|
378
|
+
$wind_to_battery = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_battery_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
406
379
|
$wind_to_battery_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToBattery(kw)')
|
407
380
|
if $wind_to_battery_col.nil?
|
408
381
|
$wind_to_battery_col = feature_report.timeseries_csv.column_names.length
|
409
382
|
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToBattery(kw)')
|
410
383
|
end
|
411
384
|
|
412
|
-
$wind_to_load =
|
385
|
+
$wind_to_load = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_load_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
413
386
|
$wind_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToLoad(kw)')
|
414
387
|
if $wind_to_load_col.nil?
|
415
388
|
$wind_to_load_col = feature_report.timeseries_csv.column_names.length
|
416
389
|
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToLoad(kw)')
|
417
390
|
end
|
418
391
|
|
419
|
-
$wind_to_grid =
|
392
|
+
$wind_to_grid = convert_powerflow_resolution(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_grid_series_kw'], reopt_resolution, feature_report.timesteps_per_hour) || [0] * (8760 * feature_report.timesteps_per_hour)
|
420
393
|
$wind_to_grid_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToGrid(kw)')
|
421
394
|
if $wind_to_grid_col.nil?
|
422
395
|
$wind_to_grid_col = feature_report.timeseries_csv.column_names.length
|
@@ -448,11 +421,17 @@ module URBANopt # :nodoc:
|
|
448
421
|
|
449
422
|
old_data = CSV.open(feature_report.timeseries_csv.path).read
|
450
423
|
start_date = Time.parse(old_data[1][0])
|
451
|
-
start_ts = (
|
424
|
+
start_ts = (
|
425
|
+
(
|
426
|
+
((start_date.yday - 1) * 60.0 * 60.0 * 24) +
|
427
|
+
((start_date.hour - 1) * 60.0 * 60.0) +
|
428
|
+
(start_date.min * 60.0) + start_date.sec) /
|
429
|
+
((60 / feature_report.timesteps_per_hour) * 60)
|
430
|
+
).to_int
|
452
431
|
|
453
432
|
mod_data = old_data.map.with_index do |x, i|
|
454
433
|
if i > 0
|
455
|
-
modrow(x, start_ts + i -
|
434
|
+
modrow(x, start_ts + i - 1)
|
456
435
|
else
|
457
436
|
x
|
458
437
|
end
|