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.
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-2021, Alliance for Sustainable Energy, LLC, and other
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-2021, Alliance for Sustainable Energy, LLC, and other
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? && !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
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-2021, Alliance for Sustainable Energy, LLC, and other
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) & (response.code == '404')
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 = ::JSON.generate(data, allow_nan: true)
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 = ::JSON.generate(response.body, allow_nan: true)
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 = ::JSON.generate(data, allow_nan: true)
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-2021, Alliance for Sustainable Energy, LLC, and other
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-2021, Alliance for Sustainable Energy, LLC, and other
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
- result.save save_name
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
- puts('Output file already exists...skipping')
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
- puts("KEEP EXISTING? #{keep_existing_output}")
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-2021, Alliance for Sustainable Energy, LLC, and other
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)