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.
- checksums.yaml +4 -4
- data/.github/pull_request_template.md +2 -2
- data/CHANGELOG.md +56 -0
- data/Gemfile +1 -7
- data/LICENSE.md +33 -21
- data/Rakefile +16 -6
- data/docs/package-lock.json +10084 -151
- data/docs/package.json +8 -4
- 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 +96 -76
- data/lib/urbanopt/reopt/reopt_lite_api.rb +29 -17
- data/lib/urbanopt/reopt/reopt_logger.rb +16 -6
- data/lib/urbanopt/reopt/reopt_post_processor.rb +20 -9
- data/lib/urbanopt/reopt/scenario/reopt_scenario_csv.rb +16 -6
- data/lib/urbanopt/reopt/scenario_report_adapter.rb +99 -84
- data/lib/urbanopt/reopt/utilities.rb +111 -0
- data/lib/urbanopt/reopt/version.rb +17 -7
- data/lib/urbanopt/reopt_scenario.rb +16 -6
- data/urbanopt-reopt.gemspec +4 -2
- metadata +19 -6
- data/.travis.yml +0 -22
- data/a.txt +0 -1
@@ -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.
|
@@ -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
|
-
|
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
|
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.
|
@@ -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
|
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.
|
@@ -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.
|
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
|
-
|
79
|
-
|
80
|
-
|
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.
|
86
|
-
scenario_report.location.
|
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.
|
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 |
|
97
|
-
if [nil
|
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.
|
107
|
-
reopt_inputs[:Scenario][:Site][:longitude] = scenario_report.location.
|
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
|
-
|
111
|
-
|
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
|
115
|
-
|
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
|
-
|
119
|
-
reopt_inputs[:Scenario][:time_steps_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
|
-
|
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.
|
205
|
-
scenario_report.location.
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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[
|
402
|
-
$pv_to_battery += Matrix[
|
403
|
-
$pv_to_load += Matrix[
|
404
|
-
$pv_to_grid += Matrix[
|
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 =
|
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 =
|
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 =
|
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 =
|
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 = (
|
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 -
|
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
|