urbanopt-reopt 0.6.1 → 0.8.0
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/CHANGELOG.md +37 -1
- data/Gemfile +1 -3
- data/LICENSE.md +1 -13
- data/Rakefile +1 -1
- data/developer_nrel_key.rb +1 -1
- data/doc_templates/LICENSE.md +17 -17
- data/doc_templates/copyright_erb.txt +2 -2
- data/doc_templates/copyright_js.txt +2 -2
- data/doc_templates/copyright_ruby.txt +2 -2
- data/docs/package-lock.json +10740 -4181
- data/docs/package.json +4 -1
- data/lib/urbanopt/reopt/extension.rb +6 -16
- data/lib/urbanopt/reopt/feature_report_adapter.rb +47 -22
- data/lib/urbanopt/reopt/reopt_lite_api.rb +37 -29
- data/lib/urbanopt/reopt/reopt_logger.rb +6 -16
- data/lib/urbanopt/reopt/reopt_post_processor.rb +30 -26
- data/lib/urbanopt/reopt/reopt_schema/reopt_input_schema.json +5 -0
- data/lib/urbanopt/reopt/reopt_schema/reopt_output_schema.json +11 -1
- data/lib/urbanopt/reopt/scenario/reopt_scenario_csv.rb +7 -17
- data/lib/urbanopt/reopt/scenario_report_adapter.rb +68 -24
- data/lib/urbanopt/reopt/utilities.rb +30 -0
- data/lib/urbanopt/reopt/version.rb +7 -17
- data/lib/urbanopt/reopt.rb +6 -16
- data/lib/urbanopt/reopt_scenario.rb +6 -16
- data/lib/urbanopt-reopt.rb +6 -16
- data/urbanopt-reopt.gemspec +2 -3
- metadata +9 -23
data/docs/package.json
CHANGED
@@ -13,7 +13,6 @@
|
|
13
13
|
"highlight.js": "^10.4.1",
|
14
14
|
"json-schema-ref-parser": "^6.1.0",
|
15
15
|
"json-schema-view-js": "git+https://git@github.com/bgschiller/json-schema-view-js.git",
|
16
|
-
"vuepress": "^1.8.2",
|
17
16
|
"webpack-dev-middleware": "^3.6.0"
|
18
17
|
},
|
19
18
|
"devDependencies": {
|
@@ -23,8 +22,12 @@
|
|
23
22
|
"gh-pages": "^2.0.1",
|
24
23
|
"ini": "^2.0.0",
|
25
24
|
"is-svg": "4.3.1",
|
25
|
+
"lodash": "^4.17.21",
|
26
|
+
"postcss": "^8.2.15",
|
26
27
|
"serialize-javascript": "^5.0.1",
|
27
28
|
"ssri": "8.0.1",
|
29
|
+
"url-parse": "^1.5.1",
|
30
|
+
"vuepress": "^1.8.2",
|
28
31
|
"yargs-parser": "^18.1.1"
|
29
32
|
}
|
30
33
|
}
|
@@ -1,31 +1,21 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, 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
|
-
|
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
|
-
|
18
|
+
#
|
29
19
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
30
20
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
31
21
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
@@ -1,31 +1,21 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, 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
|
-
|
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
|
-
|
18
|
+
#
|
29
19
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
30
20
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
31
21
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
@@ -68,7 +58,7 @@ module URBANopt # :nodoc:
|
|
68
58
|
#
|
69
59
|
# [*return:*] _Hash_ - Returns hash formatted for submittal to the \REopt Lite API
|
70
60
|
##
|
71
|
-
def reopt_json_from_feature_report(feature_report, reopt_assumptions_hash = nil)
|
61
|
+
def reopt_json_from_feature_report(feature_report, reopt_assumptions_hash = nil, groundmount_photovoltaic = nil)
|
72
62
|
name = feature_report.name.delete ' '
|
73
63
|
description = "feature_report_#{name}_#{feature_report.id}"
|
74
64
|
reopt_inputs = { Scenario: { Site: { ElectricTariff: { blended_monthly_demand_charges_us_dollars_per_kw: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], blended_monthly_rates_us_dollars_per_kwh: [0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13] }, LoadProfile: {}, Wind: { max_kw: 0 } } } }
|
@@ -103,8 +93,18 @@ module URBANopt # :nodoc:
|
|
103
93
|
reopt_inputs[:Scenario][:Site][:roof_squarefeet] = feature_report.program.roof_area_sqft[:available_roof_area_sqft]
|
104
94
|
end
|
105
95
|
|
106
|
-
if reopt_inputs[:Scenario][:Site][:land_acres].nil?
|
107
|
-
|
96
|
+
if reopt_inputs[:Scenario][:Site][:land_acres].nil?
|
97
|
+
# Check if ground-mount PV is specified with the Feature ID and take footprint area of PV
|
98
|
+
# constrain for REopt optimization
|
99
|
+
begin
|
100
|
+
if !groundmount_photovoltaic[feature_report.id].nil?
|
101
|
+
reopt_inputs[:Scenario][:Site][:land_acres] = groundmount_photovoltaic[feature_report.id] * 1.0 / 43560 # acres/sqft
|
102
|
+
# If no ground-mount PV associated with feature use site area as constrain for REopt optimization
|
103
|
+
elsif !feature_report.program.site_area_sqft.nil?
|
104
|
+
reopt_inputs[:Scenario][:Site][:land_acres] = feature_report.program.site_area_sqft * 1.0 / 43560 # acres/sqft
|
105
|
+
end
|
106
|
+
rescue StandardError
|
107
|
+
end
|
108
108
|
end
|
109
109
|
|
110
110
|
if reopt_inputs[:Scenario][:time_steps_per_hour].nil?
|
@@ -120,10 +120,10 @@ module URBANopt # :nodoc:
|
|
120
120
|
# Fill in missing timestep values with 0 if a full year is not provided
|
121
121
|
if energy_timeseries_kw.length < (feature_report.timesteps_per_hour * 8760)
|
122
122
|
start_date = Time.parse(t.by_col['Datetime'][0])
|
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) /
|
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) / \
|
124
124
|
((60 / feature_report.timesteps_per_hour) * 60)).to_int
|
125
125
|
end_date = Time.parse(t.by_col['Datetime'][-1])
|
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) /
|
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) / \
|
127
127
|
((60 / feature_report.timesteps_per_hour) * 60)).to_int
|
128
128
|
energy_timeseries_kw = [0.0] * (start_ts - 1) + energy_timeseries_kw + [0.0] * ((feature_report.timesteps_per_hour * 8760) - end_ts)
|
129
129
|
end
|
@@ -183,6 +183,7 @@ module URBANopt # :nodoc:
|
|
183
183
|
feature_report.location.longitude_deg = reopt_output['inputs']['Scenario']['Site']['longitude']
|
184
184
|
|
185
185
|
# Update distributed generation sizing and financials
|
186
|
+
feature_report.distributed_generation.annual_renewable_electricity_pct = reopt_output['outputs']['Scenario']['Site']['annual_renewable_electricity_pct'] || 0
|
186
187
|
feature_report.distributed_generation.lcc_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['lcc_us_dollars'] || 0
|
187
188
|
feature_report.distributed_generation.npv_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['npv_us_dollars'] || 0
|
188
189
|
feature_report.distributed_generation.year_one_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_energy_cost_us_dollars'] || 0
|
@@ -210,8 +211,32 @@ module URBANopt # :nodoc:
|
|
210
211
|
reopt_output['outputs']['Scenario']['Site']['PV'] = []
|
211
212
|
end
|
212
213
|
|
214
|
+
# Store the PV name and location in a hash
|
215
|
+
location = {}
|
216
|
+
azimuth = {}
|
217
|
+
tilt = {}
|
218
|
+
module_type = {}
|
219
|
+
gcr = {}
|
220
|
+
|
221
|
+
# Check whether multi PV assumption input file is used or single PV
|
222
|
+
if reopt_output['inputs']['Scenario']['Site']['PV'].is_a?(Array)
|
223
|
+
reopt_output['inputs']['Scenario']['Site']['PV'].each do |pv|
|
224
|
+
location[pv['pv_name']] = pv['location']
|
225
|
+
azimuth[pv['pv_name']] = pv['azimuth']
|
226
|
+
tilt[pv['pv_name']] = pv['tilt']
|
227
|
+
module_type[pv['pv_name']] = pv['module_type']
|
228
|
+
gcr[pv['pv_name']] = pv['gcr']
|
229
|
+
end
|
230
|
+
else
|
231
|
+
location[reopt_output['inputs']['Scenario']['Site']['PV']['pv_name']] = reopt_output['inputs']['Scenario']['Site']['PV']['location']
|
232
|
+
azimuth[reopt_output['inputs']['Scenario']['Site']['PV']['pv_name']] = reopt_output['inputs']['Scenario']['Site']['PV']['azimuth']
|
233
|
+
tilt[reopt_output['inputs']['Scenario']['Site']['PV']['pv_name']] = reopt_output['inputs']['Scenario']['Site']['PV']['tilt']
|
234
|
+
module_type[reopt_output['inputs']['Scenario']['Site']['PV']['pv_name']] = reopt_output['inputs']['Scenario']['Site']['PV']['module_type']
|
235
|
+
gcr[reopt_output['inputs']['Scenario']['Site']['PV']['pv_name']] = reopt_output['inputs']['Scenario']['Site']['PV']['gcr']
|
236
|
+
end
|
237
|
+
|
213
238
|
reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
|
214
|
-
feature_report.distributed_generation.add_tech 'solar_pv', URBANopt::Reporting::DefaultReports::SolarPV.new({ size_kw: (pv['size_kw'] || 0), id: i })
|
239
|
+
feature_report.distributed_generation.add_tech 'solar_pv', URBANopt::Reporting::DefaultReports::SolarPV.new({ size_kw: (pv['size_kw'] || 0), id: i, location: location[pv['pv_name']], average_yearly_energy_produced_kwh: pv['average_yearly_energy_produced_kwh'], azimuth: azimuth[pv['pv_name']], tilt: tilt[pv['pv_name']], module_type: module_type[pv['pv_name']], gcr: gcr[pv['pv_name']] })
|
215
240
|
end
|
216
241
|
|
217
242
|
wind = reopt_output['outputs']['Scenario']['Site']['Wind']
|
@@ -1,31 +1,21 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, 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
|
-
|
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
|
-
|
18
|
+
#
|
29
19
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
30
20
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
31
21
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
@@ -130,12 +120,26 @@ module URBANopt # :nodoc:
|
|
130
120
|
@@logger.fatal('Exceeded the REopt-Lite API limit of 300 requests per hour')
|
131
121
|
puts 'Using the URBANopt CLI to submit a Scenario optimization counts as one request per scenario'
|
132
122
|
puts 'Using the URBANopt CLI to submit a Feature optimization counts as one request per feature'
|
133
|
-
abort('Please wait and try again once the time period has elapsed')
|
123
|
+
abort('Please wait and try again once the time period has elapsed. The URBANopt CLI flag --reopt-keep-existing can be used to resume the optimization')
|
134
124
|
elsif (result.code != '201') && (result.code != '200') # Anything in the 200s is success
|
135
125
|
@@logger.debug("REopt-Lite has returned a '#{result.code}' status code. Visit https://developer.nrel.gov/docs/errors/ for more status code information")
|
126
|
+
# display error messages
|
127
|
+
json_res = JSON.parse(result.body, allow_nan: true)
|
128
|
+
json_res['messages'].delete('warnings') if json_res['messages']['warnings']
|
129
|
+
json_res['messages'].delete('Deprecations') if json_res['messages']['Deprecations']
|
130
|
+
if json_res['messages']
|
131
|
+
@@logger.error("MESSAGES: #{json_res['messages']}")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
tries = max_tries
|
135
|
+
rescue StandardError => e
|
136
|
+
@@logger.debug("error from REopt lite API: #{e}")
|
137
|
+
if tries + 1 < max_tries
|
138
|
+
@@logger.debug('trying again...')
|
139
|
+
else
|
140
|
+
@@logger.debug('max tries reached!')
|
141
|
+
return result
|
136
142
|
end
|
137
|
-
tries = 4
|
138
|
-
rescue StandardError
|
139
143
|
tries += 1
|
140
144
|
end
|
141
145
|
end
|
@@ -219,28 +223,29 @@ module URBANopt # :nodoc:
|
|
219
223
|
# Wait a few seconds for the REopt database to update before GETing results
|
220
224
|
sleep 5
|
221
225
|
get_request = Net::HTTP::Get.new(uri.request_uri)
|
222
|
-
response = make_request(http, get_request)
|
226
|
+
response = make_request(http, get_request, 8)
|
223
227
|
|
224
228
|
# Set a limit on retries when 404s are returned from REopt API
|
225
229
|
elapsed_time = 0
|
226
230
|
max_elapsed_time = 60 * 5
|
227
231
|
|
228
232
|
# If database still hasn't updated, wait a little longer and try again
|
229
|
-
while (elapsed_time < max_elapsed_time)
|
233
|
+
while (elapsed_time < max_elapsed_time) && (response && response.code == '404')
|
230
234
|
response = make_request(http, get_request)
|
231
235
|
@@logger.warn('GET request was too fast for REOpt-Lite API. Retrying...')
|
232
236
|
elapsed_time += 5
|
233
237
|
sleep 5
|
234
238
|
end
|
235
239
|
|
236
|
-
data = JSON.parse(response.body)
|
237
|
-
text =
|
240
|
+
data = JSON.parse(response.body, allow_nan: true)
|
241
|
+
text = JSON.pretty_generate(data)
|
238
242
|
begin
|
239
243
|
File.open(filename, 'w+') do |f|
|
240
244
|
f.puts(text)
|
241
245
|
end
|
242
|
-
rescue StandardError
|
246
|
+
rescue StandardError => e
|
243
247
|
@@logger.error("Cannot write - #{filename}")
|
248
|
+
@@logger.error("ERROR: #{e}")
|
244
249
|
end
|
245
250
|
|
246
251
|
if response.code == '200'
|
@@ -280,6 +285,10 @@ module URBANopt # :nodoc:
|
|
280
285
|
|
281
286
|
# Send the request
|
282
287
|
response = make_request(http, post_request)
|
288
|
+
if !response.is_a?(Net::HTTPSuccess)
|
289
|
+
@@logger.error('make_request Failed')
|
290
|
+
raise 'Check_connection Failed'
|
291
|
+
end
|
283
292
|
|
284
293
|
# Get UUID
|
285
294
|
run_uuid = JSON.parse(response.body, allow_nan: true)['run_uuid']
|
@@ -295,12 +304,11 @@ module URBANopt # :nodoc:
|
|
295
304
|
@@logger.info("REopt results saved to #{filename}")
|
296
305
|
end
|
297
306
|
|
298
|
-
text =
|
307
|
+
text = JSON.parse(response.body, allow_nan: true)
|
299
308
|
if response.code != '201'
|
300
309
|
File.open(filename, 'w+') do |f|
|
301
|
-
f.puts(text)
|
310
|
+
f.puts(JSON.pretty_generate(text))
|
302
311
|
end
|
303
|
-
@@logger.error("Cannot write - #{filename}")
|
304
312
|
raise "Error in REopt optimization post - see #{filename}"
|
305
313
|
end
|
306
314
|
|
@@ -353,8 +361,8 @@ module URBANopt # :nodoc:
|
|
353
361
|
_tries += 1
|
354
362
|
end
|
355
363
|
|
356
|
-
data = JSON.parse(response.body)
|
357
|
-
text =
|
364
|
+
data = JSON.parse(response.body, allow_nan: true)
|
365
|
+
text = JSON.pretty_generate(data)
|
358
366
|
begin
|
359
367
|
File.open(filename, 'w+') do |f|
|
360
368
|
f.puts(text)
|
@@ -1,31 +1,21 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, 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
|
-
|
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
|
-
|
18
|
+
#
|
29
19
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
30
20
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
31
21
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
@@ -1,31 +1,21 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, 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
|
-
|
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
|
-
|
18
|
+
#
|
29
19
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
30
20
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
31
21
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
@@ -101,12 +91,14 @@ module URBANopt # :nodoc:
|
|
101
91
|
end
|
102
92
|
|
103
93
|
if !scenario_reopt_assumptions_file.nil?
|
94
|
+
@scenario_reopt_assumptions_file = scenario_reopt_assumptions_file
|
104
95
|
File.open(scenario_reopt_assumptions_file, 'r') do |file|
|
105
96
|
@scenario_reopt_default_assumptions_hash = JSON.parse(file.read, symbolize_names: true)
|
106
97
|
end
|
107
98
|
end
|
108
99
|
|
109
100
|
if !reopt_feature_assumptions.empty?
|
101
|
+
@reopt_feature_assumptions = reopt_feature_assumptions
|
110
102
|
reopt_feature_assumptions.each do |file|
|
111
103
|
@feature_reports_reopt_default_assumption_hashes << JSON.parse(File.open(file, 'r').read, symbolize_names: true)
|
112
104
|
end
|
@@ -137,6 +129,7 @@ module URBANopt # :nodoc:
|
|
137
129
|
reopt_output_file = File.join(feature_report.directory_name, 'reopt')
|
138
130
|
end
|
139
131
|
reopt_output = api.reopt_request(reopt_input, reopt_output_file)
|
132
|
+
print("REOPT OUTPUT FILE: #{reopt_output_file}")
|
140
133
|
if run_resilience
|
141
134
|
run_uuid = reopt_output['outputs']['Scenario']['run_uuid']
|
142
135
|
if File.directory? reopt_output_file
|
@@ -166,9 +159,13 @@ module URBANopt # :nodoc:
|
|
166
159
|
# * +timeseries_csv_path+ - _String_ - Optional. Path to a file at which the new timeseries CSV for the ScenarioReport will be saved.
|
167
160
|
#
|
168
161
|
# [*return:*] _URBANopt::Scenario::DefaultReports::ScenarioReport_ Returns an updated ScenarioReport
|
169
|
-
def run_scenario_report(scenario_report:, reopt_assumptions_hash: nil, reopt_output_file: nil, timeseries_csv_path: nil, save_name: nil, run_resilience: true)
|
162
|
+
def run_scenario_report(scenario_report:, reopt_assumptions_hash: nil, reopt_output_file: nil, timeseries_csv_path: nil, save_name: nil, run_resilience: true, community_photovoltaic: nil)
|
163
|
+
puts "run scenario report"
|
164
|
+
@save_assumptions_filepath = false
|
170
165
|
if !reopt_assumptions_hash.nil?
|
171
166
|
@scenario_reopt_default_assumptions_hash = reopt_assumptions_hash
|
167
|
+
else
|
168
|
+
@save_assumptions_filepath = true
|
172
169
|
end
|
173
170
|
if !reopt_output_file.nil?
|
174
171
|
@scenario_reopt_default_output_file = reopt_output_file
|
@@ -180,7 +177,7 @@ module URBANopt # :nodoc:
|
|
180
177
|
api = URBANopt::REopt::REoptLiteAPI.new(@nrel_developer_key, @localhost)
|
181
178
|
adapter = URBANopt::REopt::ScenarioReportAdapter.new
|
182
179
|
|
183
|
-
reopt_input = adapter.reopt_json_from_scenario_report(scenario_report, @scenario_reopt_default_assumptions_hash)
|
180
|
+
reopt_input = adapter.reopt_json_from_scenario_report(scenario_report, @scenario_reopt_default_assumptions_hash, community_photovoltaic)
|
184
181
|
|
185
182
|
reopt_output = api.reopt_request(reopt_input, @scenario_reopt_default_output_file)
|
186
183
|
if run_resilience
|
@@ -195,8 +192,14 @@ module URBANopt # :nodoc:
|
|
195
192
|
end
|
196
193
|
|
197
194
|
result = adapter.update_scenario_report(scenario_report, reopt_output, @scenario_timeseries_default_output_file, resilience_stats)
|
195
|
+
# can you save the assumptions file path that was used?
|
196
|
+
if @save_assumptions_filepath && @scenario_reopt_assumptions_file
|
197
|
+
result.distributed_generation.reopt_assumptions_file_path = @scenario_reopt_assumptions_file
|
198
|
+
end
|
199
|
+
|
198
200
|
if !save_name.nil?
|
199
|
-
|
201
|
+
# don't save individual feature reports when doing the scenario optimization!
|
202
|
+
result.save(save_name, false)
|
200
203
|
end
|
201
204
|
return result
|
202
205
|
end
|
@@ -212,7 +215,7 @@ module URBANopt # :nodoc:
|
|
212
215
|
# * +timeseries_csv_path+ - _Array_ - Optional. A array of paths to files at which the new timeseries CSV for the FeatureReports will be saved. The number and order of the paths should match the feature_reports array.
|
213
216
|
#
|
214
217
|
# [*return:*] _Array_ Returns an array of updated _URBANopt::Scenario::DefaultReports::FeatureReport_ objects
|
215
|
-
def run_feature_reports(feature_reports:, reopt_assumptions_hashes: [], reopt_output_files: [], timeseries_csv_paths: [], save_names: nil, run_resilience: true, keep_existing_output: false)
|
218
|
+
def run_feature_reports(feature_reports:, reopt_assumptions_hashes: [], reopt_output_files: [], timeseries_csv_paths: [], save_names: nil, run_resilience: true, keep_existing_output: false, groundmount_photovoltaic: nil)
|
216
219
|
if !reopt_assumptions_hashes.empty?
|
217
220
|
@feature_reports_reopt_default_assumption_hashes = reopt_assumptions_hashes
|
218
221
|
end
|
@@ -244,7 +247,7 @@ module URBANopt # :nodoc:
|
|
244
247
|
# check if we should rerun
|
245
248
|
if !(keep_existing_output && output_exists(@feature_reports_reopt_default_output_files[idx]))
|
246
249
|
begin
|
247
|
-
reopt_input = feature_adapter.reopt_json_from_feature_report(feature_report, @feature_reports_reopt_default_assumption_hashes[idx])
|
250
|
+
reopt_input = feature_adapter.reopt_json_from_feature_report(feature_report, @feature_reports_reopt_default_assumption_hashes[idx], groundmount_photovoltaic)
|
248
251
|
reopt_output = api.reopt_request(reopt_input, @feature_reports_reopt_default_output_files[idx])
|
249
252
|
if run_resilience
|
250
253
|
run_uuid = reopt_output['outputs']['Scenario']['run_uuid']
|
@@ -265,11 +268,12 @@ module URBANopt # :nodoc:
|
|
265
268
|
warn 'Could not save feature reports - the number of save names provided did not match the number of feature reports'
|
266
269
|
end
|
267
270
|
end
|
268
|
-
rescue StandardError
|
271
|
+
rescue StandardError => e
|
269
272
|
@@logger.info("Could not optimize Feature Report #{feature_report.name} #{feature_report.id}")
|
273
|
+
@@logger.error("ERROR: #{e}")
|
270
274
|
end
|
271
275
|
else
|
272
|
-
|
276
|
+
@@logger.info('Output file already exists...skipping')
|
273
277
|
end
|
274
278
|
end
|
275
279
|
|
@@ -305,9 +309,9 @@ module URBANopt # :nodoc:
|
|
305
309
|
# * +feature_report_timeseries_csv_paths+ - _Array_ - Optional. An array of paths to files at which the new timeseries CSV for the FeatureReports will be saved. The number and order of the paths should match the array in ScenarioReport.feature_reports.
|
306
310
|
#
|
307
311
|
# [*return:*] _URBANopt::Scenario::DefaultReports::ScenarioReport_ - Returns an updated ScenarioReport
|
308
|
-
def run_scenario_report_features(scenario_report:, reopt_assumptions_hashes: [], reopt_output_files: [], feature_report_timeseries_csv_paths: [], save_names_feature_reports: nil, save_name_scenario_report: nil, run_resilience: true, keep_existing_output: false)
|
309
|
-
new_feature_reports = run_feature_reports(feature_reports: scenario_report.feature_reports, reopt_assumptions_hashes: reopt_assumptions_hashes, reopt_output_files: reopt_output_files, timeseries_csv_paths: feature_report_timeseries_csv_paths, save_names: save_names_feature_reports, run_resilience: run_resilience, keep_existing_output: keep_existing_output)
|
310
|
-
|
312
|
+
def run_scenario_report_features(scenario_report:, reopt_assumptions_hashes: [], reopt_output_files: [], feature_report_timeseries_csv_paths: [], save_names_feature_reports: nil, save_name_scenario_report: nil, run_resilience: true, keep_existing_output: false, groundmount_photovoltaic: nil)
|
313
|
+
new_feature_reports = run_feature_reports(feature_reports: scenario_report.feature_reports, reopt_assumptions_hashes: reopt_assumptions_hashes, reopt_output_files: reopt_output_files, timeseries_csv_paths: feature_report_timeseries_csv_paths, save_names: save_names_feature_reports, run_resilience: run_resilience, keep_existing_output: keep_existing_output, groundmount_photovoltaic: groundmount_photovoltaic)
|
314
|
+
|
311
315
|
# only do this if you have run feature reports
|
312
316
|
new_scenario_report = URBANopt::Reporting::DefaultReports::ScenarioReport.new
|
313
317
|
if !new_feature_reports.empty?
|
@@ -371,6 +371,11 @@
|
|
371
371
|
"description": "State rebate based on installed capacity",
|
372
372
|
"min": 0
|
373
373
|
},
|
374
|
+
"location": {
|
375
|
+
"default": "roof",
|
376
|
+
"type": "string",
|
377
|
+
"description": "Indicates location of PV. Available options are roof and ground."
|
378
|
+
},
|
374
379
|
"max_kw": {
|
375
380
|
"default": 1000000000.0,
|
376
381
|
"max": 1000000000.0,
|
@@ -71,6 +71,11 @@
|
|
71
71
|
"Site": {
|
72
72
|
"type": "object",
|
73
73
|
"properties": {
|
74
|
+
"annual_renewable_electricity_pct": {
|
75
|
+
"type": "float",
|
76
|
+
"description": "Fraction of annual renewable electricity - 0 for none, 1 for all, over 1 for more generated than consumed",
|
77
|
+
"units": "none"
|
78
|
+
},
|
74
79
|
"LoadProfile": {
|
75
80
|
"type": "object",
|
76
81
|
"properties": {
|
@@ -142,6 +147,11 @@
|
|
142
147
|
"PV": {
|
143
148
|
"type": "object",
|
144
149
|
"properties": {
|
150
|
+
"location": {
|
151
|
+
"default": "roof",
|
152
|
+
"type": "string",
|
153
|
+
"description": "Indicates location of PV. Available options are roof and ground."
|
154
|
+
},
|
145
155
|
"size_kw": {
|
146
156
|
"type": "float",
|
147
157
|
"description": "Optimal PV system size",
|
@@ -535,4 +545,4 @@
|
|
535
545
|
}
|
536
546
|
}
|
537
547
|
}
|
538
|
-
}
|
548
|
+
}
|
@@ -1,31 +1,21 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, 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
|
-
|
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
|
-
|
18
|
+
#
|
29
19
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
30
20
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
31
21
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
@@ -106,7 +96,7 @@ module URBANopt
|
|
106
96
|
if row.length > 3 && !@reopt_files_dir.nil?
|
107
97
|
@reopt_feature_assumptions[idx - 1] = File.join(@reopt_files_dir, row[3].chomp)
|
108
98
|
end
|
109
|
-
|
99
|
+
|
110
100
|
# gets +features+ from the feature_file.
|
111
101
|
features = []
|
112
102
|
feature = feature_file.get_feature_by_id(feature_id)
|