urbanopt-reopt 0.7.0 → 0.9.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/index.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # **URBANopt REopt Gem**
2
2
 
3
3
  The **URBANopt<sup>&trade;</sup> REopt Gem** extends **URBANopt::Reporting::DefaultReports::ScenarioReport** and **URBANopt::Reporting::DefaultReports::FeatureReport** with the ability to derive cost-optimal distributed energy resource (DER) technology sizes and annual dispatch strageties via the [REopt Lite](https://reopt.nrel.gov/tool) decision support platform.
4
- REopt Lite is a technoeconomic model which leverages mixed integer linear programming to identify the cost-optimal sizing of solar PV, Wind, Storage and/or diesel generation given an electric load profile, a utility rate tariff and other technoeconomic parameters. See [https://developer.nrel.gov/docs/energy-optimization/reopt-v1/](https://developer.nrel.gov/docs/energy-optimization/reopt-v1/) for more detailed information on input parameters and default assumptions.
4
+ REopt Lite is a technoeconomic model which leverages mixed integer linear programming to identify the cost-optimal sizing of solar PV, Wind, Storage and/or diesel generation given an electric load profile, a utility rate tariff and other technoeconomic parameters. See [https://developer.nrel.gov/docs/energy-optimization/reopt/v2/](https://developer.nrel.gov/docs/energy-optimization/reopt/v2/) for more detailed information on input parameters and default assumptions.
5
5
 
6
6
  See the [example project](https://github.com/urbanopt/urbanopt-example-reopt-project.git) for more infomation about usage of this gem.
7
7
 
@@ -83,7 +83,7 @@ Moreover, the following optimal dispatch fields are added to its timeseries CSV.
83
83
  | ElectricityProduced:Wind:ToGrid | kWh |
84
84
  ```
85
85
 
86
- The REopt Lite has default values for all non-required input parameters that are used unless the user specifies custom assumptions. See [https://developer.nrel.gov/docs/energy-optimization/reopt-v1/](https://developer.nrel.gov/docs/energy-optimization/reopt-v1/) for more detailed information on input parameters and default assumptions.
86
+ The REopt Lite has default values for all non-required input parameters that are used unless the user specifies custom assumptions. See [https://developer.nrel.gov/docs/energy-optimization/reopt/v2/](https://developer.nrel.gov/docs/energy-optimization/reopt/v2/) for more detailed information on input parameters and default assumptions.
87
87
 
88
88
  <b>Note:</b> Required attributes for a REopt run include latitude and longitude. If no utility rate is specified in your REopt Lite assumption settings, then a constant default rate of $0.13 is assumed without demand charges. Also, by default, only solar PV and storage are considered in the analysis (i.e. Wind and Generators are excluded from consideration).
89
89
 
@@ -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.
@@ -130,10 +120,10 @@ module URBANopt # :nodoc:
130
120
  # Fill in missing timestep values with 0 if a full year is not provided
131
121
  if energy_timeseries_kw.length < (feature_report.timesteps_per_hour * 8760)
132
122
  start_date = Time.parse(t.by_col['Datetime'][0])
133
- 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) / \
134
124
  ((60 / feature_report.timesteps_per_hour) * 60)).to_int
135
125
  end_date = Time.parse(t.by_col['Datetime'][-1])
136
- 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) / \
137
127
  ((60 / feature_report.timesteps_per_hour) * 60)).to_int
138
128
  energy_timeseries_kw = [0.0] * (start_ts - 1) + energy_timeseries_kw + [0.0] * ((feature_report.timesteps_per_hour * 8760) - end_ts)
139
129
  end
@@ -193,6 +183,7 @@ module URBANopt # :nodoc:
193
183
  feature_report.location.longitude_deg = reopt_output['inputs']['Scenario']['Site']['longitude']
194
184
 
195
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
196
187
  feature_report.distributed_generation.lcc_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['lcc_us_dollars'] || 0
197
188
  feature_report.distributed_generation.npv_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['npv_us_dollars'] || 0
198
189
  feature_report.distributed_generation.year_one_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_energy_cost_us_dollars'] || 0
@@ -222,17 +213,30 @@ module URBANopt # :nodoc:
222
213
 
223
214
  # Store the PV name and location in a hash
224
215
  location = {}
216
+ azimuth = {}
217
+ tilt = {}
218
+ module_type = {}
219
+ gcr = {}
220
+
225
221
  # Check whether multi PV assumption input file is used or single PV
226
222
  if reopt_output['inputs']['Scenario']['Site']['PV'].is_a?(Array)
227
223
  reopt_output['inputs']['Scenario']['Site']['PV'].each do |pv|
228
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
229
  end
230
230
  else
231
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']
232
236
  end
233
237
 
234
238
  reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
235
- 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']] })
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']] })
236
240
  end
237
241
 
238
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.
@@ -41,7 +31,6 @@
41
31
  require 'net/https'
42
32
  require 'openssl'
43
33
  require 'uri'
44
- require 'uri'
45
34
  require 'json'
46
35
  require 'securerandom'
47
36
  require 'certified'
@@ -65,8 +54,8 @@ module URBANopt # :nodoc:
65
54
  def initialize(nrel_developer_key = nil, use_localhost = false)
66
55
  @use_localhost = use_localhost
67
56
  if @use_localhost
68
- @uri_submit = URI.parse('http//:127.0.0.1:8000/v1/job/')
69
- @uri_submit_outagesimjob = URI.parse('http//:127.0.0.1:8000/v1/outagesimjob/')
57
+ @uri_submit = URI.parse('http//:127.0.0.1:8000/v2/job/')
58
+ @uri_submit_outagesimjob = URI.parse('http//:127.0.0.1:8000/v2/outagesimjob/')
70
59
  else
71
60
  if [nil, '', '<insert your key here>'].include? nrel_developer_key
72
61
  if [nil, '', '<insert your key here>'].include? DEVELOPER_NREL_KEY
@@ -76,8 +65,8 @@ module URBANopt # :nodoc:
76
65
  end
77
66
  end
78
67
  @nrel_developer_key = nrel_developer_key
79
- @uri_submit = URI.parse("https://developer.nrel.gov/api/reopt/v1/job/?api_key=#{@nrel_developer_key}")
80
- @uri_submit_outagesimjob = URI.parse("https://developer.nrel.gov/api/reopt/v1/outagesimjob/?api_key=#{@nrel_developer_key}")
68
+ @uri_submit = URI.parse("https://developer.nrel.gov/api/reopt/v2/job?api_key=#{@nrel_developer_key}")
69
+ @uri_submit_outagesimjob = URI.parse("https://developer.nrel.gov/api/reopt/v2/outagesimjob?api_key=#{@nrel_developer_key}")
81
70
  # initialize @@logger
82
71
  @@logger ||= URBANopt::REopt.reopt_logger
83
72
  end
@@ -95,10 +84,10 @@ module URBANopt # :nodoc:
95
84
  ##
96
85
  def uri_results(run_uuid) # :nodoc:
97
86
  if @use_localhost
98
- return URI.parse("http://127.0.0.1:8000/v1/job/#{run_uuid}/results")
87
+ return URI.parse("http://127.0.0.1:8000/v2/job/#{run_uuid}/results")
99
88
  end
100
89
 
101
- return URI.parse("https://developer.nrel.gov/api/reopt/v1/job/#{run_uuid}/results?api_key=#{@nrel_developer_key}")
90
+ return URI.parse("https://developer.nrel.gov/api/reopt/v2/job/#{run_uuid}/results?api_key=#{@nrel_developer_key}")
102
91
  end
103
92
 
104
93
  ##
@@ -113,26 +102,31 @@ module URBANopt # :nodoc:
113
102
  ##
114
103
  def uri_resilience(run_uuid) # :nodoc:
115
104
  if @use_localhost
116
- return URI.parse("http://127.0.0.1:8000/v1/job/#{run_uuid}/resilience_stats")
105
+ return URI.parse("http://127.0.0.1:8000/v2/job/#{run_uuid}/resilience_stats")
117
106
  end
118
107
 
119
- return URI.parse("https://developer.nrel.gov/api/reopt/v1/job/#{run_uuid}/resilience_stats?api_key=#{@nrel_developer_key}")
108
+ return URI.parse("https://developer.nrel.gov/api/reopt/v2/job/#{run_uuid}/resilience_stats?api_key=#{@nrel_developer_key}")
120
109
  end
121
110
 
122
- def make_request(http, r, max_tries = 3)
111
+ def make_request(http, req, max_tries = 3)
123
112
  result = nil
124
113
  tries = 0
125
114
  while tries < max_tries
126
115
  begin
127
- result = http.request(r)
116
+ result = http.request(req)
128
117
  # Result codes sourced from https://developer.nrel.gov/docs/errors/
129
118
  if result.code == '429'
130
119
  @@logger.fatal('Exceeded the REopt-Lite API limit of 300 requests per hour')
131
120
  puts 'Using the URBANopt CLI to submit a Scenario optimization counts as one request per scenario'
132
121
  puts 'Using the URBANopt CLI to submit a Feature optimization counts as one request per feature'
133
122
  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')
123
+ elsif result.code == '404'
124
+ @@logger.info("REOpt is still calculating. We'll give it a moment and check again")
125
+ sleep 15
126
+ tries += 1
127
+ next
134
128
  elsif (result.code != '201') && (result.code != '200') # Anything in the 200s is success
135
- @@logger.debug("REopt-Lite has returned a '#{result.code}' status code. Visit https://developer.nrel.gov/docs/errors/ for more status code information")
129
+ @@logger.warn("REopt-Lite has returned a '#{result.code}' status code. Visit https://developer.nrel.gov/docs/errors/ for more status code information")
136
130
  # display error messages
137
131
  json_res = JSON.parse(result.body, allow_nan: true)
138
132
  json_res['messages'].delete('warnings') if json_res['messages']['warnings']
@@ -351,10 +345,10 @@ module URBANopt # :nodoc:
351
345
  sleep 5
352
346
  end
353
347
 
354
- _max_retry = 5
355
- _tries = 0
348
+ max_retry = 5
349
+ tries = 0
356
350
  (check_complete = sizes == 0) && ((data['outputs']['Scenario']['Site']['Financial']['npv_us_dollars'] || 0) > 0)
357
- while (_tries < _max_retry) && check_complete
351
+ while (tries < max_retry) && check_complete
358
352
  sleep 3
359
353
  response = make_request(http, get_request)
360
354
  data = JSON.parse(response.body, allow_nan: true)
@@ -368,7 +362,7 @@ module URBANopt # :nodoc:
368
362
  end
369
363
  sizes = pv_sizes + (data['outputs']['Scenario']['Site']['Storage']['size_kw'] || 0) + (data['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) + (data['outputs']['Scenario']['Site']['Generator']['size_kw'] || 0)
370
364
  (check_complete = sizes == 0) && ((data['outputs']['Scenario']['Site']['Financial']['npv_us_dollars'] || 0) > 0)
371
- _tries += 1
365
+ tries += 1
372
366
  end
373
367
 
374
368
  data = JSON.parse(response.body, allow_nan: true)
@@ -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.
@@ -43,6 +33,9 @@ require 'logger'
43
33
  module URBANopt
44
34
  module REopt
45
35
  @@reopt_logger = Logger.new($stdout)
36
+
37
+ # Set Logger::DEBUG for development
38
+ @@reopt_logger.level = Logger::WARN
46
39
  ##
47
40
  # Definining class variable "@@logger" to log errors, info and warning messages.
48
41
  def self.reopt_logger
@@ -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.
@@ -93,20 +83,19 @@ module URBANopt # :nodoc:
93
83
  @@logger.info("Created directory: #{File.join(fr.directory_name, 'reopt')}")
94
84
  end
95
85
  @feature_reports_reopt_default_output_files << File.join(fr.directory_name, "reopt/feature_report_#{fr.id}_reopt_run.json")
96
- end
97
-
98
- @scenario_report.feature_reports.each do |fr|
99
86
  @feature_reports_timeseries_default_output_files << File.join(fr.directory_name, "feature_report_#{fr.id}_timeseries.csv")
100
87
  end
101
88
  end
102
89
 
103
90
  if !scenario_reopt_assumptions_file.nil?
91
+ @scenario_reopt_assumptions_file = scenario_reopt_assumptions_file
104
92
  File.open(scenario_reopt_assumptions_file, 'r') do |file|
105
93
  @scenario_reopt_default_assumptions_hash = JSON.parse(file.read, symbolize_names: true)
106
94
  end
107
95
  end
108
96
 
109
97
  if !reopt_feature_assumptions.empty?
98
+ @reopt_feature_assumptions = reopt_feature_assumptions
110
99
  reopt_feature_assumptions.each do |file|
111
100
  @feature_reports_reopt_default_assumption_hashes << JSON.parse(File.open(file, 'r').read, symbolize_names: true)
112
101
  end
@@ -137,12 +126,13 @@ module URBANopt # :nodoc:
137
126
  reopt_output_file = File.join(feature_report.directory_name, 'reopt')
138
127
  end
139
128
  reopt_output = api.reopt_request(reopt_input, reopt_output_file)
129
+ @@logger.debug("REOpt output file: #{reopt_output_file}")
140
130
  if run_resilience
141
131
  run_uuid = reopt_output['outputs']['Scenario']['run_uuid']
142
132
  if File.directory? reopt_output_file
143
133
  resilience_stats = api.resilience_request(run_uuid, reopt_output_file)
144
134
  else
145
- resilience_stats = api.resilience_request(run_uuid, reopt_output_file.sub!('.json', '_resilience.json'))
135
+ resilience_stats = api.resilience_request(run_uuid, reopt_output_file.sub('.json', '_resilience.json'))
146
136
  end
147
137
  else
148
138
  resilience_stats = nil
@@ -167,8 +157,12 @@ module URBANopt # :nodoc:
167
157
  #
168
158
  # [*return:*] _URBANopt::Scenario::DefaultReports::ScenarioReport_ Returns an updated ScenarioReport
169
159
  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)
160
+ puts 'run scenario report'
161
+ @save_assumptions_filepath = false
170
162
  if !reopt_assumptions_hash.nil?
171
163
  @scenario_reopt_default_assumptions_hash = reopt_assumptions_hash
164
+ else
165
+ @save_assumptions_filepath = true
172
166
  end
173
167
  if !reopt_output_file.nil?
174
168
  @scenario_reopt_default_output_file = reopt_output_file
@@ -188,15 +182,21 @@ module URBANopt # :nodoc:
188
182
  if File.directory? @scenario_reopt_default_output_file
189
183
  resilience_stats = api.resilience_request(run_uuid, @scenario_reopt_default_output_file)
190
184
  else
191
- resilience_stats = api.resilience_request(run_uuid, @scenario_reopt_default_output_file.sub!('.json', '_resilience.json'))
185
+ resilience_stats = api.resilience_request(run_uuid, @scenario_reopt_default_output_file.sub('.json', '_resilience.json'))
192
186
  end
193
187
  else
194
188
  resilience_stats = nil
195
189
  end
196
190
 
197
191
  result = adapter.update_scenario_report(scenario_report, reopt_output, @scenario_timeseries_default_output_file, resilience_stats)
192
+ # can you save the assumptions file path that was used?
193
+ if @save_assumptions_filepath && @scenario_reopt_assumptions_file
194
+ result.distributed_generation.reopt_assumptions_file_path = @scenario_reopt_assumptions_file
195
+ end
196
+
198
197
  if !save_name.nil?
199
- result.save save_name
198
+ # don't save individual feature reports when doing the scenario optimization!
199
+ result.save(save_name, false)
200
200
  end
201
201
  return result
202
202
  end
@@ -251,7 +251,7 @@ module URBANopt # :nodoc:
251
251
  if File.directory? @feature_reports_reopt_default_output_files[idx]
252
252
  resilience_stats = api.resilience_request(run_uuid, @feature_reports_reopt_default_output_files[idx])
253
253
  else
254
- resilience_stats = api.resilience_request(run_uuid, @feature_reports_reopt_default_output_files[idx].sub!('.json', '_resilience.json'))
254
+ resilience_stats = api.resilience_request(run_uuid, @feature_reports_reopt_default_output_files[idx].sub('.json', '_resilience.json'))
255
255
  end
256
256
  else
257
257
  resilience_stats = nil
@@ -270,7 +270,7 @@ module URBANopt # :nodoc:
270
270
  @@logger.error("ERROR: #{e}")
271
271
  end
272
272
  else
273
- puts('Output file already exists...skipping')
273
+ @@logger.info('Output file already exists...skipping')
274
274
  end
275
275
  end
276
276
 
@@ -308,7 +308,7 @@ module URBANopt # :nodoc:
308
308
  # [*return:*] _URBANopt::Scenario::DefaultReports::ScenarioReport_ - Returns an updated ScenarioReport
309
309
  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)
310
310
  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)
311
- puts("KEEP EXISTING? #{keep_existing_output}")
311
+
312
312
  # only do this if you have run feature reports
313
313
  new_scenario_report = URBANopt::Reporting::DefaultReports::ScenarioReport.new
314
314
  if !new_feature_reports.empty?
@@ -577,7 +577,6 @@
577
577
  }
578
578
  }
579
579
  },
580
-
581
580
  "Storage": {
582
581
  "type": "object",
583
582
  "properties": {
@@ -1113,4 +1112,4 @@
1113
1112
  }
1114
1113
  }
1115
1114
  }
1116
- }
1115
+ }
@@ -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": {
@@ -540,4 +545,4 @@
540
545
  }
541
546
  }
542
547
  }
543
- }
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)