urbanopt-reopt 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +24 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- data/.github/pull_request_template.md +13 -0
- data/.gitignore +3 -1
- data/CHANGELOG.md +8 -0
- data/CONTRIBUTING.md +58 -0
- data/Gemfile +3 -4
- data/lib/urbanopt/reopt/feature_report_adapter.rb +157 -91
- data/lib/urbanopt/reopt/reopt_post_processor.rb +37 -15
- data/lib/urbanopt/reopt/scenario_report_adapter.rb +155 -96
- data/lib/urbanopt/reopt/version.rb +1 -1
- data/urbanopt-reopt.gemspec +1 -1
- metadata +6 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a833a15c613e58704915acea2d8a31cfd2ded2f9
|
4
|
+
data.tar.gz: 4aa9285353fb46787c73b12d7d6b4e47da0e4098
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 364198ba99ef78bc954f94519717abb17d7e24a9d1c46c08eee4b05c4881f6b510d1557e451f64ee8e42cf00c30c4892ddf018d1b5040d88f68c31456060fb46
|
7
|
+
data.tar.gz: 5040b4fdbee705eabd026c0139d76857b53fcd325aa6e0730f58eba29b5107c86d0bb8eb77c3fb064dc2173b60ed8077cb578e270305ef36ebdf09560aa1212a
|
@@ -0,0 +1,24 @@
|
|
1
|
+
---
|
2
|
+
name: Bug report
|
3
|
+
about: Create a report to help us improve
|
4
|
+
title: ''
|
5
|
+
labels: bug
|
6
|
+
assignees: ''
|
7
|
+
---
|
8
|
+
|
9
|
+
**Expected behavior**
|
10
|
+
_A clear and concise description of what you expected to happen._
|
11
|
+
|
12
|
+
**Actual behavior**
|
13
|
+
_A clear and concise description of what actually happens._
|
14
|
+
|
15
|
+
**To Reproduce**
|
16
|
+
Steps to reproduce the behavior:
|
17
|
+
|
18
|
+
1. Go to '...'
|
19
|
+
1. Enter '...'
|
20
|
+
1. Enter '...'
|
21
|
+
|
22
|
+
### Additional context
|
23
|
+
|
24
|
+
_E.g.: Windows, Mac, Linux? Are you behind a firewall? Do you have additional security constraints?_
|
@@ -0,0 +1,19 @@
|
|
1
|
+
---
|
2
|
+
name: Feature request
|
3
|
+
about: Suggest an idea for this project
|
4
|
+
title: ''
|
5
|
+
labels: enhancement
|
6
|
+
assignees: ''
|
7
|
+
---
|
8
|
+
|
9
|
+
**Is your feature request related to a problem?**
|
10
|
+
A clear and concise description of what the problem is: _I'm frustrated when [...]_
|
11
|
+
|
12
|
+
**Describe the solution you'd like**
|
13
|
+
A clear and concise description of what you want to happen
|
14
|
+
|
15
|
+
**Alternatives you've considered**
|
16
|
+
A clear and concise description of any alternative solutions or features you've considered
|
17
|
+
|
18
|
+
**Additional context**
|
19
|
+
Add any other context or screenshots about the feature request here
|
@@ -0,0 +1,13 @@
|
|
1
|
+
### Addresses #[issue number here]
|
2
|
+
|
3
|
+
### Pull Request Description
|
4
|
+
|
5
|
+
[description here]
|
6
|
+
|
7
|
+
### Checklist (Delete lines that don't apply)
|
8
|
+
|
9
|
+
- [ ] Unit tests have been added or updated
|
10
|
+
- [ ] Documentation has been modified appropriately
|
11
|
+
- [ ] All ci tests pass (green)
|
12
|
+
- [ ] An [ISSUE](https://github.com/urbanopt/urbanopt-cli/issues) has been created that this is addressing. Issues will get added to the Change Log when the change_log.rb script is run
|
13
|
+
- [ ] This branch is up-to-date with develop
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# URBANopt REopt Gem
|
2
2
|
|
3
|
+
## Version 0.2.0
|
4
|
+
|
5
|
+
* Handles multiple PV systems in the REopt Lite assumptions
|
6
|
+
* Changes REoptPostProcessor run_scenario and run_scenario_features methods to save feature and scenario reports with custom names
|
7
|
+
* Parses date from timeseries CSV when creating load profile for REopt job and when parsing optimized results
|
8
|
+
* Renames REopt timeseries CSV columns to include 'REopt' and units
|
9
|
+
|
10
|
+
|
3
11
|
## Version 0.1.0
|
4
12
|
|
5
13
|
* Initial release of URBANopt REopt Gem.
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# URBANopt Contribution Policy
|
2
|
+
|
3
|
+
## Version 1.0
|
4
|
+
|
5
|
+
The URBANopt team welcomes your contribution to the project. You can contribute to the URBANopt project in several ways: by using the software, reporting issues, contributing documentation, or contributing code back to the project. The GitHub [Contributing to Open Source](https://opensource.guide/how-to-contribute/) guide provides a good overview. If you contribute code, you agree that your contribution may be incorporated into the URBANopt Software Development Kit (SDK) and made available under the URBANopt SDK license.
|
6
|
+
|
7
|
+
The contribution process for URBANopt is composed of three steps:
|
8
|
+
|
9
|
+
## 1. Send consent email
|
10
|
+
|
11
|
+
In order for us to distribute your code as part of URBANopt under the URBANopt SDK [license](https://github.com/urbanopt/urbanopt-scenario-gem/blob/develop/LICENSE.md), we’ll need your consent. An email acknowledging your understanding of these terms and agreeing to them is all that will be asked of any contributor. Send an email to the URBANopt project manager ([see below](#documentation) for the address) including the following text and a list of co-contributors (if any):
|
12
|
+
|
13
|
+
*I agree to contribute to the URBANopt SDK. I agree to the following terms and conditions for my contributions: First, I agree that I am licensing the copyright to my contributions under the terms of the current URBANopt SDK license. Second, I hereby grant to Alliance for Sustainable Energy, LLC, to any successor manager and distributor of URBANopt SDK appointed by the U.S. Department of Energy, and to all recipients of a version of URBANopt SDK that includes my contributions, a non-exclusive, worldwide, royalty-free, irrevocable patent license under any patent claims owned by me, or owned by my employer and known to me, that are or will be,necessarily infringed upon by my contributions alone, or by combination of my contributions with the version of URBANopt SDK to which they are contributed, to make, have made, use, offer to sell, sell, import, and otherwise transfer any version of URBANopt SDK that includes my contributions, in source code and object code form. Third, I represent and warrant that I am authorized to make the contributions and grant the foregoing license(s). Additionally, if, to my knowledge, my employer has rights to intellectual property that covers my contributions, I represent and warrant that I have received permission to make these contributions and grant the foregoing license(s) on behalf of my employer.*
|
14
|
+
|
15
|
+
Once we have your consent on file, you’ll only need to redo it if conditions change (e.g. a change of employer).
|
16
|
+
|
17
|
+
## 2. Scope agreement and timeline commitment
|
18
|
+
|
19
|
+
If your contribution is small (e.g. a bug fix), simply submit your contribution via GitHub. If you find a bug, first make sure it is not an already known issue, then report it in the GitHub [issue tracker](https://github.com/urbanopt/urbanopt-scenario-gem/issues) for this repository. If your contribution is larger (e.g. a new feature or new functionality/capability), we’ll need to evaluate your proposed contribution first. We may ask you to revise your materials and make changes to it, which we will then re-review.
|
20
|
+
|
21
|
+
## 3. Technical contribution process
|
22
|
+
|
23
|
+
We want URBANopt to adhere to our established quality standards. Smaller, non-code contributions may not require as much review as code contributions, but all contributions will be reviewed. Code contributions will initially be in a source control branch, and then will be merged into the official URBANopt repository after review and approval. Any bugs, either discovered by you, us, or any users will be tracked in our issue tracker. We request that you take full responsibility for correcting bugs. Be aware that, unless notified otherwise, the correction of bugs takes precedence over the submission or creation of new code.
|
24
|
+
|
25
|
+
### Release Schedule
|
26
|
+
|
27
|
+
Contributions should be aligned with the URBANopt release schedule. The URBANopt SDK is currently released publicly two times each year (approximately on the last workday of March and October). There are cutoff dates for when new contributions are allowed for the upcoming release (approximately two weeks before release date). If your contribution is incomplete or comes in past the cutoff date for a release, we reserve the right to hold your code for a later release.
|
28
|
+
|
29
|
+
### Coding Standards
|
30
|
+
|
31
|
+
Make sure you read and follow the coding standards when writing URBANopt SDK code. Although these standards are not complete or very detailed, they should give you an idea of the style that we would like you to adopt. New additions to the URBANopt SDK must be written using object-oriented programming techniques and practices. Please also look at the URBANopt SDK code itself as an example of the preferred coding style.
|
32
|
+
|
33
|
+
### Code Reviews
|
34
|
+
|
35
|
+
You will be working and testing your code in a source control branch. When a piece of functionality is complete, tested and working, let us know and we will review your code. If the functionality that you contributed is complex, we may ask you for a written design document as well. We want your code to follow coding standards, be clear, readable, and maintainable, and of course it should do what it is supposed to do. We will look for errors, style issues, comments (or lack thereof), and any other issues in your code. We will inform you of our comments and we expect you to make the recommended changes. New re-reviews may be expected until the code complies with our required processes.
|
36
|
+
|
37
|
+
### Unit Tests
|
38
|
+
|
39
|
+
We ask that you supply unit tests along with the code that you have written. A unit test is a program that exercises your code in isolation to verify that it does what it is supposed to do. Your unit tests are very important to us. First, they give an indication that your code works according to its intended functionality. Second, we execute your unit tests automatically along with our unit tests to verify that the overall URBANopt SDK code continues to work.
|
40
|
+
|
41
|
+
### Code Coverage
|
42
|
+
|
43
|
+
We require that your unit tests provide an adequate coverage of the source code you are submitting. You will need to design your unit tests in such a way that all critical parts of the code (at least) are tested and verified.
|
44
|
+
|
45
|
+
### Documentation
|
46
|
+
|
47
|
+
Proper documentation is crucial for our users, without it users will not know how to use your contribution. We require that you create user documentation so that end users know how to use your new functionality.
|
48
|
+
|
49
|
+
For further questions or information:
|
50
|
+
|
51
|
+
- Ben Polly\
|
52
|
+
URBANopt Project Management\
|
53
|
+
ben.polly@nrel.gov\
|
54
|
+
(303) 384-7429
|
55
|
+
|
56
|
+
URBANopt is funded by the U.S. Department of Energy (DOE) and managed by the National Renewable Energy Laboratory (NREL).
|
57
|
+
|
58
|
+
URBANopt is developed in collaboration with NREL, LBNL, and private firms.
|
data/Gemfile
CHANGED
@@ -44,18 +44,17 @@ allow_local = ENV['FAVOR_LOCAL_GEMS']
|
|
44
44
|
if allow_local && File.exist?('../urbanopt-scenario-gem')
|
45
45
|
gem 'urbanopt-scenario', path: '../urbanopt-scenario-gem'
|
46
46
|
elsif allow_local
|
47
|
-
gem 'urbanopt-scenario', github: 'URBANopt/urbanopt-scenario-gem', branch: '
|
47
|
+
gem 'urbanopt-scenario', github: 'URBANopt/urbanopt-scenario-gem', branch: 'develop'
|
48
48
|
else
|
49
|
-
gem 'urbanopt-scenario', '0.
|
49
|
+
gem 'urbanopt-scenario', '0.2.0'
|
50
50
|
end
|
51
51
|
|
52
52
|
if allow_local && File.exists?('../urbanopt-geojson-gem')
|
53
|
-
# gem 'openstudio-extension', github: 'NREL/OpenStudio-extension-gem', branch: 'develop'
|
54
53
|
gem 'urbanopt-geojson', path: '../urbanopt-geojson-gem'
|
55
54
|
elsif allow_local
|
56
55
|
gem 'urbanopt-geojson', github: 'URBANopt/urbanopt-geojson-gem', branch: 'develop'
|
57
56
|
else
|
58
|
-
gem 'urbanopt-geojson', '0.
|
57
|
+
gem 'urbanopt-geojson', '0.2.0'
|
59
58
|
end
|
60
59
|
|
61
60
|
# simplecov has an unnecessary dependency on native json gem, use fork that does not require this
|
@@ -32,6 +32,7 @@ require 'urbanopt/scenario/default_reports'
|
|
32
32
|
require 'urbanopt/reopt/reopt_logger'
|
33
33
|
require 'csv'
|
34
34
|
require 'matrix'
|
35
|
+
require 'time'
|
35
36
|
|
36
37
|
module URBANopt # :nodoc:
|
37
38
|
module REopt # :nodoc:
|
@@ -74,7 +75,7 @@ module URBANopt # :nodoc:
|
|
74
75
|
requireds.each_with_index do |i, x|
|
75
76
|
if [nil, 0].include? x
|
76
77
|
n = requireds_names[i]
|
77
|
-
|
78
|
+
# @@logger.error("Missing value for #{n} - this is a required input")
|
78
79
|
raise "Missing value for #{n} - this is a required input"
|
79
80
|
end
|
80
81
|
end
|
@@ -95,20 +96,25 @@ module URBANopt # :nodoc:
|
|
95
96
|
reopt_inputs[:Scenario][:Site][:land_acres] = feature_report.program.site_area * 1.0 / 43560 # acres/sqft
|
96
97
|
end
|
97
98
|
|
99
|
+
unless feature_report.timesteps_per_hour.nil?
|
100
|
+
reopt_inputs[:Scenario][:time_steps_per_hour] = feature_report.timesteps_per_hour
|
101
|
+
end
|
102
|
+
|
98
103
|
# Parse Load Profile
|
99
104
|
begin
|
100
|
-
col_num = feature_report.timeseries_csv.column_names.index('Electricity:Facility')
|
105
|
+
col_num = feature_report.timeseries_csv.column_names.index('Electricity:Facility(kWh)')
|
101
106
|
t = CSV.read(feature_report.timeseries_csv.path, headers: true, converters: :numeric)
|
102
|
-
energy_timeseries_kwh = t.by_col[col_num].map { |e| ((e || 0)
|
103
|
-
if (feature_report.timesteps_per_hour
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
107
|
+
energy_timeseries_kwh = t.by_col[col_num].map { |e| ((e || 0) ) }
|
108
|
+
if energy_timeseries_kwh.length < (feature_report.timesteps_per_hour * 8760)
|
109
|
+
start_date = Time.parse(t.by_col["Datetime"][0])
|
110
|
+
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) /
|
111
|
+
(( 60 / feature_report.timesteps_per_hour ) * 60)).to_int
|
112
|
+
end_date = Time.parse(t.by_col["Datetime"][-1])
|
113
|
+
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) /
|
114
|
+
(( 60 / feature_report.timesteps_per_hour ) * 60)).to_int
|
115
|
+
energy_timeseries_kwh = [0.0]*(start_ts-1) + energy_timeseries_kwh + [0.0]*((feature_report.timesteps_per_hour * 8760) - end_ts)
|
110
116
|
end
|
111
|
-
reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw] = energy_timeseries_kwh.map { |e| e ? e : 0 }
|
117
|
+
reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw] = energy_timeseries_kwh.map { |e| e ? e : 0 }[0,(feature_report.timesteps_per_hour * 8760)]
|
112
118
|
rescue StandardError
|
113
119
|
@@logger.error("Could not parse the annual electric load from the timeseries csv - #{feature_report.timeseries_csv.path}")
|
114
120
|
raise "Could not parse the annual electric load from the timeseries csv - #{feature_report.timeseries_csv.path}"
|
@@ -133,6 +139,26 @@ module URBANopt # :nodoc:
|
|
133
139
|
@@logger.info("Warning cannot Feature Report #{feature_report.name} #{feature_report.id} - REopt optimization was non-optimal")
|
134
140
|
return feature_report
|
135
141
|
end
|
142
|
+
|
143
|
+
$ts_per_hour = feature_report.timesteps_per_hour
|
144
|
+
def scale_timeseries(input, ts_per_hr=$ts_per_hour)
|
145
|
+
if input.nil?
|
146
|
+
return nil
|
147
|
+
end
|
148
|
+
if input.length ==0
|
149
|
+
return nil
|
150
|
+
end
|
151
|
+
if input.length == (8760 * ts_per_hr)
|
152
|
+
return input
|
153
|
+
end
|
154
|
+
result = []
|
155
|
+
input.each do |val|
|
156
|
+
(1..ts_per_hr).each do |x|
|
157
|
+
result.push(val/ts_per_hr.to_f)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
return result
|
161
|
+
end
|
136
162
|
|
137
163
|
# Update location
|
138
164
|
feature_report.location.latitude = reopt_output['inputs']['Scenario']['Site']['latitude']
|
@@ -142,36 +168,57 @@ module URBANopt # :nodoc:
|
|
142
168
|
feature_report.timesteps_per_hour = reopt_output['inputs']['Scenario']['time_steps_per_hour']
|
143
169
|
|
144
170
|
# Update distributed generation sizing and financials
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
171
|
+
feature_report.distributed_generation.lcc_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['lcc_us_dollars'] || 0
|
172
|
+
feature_report.distributed_generation.npv_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['npv_us_dollars'] || 0
|
173
|
+
feature_report.distributed_generation.year_one_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_energy_cost_us_dollars'] || 0
|
174
|
+
feature_report.distributed_generation.year_one_demand_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_demand_cost_us_dollars'] || 0
|
175
|
+
feature_report.distributed_generation.year_one_bill_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_bill_us_dollars'] || 0
|
176
|
+
feature_report.distributed_generation.total_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['total_energy_cost_us_dollars'] || 0
|
177
|
+
|
178
|
+
if reopt_output['outputs']['Scenario']['Site']['PV'].class == Hash
|
179
|
+
reopt_output['outputs']['Scenario']['Site']['PV'] = [reopt_output['outputs']['Scenario']['Site']['PV']]
|
180
|
+
elsif reopt_output['outputs']['Scenario']['Site']['PV'].nil?
|
181
|
+
reopt_output['outputs']['Scenario']['Site']['PV'] = []
|
182
|
+
end
|
183
|
+
|
184
|
+
reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
|
185
|
+
feature_report.distributed_generation.add_tech 'solar_pv', URBANopt::Scenario::DefaultReports::SolarPV.new( {size_kw: (pv['size_kw'] || 0), id: i })
|
186
|
+
end
|
187
|
+
|
188
|
+
wind = reopt_output['outputs']['Scenario']['Site']['Wind']
|
189
|
+
if !wind['size_kw'].nil? and wind['size_kw'] != 0
|
190
|
+
feature_report.distributed_generation.add_tech 'wind', URBANopt::Scenario::DefaultReports::Wind.new( {size_kw: (wind['size_kw'] || 0) })
|
191
|
+
end
|
157
192
|
|
193
|
+
generator = reopt_output['outputs']['Scenario']['Site']['Generator']
|
194
|
+
if !generator['size_kw'].nil? and generator['size_kw'] != 0
|
195
|
+
feature_report.distributed_generation.add_tech 'generator', URBANopt::Scenario::DefaultReports::Generator.new( {size_kw: (generator['size_kw'] || 0) })
|
196
|
+
end
|
197
|
+
|
198
|
+
storage = reopt_output['outputs']['Scenario']['Site']['Storage']
|
199
|
+
if !storage['size_kw'].nil? and storage['size_kw'] != 0
|
200
|
+
feature_report.distributed_generation.add_tech 'storage', URBANopt::Scenario::DefaultReports::Storage.new( {size_kwh: (storage['size_kwh'] || 0), size_kw: (storage['size_kw'] || 0) })
|
201
|
+
end
|
202
|
+
|
158
203
|
generation_timeseries_kwh = Matrix[[0] * 8760]
|
159
204
|
|
160
205
|
unless reopt_output['outputs']['Scenario']['Site']['PV'].nil?
|
161
|
-
|
162
|
-
if
|
163
|
-
|
206
|
+
reopt_output['outputs']['Scenario']['Site']['PV'].each do |pv|
|
207
|
+
if (pv['size_kw'] || 0) > 0
|
208
|
+
if !pv['year_one_power_production_series_kw'].nil?
|
209
|
+
generation_timeseries_kwh += Matrix[pv['year_one_power_production_series_kw']]
|
210
|
+
end
|
164
211
|
end
|
165
|
-
|
212
|
+
end
|
166
213
|
end
|
167
214
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
215
|
+
unless reopt_output['outputs']['Scenario']['Site']['Storage'].nil?
|
216
|
+
if (reopt_output['outputs']['Scenario']['Site']['Storage']['size_kw'] or 0) > 0
|
217
|
+
if !reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'].nil?
|
218
|
+
generation_timeseries_kwh = generation_timeseries_kwh + Matrix[reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']]
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
175
222
|
|
176
223
|
unless reopt_output['outputs']['Scenario']['Site']['Wind'].nil?
|
177
224
|
if (reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) > 0
|
@@ -190,136 +237,152 @@ module URBANopt # :nodoc:
|
|
190
237
|
end
|
191
238
|
|
192
239
|
$generation_timeseries_kwh = generation_timeseries_kwh.to_a[0] || [0] * 8760
|
193
|
-
$generation_timeseries_kwh_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:Total')
|
240
|
+
$generation_timeseries_kwh_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Total(kw)')
|
194
241
|
if $generation_timeseries_kwh_col.nil?
|
195
242
|
$generation_timeseries_kwh_col = feature_report.timeseries_csv.column_names.length
|
196
|
-
feature_report.timeseries_csv.column_names.push('ElectricityProduced:Total')
|
243
|
+
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Total(kw)')
|
197
244
|
end
|
198
245
|
|
199
|
-
$load = reopt_output['outputs']['Scenario']['Site']['LoadProfile']['year_one_electric_load_series_kw'] || [0] * 8760
|
200
|
-
$load_col = feature_report.timeseries_csv.column_names.index('Electricity:Load:Total')
|
246
|
+
$load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['LoadProfile']['year_one_electric_load_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
247
|
+
$load_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Load:Total(kw)')
|
201
248
|
if $load_col.nil?
|
202
249
|
$load_col = feature_report.timeseries_csv.column_names.length
|
203
|
-
feature_report.timeseries_csv.column_names.push('Electricity:Load:Total')
|
250
|
+
feature_report.timeseries_csv.column_names.push('REopt:Electricity:Load:Total(kw)')
|
204
251
|
end
|
205
252
|
|
206
|
-
$utility_to_load = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_load_series_kw'] || [0] * 8760
|
207
|
-
$utility_to_load_col = feature_report.timeseries_csv.column_names.index('Electricity:Grid:ToLoad')
|
253
|
+
$utility_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_load_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
254
|
+
$utility_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToLoad(kw)')
|
208
255
|
if $utility_to_load_col.nil?
|
209
256
|
$utility_to_load_col = feature_report.timeseries_csv.column_names.length
|
210
|
-
feature_report.timeseries_csv.column_names.push('Electricity:Grid:ToLoad')
|
257
|
+
feature_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToLoad(kw)')
|
211
258
|
end
|
212
259
|
|
213
|
-
$utility_to_battery = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_battery_series_kw'] || [0] * 8760
|
214
|
-
$utility_to_battery_col = feature_report.timeseries_csv.column_names.index('Electricity:Grid:ToBattery')
|
260
|
+
$utility_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_battery_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
261
|
+
$utility_to_battery_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToBattery(kw)')
|
215
262
|
if $utility_to_battery_col.nil?
|
216
263
|
$utility_to_battery_col = feature_report.timeseries_csv.column_names.length
|
217
|
-
feature_report.timeseries_csv.column_names.push('Electricity:Grid:ToBattery')
|
264
|
+
feature_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToBattery(kw)')
|
218
265
|
end
|
219
266
|
|
220
|
-
$storage_to_load = reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw'] || [0] * 8760
|
221
|
-
$storage_to_load_col = feature_report.timeseries_csv.column_names.index('Electricity:Storage:ToLoad')
|
267
|
+
$storage_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
268
|
+
$storage_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToLoad(kw)')
|
222
269
|
if $storage_to_load_col.nil?
|
223
270
|
$storage_to_load_col = feature_report.timeseries_csv.column_names.length
|
224
|
-
feature_report.timeseries_csv.column_names.push('Electricity:Storage:ToLoad')
|
271
|
+
feature_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToLoad(kw)')
|
225
272
|
end
|
226
273
|
|
227
|
-
$storage_to_grid = reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'] || [0] * 8760
|
228
|
-
$storage_to_grid_col = feature_report.timeseries_csv.column_names.index('Electricity:Storage:ToGrid')
|
274
|
+
$storage_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
275
|
+
$storage_to_grid_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToGrid(kw)')
|
229
276
|
if $storage_to_grid_col.nil?
|
230
277
|
$storage_to_grid_col = feature_report.timeseries_csv.column_names.length
|
231
|
-
feature_report.timeseries_csv.column_names.push('Electricity:Storage:ToGrid')
|
278
|
+
feature_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToGrid(kw)')
|
232
279
|
end
|
233
280
|
|
234
|
-
$storage_soc = reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct'] || [0] * 8760
|
235
|
-
$storage_soc_col = feature_report.timeseries_csv.column_names.index('Electricity:Storage:StateOfCharge')
|
281
|
+
$storage_soc = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
282
|
+
$storage_soc_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:StateOfCharge(pct)')
|
236
283
|
if $storage_soc_col.nil?
|
237
284
|
$storage_soc_col = feature_report.timeseries_csv.column_names.length
|
238
|
-
feature_report.timeseries_csv.column_names.push('Electricity:Storage:StateOfCharge')
|
285
|
+
feature_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:StateOfCharge(pct)')
|
239
286
|
end
|
240
287
|
|
241
|
-
$generator_total = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'] || [0] * 8760
|
242
|
-
$generator_total_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:Total')
|
288
|
+
$generator_total = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
289
|
+
$generator_total_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:Total(kw)')
|
243
290
|
if $generator_total_col.nil?
|
244
291
|
$generator_total_col = feature_report.timeseries_csv.column_names.length
|
245
|
-
feature_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:Total')
|
292
|
+
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:Total(kw)')
|
246
293
|
end
|
247
294
|
|
248
|
-
$generator_to_battery = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_battery_series_kw'] || [0] * 8760
|
249
|
-
$generator_to_battery_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:ToBattery')
|
295
|
+
$generator_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_battery_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
296
|
+
$generator_to_battery_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToBattery(kw)')
|
250
297
|
if $generator_to_battery_col.nil?
|
251
298
|
$generator_to_battery_col = feature_report.timeseries_csv.column_names.length
|
252
|
-
feature_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToBattery')
|
299
|
+
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToBattery(kw)')
|
253
300
|
end
|
254
301
|
|
255
|
-
$generator_to_load = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw'] || [0] * 8760
|
256
|
-
$generator_to_load_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:ToLoad')
|
302
|
+
$generator_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
303
|
+
$generator_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToLoad(kw)')
|
257
304
|
if $generator_to_load_col.nil?
|
258
305
|
$generator_to_load_col = feature_report.timeseries_csv.column_names.length
|
259
|
-
feature_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToLoad')
|
306
|
+
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToLoad(kw)')
|
260
307
|
end
|
261
308
|
|
262
|
-
$generator_to_grid = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_grid_series_kw'] || [0] * 8760
|
263
|
-
$generator_to_grid_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:ToGrid')
|
309
|
+
$generator_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_grid_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
310
|
+
$generator_to_grid_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToGrid(kw)')
|
264
311
|
if $generator_to_grid_col.nil?
|
265
312
|
$generator_to_grid_col = feature_report.timeseries_csv.column_names.length
|
266
|
-
feature_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToGrid')
|
313
|
+
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToGrid(kw)')
|
267
314
|
end
|
268
315
|
|
269
|
-
$
|
270
|
-
$pv_total_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:PV:Total')
|
316
|
+
$pv_total_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:Total(kw)')
|
271
317
|
if $pv_total_col.nil?
|
272
318
|
$pv_total_col = feature_report.timeseries_csv.column_names.length
|
273
|
-
feature_report.timeseries_csv.column_names.push('ElectricityProduced:PV:Total')
|
319
|
+
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:Total(kw)')
|
274
320
|
end
|
275
321
|
|
276
|
-
$
|
277
|
-
$pv_to_battery_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToBattery')
|
322
|
+
$pv_to_battery_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToBattery(kw)')
|
278
323
|
if $pv_to_battery_col.nil?
|
279
324
|
$pv_to_battery_col = feature_report.timeseries_csv.column_names.length
|
280
|
-
feature_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToBattery')
|
325
|
+
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToBattery(kw)')
|
281
326
|
end
|
282
327
|
|
283
|
-
$
|
284
|
-
$pv_to_load_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToLoad')
|
328
|
+
$pv_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToLoad(kw)')
|
285
329
|
if $pv_to_load_col.nil?
|
286
330
|
$pv_to_load_col = feature_report.timeseries_csv.column_names.length
|
287
|
-
feature_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToLoad')
|
331
|
+
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToLoad(kw)')
|
288
332
|
end
|
289
333
|
|
290
|
-
|
291
|
-
$pv_to_grid_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToGrid')
|
334
|
+
|
335
|
+
$pv_to_grid_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToGrid(kw)')
|
292
336
|
if $pv_to_grid_col.nil?
|
293
337
|
$pv_to_grid_col = feature_report.timeseries_csv.column_names.length
|
294
|
-
feature_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToGrid')
|
338
|
+
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToGrid(kw)')
|
339
|
+
end
|
340
|
+
|
341
|
+
$pv_total = Matrix[[0] * (8760 * feature_report.timesteps_per_hour)]
|
342
|
+
$pv_to_battery = Matrix[[0] * (8760 * feature_report.timesteps_per_hour)]
|
343
|
+
$pv_to_load = Matrix[[0] * (8760 * feature_report.timesteps_per_hour)]
|
344
|
+
$pv_to_grid = Matrix[[0] * (8760 * feature_report.timesteps_per_hour)]
|
345
|
+
|
346
|
+
reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
|
347
|
+
if (pv['size_kw'] || 0) > 0
|
348
|
+
$pv_total += Matrix[scale_timeseries(pv['year_one_power_production_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)]
|
349
|
+
$pv_to_battery += Matrix[scale_timeseries(pv['year_one_to_battery_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)]
|
350
|
+
$pv_to_load += Matrix[scale_timeseries(pv['year_one_to_load_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)]
|
351
|
+
$pv_to_grid += Matrix[scale_timeseries(pv['year_one_to_grid_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)]
|
352
|
+
end
|
295
353
|
end
|
296
354
|
|
297
|
-
$
|
298
|
-
$
|
355
|
+
$pv_total = $pv_total.to_a[0]
|
356
|
+
$pv_to_battery = $pv_to_battery.to_a[0]
|
357
|
+
$pv_to_load = $pv_to_load.to_a[0]
|
358
|
+
$pv_to_grid = $pv_to_grid.to_a[0]
|
359
|
+
|
360
|
+
$wind_total = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
361
|
+
$wind_total_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:Total(kw)')
|
299
362
|
if $wind_total_col.nil?
|
300
363
|
$wind_total_col = feature_report.timeseries_csv.column_names.length
|
301
|
-
feature_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:Total')
|
364
|
+
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:Total(kw)')
|
302
365
|
end
|
303
366
|
|
304
|
-
$wind_to_battery = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_battery_series_kw'] || [0] * 8760
|
305
|
-
$wind_to_battery_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:ToBattery')
|
367
|
+
$wind_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_battery_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
368
|
+
$wind_to_battery_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToBattery(kw)')
|
306
369
|
if $wind_to_battery_col.nil?
|
307
370
|
$wind_to_battery_col = feature_report.timeseries_csv.column_names.length
|
308
|
-
feature_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToBattery')
|
371
|
+
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToBattery(kw)')
|
309
372
|
end
|
310
373
|
|
311
|
-
$wind_to_load = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_load_series_kw'] || [0] * 8760
|
312
|
-
$wind_to_load_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:ToLoad')
|
374
|
+
$wind_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_load_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
375
|
+
$wind_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToLoad(kw)')
|
313
376
|
if $wind_to_load_col.nil?
|
314
377
|
$wind_to_load_col = feature_report.timeseries_csv.column_names.length
|
315
|
-
feature_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToLoad')
|
378
|
+
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToLoad(kw)')
|
316
379
|
end
|
317
380
|
|
318
|
-
$wind_to_grid = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_grid_series_kw'] || [0] * 8760
|
319
|
-
$wind_to_grid_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:ToGrid')
|
381
|
+
$wind_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_grid_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
|
382
|
+
$wind_to_grid_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToGrid(kw)')
|
320
383
|
if $wind_to_grid_col.nil?
|
321
384
|
$wind_to_grid_col = feature_report.timeseries_csv.column_names.length
|
322
|
-
feature_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToGrid')
|
385
|
+
feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToGrid(kw)')
|
323
386
|
end
|
324
387
|
|
325
388
|
def modrow(x, i) # :nodoc:
|
@@ -346,9 +409,12 @@ module URBANopt # :nodoc:
|
|
346
409
|
end
|
347
410
|
|
348
411
|
old_data = CSV.open(feature_report.timeseries_csv.path).read
|
412
|
+
start_date = Time.parse(old_data[1][0])
|
413
|
+
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) / (( 60 / feature_report.timesteps_per_hour ) * 60)).to_int
|
414
|
+
|
349
415
|
mod_data = old_data.map.with_index do |x, i|
|
350
416
|
if i > 0
|
351
|
-
modrow(x, i)
|
417
|
+
modrow(x, start_ts + i -2)
|
352
418
|
else
|
353
419
|
x
|
354
420
|
end
|
@@ -70,11 +70,18 @@ module URBANopt # :nodoc:
|
|
70
70
|
if !scenario_report.nil?
|
71
71
|
@scenario_report = scenario_report
|
72
72
|
|
73
|
-
|
73
|
+
if !Dir.exist?(File.join(@scenario_report.directory_name, "reopt"))
|
74
|
+
Dir.mkdir(File.join(@scenario_report.directory_name, "reopt"))
|
75
|
+
end
|
76
|
+
|
77
|
+
@scenario_reopt_default_output_file = File.join(@scenario_report.directory_name, "reopt/scenario_report_#{@scenario_report.id}_reopt_run.json")
|
74
78
|
@scenario_timeseries_default_output_file = File.join(@scenario_report.directory_name, "scenario_report_#{@scenario_report.id}_timeseries.csv")
|
75
79
|
|
76
80
|
@scenario_report.feature_reports.each do |fr|
|
77
|
-
|
81
|
+
if !Dir.exist?(File.join(fr.directory_name, "reopt"))
|
82
|
+
Dir.mkdir(File.join(fr.directory_name, "reopt"))
|
83
|
+
end
|
84
|
+
@feature_reports_reopt_default_output_files << File.join(fr.directory_name, "reopt/feature_report_#{fr.id}_reopt_run.json")
|
78
85
|
end
|
79
86
|
|
80
87
|
@scenario_report.feature_reports.each do |fr|
|
@@ -111,7 +118,7 @@ module URBANopt # :nodoc:
|
|
111
118
|
#
|
112
119
|
# [*return:*] _URBANopt::Scenario::DefaultReports::FeatureReport_ - Returns an updated FeatureReport
|
113
120
|
##
|
114
|
-
def run_feature_report(feature_report
|
121
|
+
def run_feature_report(feature_report:, reopt_assumptions_hash:nil, reopt_output_file:nil, timeseries_csv_path:nil, save_name:nil)
|
115
122
|
api = URBANopt::REopt::REoptLiteAPI.new(@nrel_developer_key, @localhost)
|
116
123
|
adapter = URBANopt::REopt::FeatureReportAdapter.new
|
117
124
|
|
@@ -120,7 +127,11 @@ module URBANopt # :nodoc:
|
|
120
127
|
reopt_output_file = feature_report.directory_name
|
121
128
|
end
|
122
129
|
reopt_output = api.reopt_request(reopt_input, reopt_output_file)
|
123
|
-
|
130
|
+
result = adapter.update_feature_report(feature_report, reopt_output, timeseries_csv_path)
|
131
|
+
if !save_name.nil?
|
132
|
+
result.save_feature_report save_name
|
133
|
+
end
|
134
|
+
return result
|
124
135
|
end
|
125
136
|
|
126
137
|
##
|
@@ -135,7 +146,7 @@ module URBANopt # :nodoc:
|
|
135
146
|
# * +timeseries_csv_path+ - _String_ - Optional. Path to a file at which the new timeseries CSV for the ScenarioReport will be saved.
|
136
147
|
#
|
137
148
|
# [*return:*] _URBANopt::Scenario::DefaultReports::ScenarioReport_ Returns an updated ScenarioReport
|
138
|
-
def run_scenario_report(scenario_report
|
149
|
+
def run_scenario_report(scenario_report:, reopt_assumptions_hash:nil, reopt_output_file:nil, timeseries_csv_path:nil, save_name:nil)
|
139
150
|
if !reopt_assumptions_hash.nil?
|
140
151
|
@scenario_reopt_default_assumptions_hash = reopt_assumptions_hash
|
141
152
|
end
|
@@ -153,7 +164,11 @@ module URBANopt # :nodoc:
|
|
153
164
|
|
154
165
|
reopt_output = api.reopt_request(reopt_input, @scenario_reopt_default_output_file)
|
155
166
|
|
156
|
-
|
167
|
+
result = adapter.update_scenario_report(scenario_report, reopt_output, @scenario_timeseries_default_output_file)
|
168
|
+
if !save_name.nil?
|
169
|
+
result.save save_name
|
170
|
+
end
|
171
|
+
return result
|
157
172
|
end
|
158
173
|
|
159
174
|
# Updates a set of FeatureReports based on an optional set of \REopt Lite optimization assumptions.
|
@@ -167,7 +182,8 @@ module URBANopt # :nodoc:
|
|
167
182
|
# * +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.
|
168
183
|
#
|
169
184
|
# [*return:*] _Array_ Returns an array of updated _URBANopt::Scenario::DefaultReports::FeatureReport_ objects
|
170
|
-
def run_feature_reports(feature_reports
|
185
|
+
def run_feature_reports(feature_reports:, reopt_assumptions_hashes:[], reopt_output_files:[], timeseries_csv_paths:[], save_names:nil)
|
186
|
+
|
171
187
|
if !reopt_assumptions_hashes.empty?
|
172
188
|
@feature_reports_reopt_default_assumption_hashes = reopt_assumptions_hashes
|
173
189
|
end
|
@@ -182,7 +198,7 @@ module URBANopt # :nodoc:
|
|
182
198
|
|
183
199
|
if @feature_reports_reopt_default_output_files.empty?
|
184
200
|
feature_reports.each do |fr|
|
185
|
-
@feature_reports_reopt_default_output_files << File.join(fr.directory_name, "feature_report_#{fr.id}_reopt_run.json")
|
201
|
+
@feature_reports_reopt_default_output_files << File.join(fr.directory_name, "reopt/feature_report_#{fr.id}_reopt_run.json")
|
186
202
|
end
|
187
203
|
end
|
188
204
|
|
@@ -198,17 +214,21 @@ module URBANopt # :nodoc:
|
|
198
214
|
feature_reports.each_with_index do |feature_report, idx|
|
199
215
|
begin
|
200
216
|
reopt_input = feature_adapter.reopt_json_from_feature_report(feature_report, @feature_reports_reopt_default_assumption_hashes[idx])
|
201
|
-
if reopt_output_files[idx].nil?
|
202
|
-
reopt_output_files[idx] = feature_report.directory_name
|
203
|
-
end
|
204
217
|
reopt_output = api.reopt_request(reopt_input, @feature_reports_reopt_default_output_files[idx])
|
205
218
|
new_feature_report = feature_adapter.update_feature_report(feature_report, reopt_output, @feature_reports_timeseries_default_output_files[idx])
|
206
219
|
new_feature_reports.push(new_feature_report)
|
220
|
+
if !save_names.nil?
|
221
|
+
if save_names.length == feature_reports.length
|
222
|
+
new_feature_report.save_feature_report save_names[idx]
|
223
|
+
else
|
224
|
+
warn "Could not save feature reports - the number of save names provided did not match the number of feature reports"
|
225
|
+
end
|
226
|
+
end
|
207
227
|
rescue StandardError
|
208
228
|
@@logger.info("Could not optimize Feature Report #{feature_report.name} #{feature_report.id}")
|
209
229
|
end
|
210
230
|
end
|
211
|
-
|
231
|
+
|
212
232
|
return new_feature_reports
|
213
233
|
end
|
214
234
|
|
@@ -223,8 +243,8 @@ module URBANopt # :nodoc:
|
|
223
243
|
# * +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.
|
224
244
|
#
|
225
245
|
# [*return:*] _URBANopt::Scenario::DefaultReports::ScenarioReport_ - Returns an updated ScenarioReport
|
226
|
-
def run_scenario_report_features(scenario_report
|
227
|
-
new_feature_reports = run_feature_reports(scenario_report.feature_reports, reopt_assumptions_hashes, reopt_output_files, feature_report_timeseries_csv_paths)
|
246
|
+
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)
|
247
|
+
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)
|
228
248
|
|
229
249
|
new_scenario_report = URBANopt::Scenario::DefaultReports::ScenarioReport.new
|
230
250
|
new_scenario_report.id = scenario_report.id
|
@@ -237,7 +257,9 @@ module URBANopt # :nodoc:
|
|
237
257
|
new_feature_reports.each do |feature_report|
|
238
258
|
new_scenario_report.add_feature_report(feature_report)
|
239
259
|
end
|
240
|
-
|
260
|
+
if !save_name_scenario_report.nil?
|
261
|
+
new_scenario_report.save save_name_scenario_report
|
262
|
+
end
|
241
263
|
return new_scenario_report
|
242
264
|
end
|
243
265
|
end
|
@@ -30,8 +30,9 @@
|
|
30
30
|
|
31
31
|
require 'urbanopt/scenario/default_reports'
|
32
32
|
require 'urbanopt/reopt/reopt_logger'
|
33
|
-
|
33
|
+
require 'matrix'
|
34
34
|
require 'csv'
|
35
|
+
require 'time'
|
35
36
|
|
36
37
|
module URBANopt # :nodoc:
|
37
38
|
module REopt # :nodoc:
|
@@ -116,23 +117,23 @@ module URBANopt # :nodoc:
|
|
116
117
|
|
117
118
|
# Update load profile info
|
118
119
|
begin
|
119
|
-
col_num = scenario_report.timeseries_csv.column_names.index('Electricity:Facility')
|
120
|
+
col_num = scenario_report.timeseries_csv.column_names.index('Electricity:Facility(kWh)')
|
120
121
|
t = CSV.read(scenario_report.timeseries_csv.path, headers: true, converters: :numeric)
|
121
|
-
energy_timeseries_kwh = t.by_col[col_num].map { |e| ((e || 0)
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
122
|
+
energy_timeseries_kwh = t.by_col[col_num].map { |e| ((e || 0) ) }
|
123
|
+
if energy_timeseries_kwh.length < (scenario_report.timesteps_per_hour * 8760)
|
124
|
+
start_date = Time.parse(t.by_col["Datetime"][0])
|
125
|
+
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) /
|
126
|
+
(( 60 / scenario_report.timesteps_per_hour ) * 60)).to_int
|
127
|
+
end_date = Time.parse(t.by_col["Datetime"][-1])
|
128
|
+
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) /
|
129
|
+
(( 60 / scenario_report.timesteps_per_hour ) * 60)).to_int
|
130
|
+
energy_timeseries_kwh = [0.0]*(start_ts-1) + energy_timeseries_kwh + [0.0]*((scenario_report.timesteps_per_hour * 8760) - end_ts)
|
130
131
|
end
|
131
|
-
reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw] = energy_timeseries_kwh
|
132
|
+
reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw] = energy_timeseries_kwh.map { |e| e ? e : 0 }[0,(scenario_report.timesteps_per_hour * 8760)]
|
132
133
|
rescue StandardError
|
134
|
+
@@logger.error("Could not parse the annual electric load from the timeseries csv - #{scenario_report.timeseries_csv.path}")
|
133
135
|
raise "Could not parse the annual electric load from the timeseries csv - #{scenario_report.timeseries_csv.path}"
|
134
136
|
end
|
135
|
-
|
136
137
|
return reopt_inputs
|
137
138
|
end
|
138
139
|
|
@@ -174,6 +175,26 @@ module URBANopt # :nodoc:
|
|
174
175
|
@@logger.info("Warning cannot Feature Report #{scenario_report.name} #{scenario_report.id} - REopt optimization was non-optimal")
|
175
176
|
return scenario_report
|
176
177
|
end
|
178
|
+
|
179
|
+
$ts_per_hour = scenario_report.timesteps_per_hour
|
180
|
+
def scale_timeseries(input, ts_per_hr=$ts_per_hour)
|
181
|
+
if input.nil?
|
182
|
+
return nil
|
183
|
+
end
|
184
|
+
if input.length ==0
|
185
|
+
return nil
|
186
|
+
end
|
187
|
+
if input.length == (8760 * ts_per_hr)
|
188
|
+
return input
|
189
|
+
end
|
190
|
+
result = []
|
191
|
+
input.each do |val|
|
192
|
+
(1..ts_per_hr).each do |x|
|
193
|
+
result.push(val/ts_per_hr.to_f)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
return result
|
197
|
+
end
|
177
198
|
|
178
199
|
# Update location
|
179
200
|
scenario_report.location.latitude = reopt_output['inputs']['Scenario']['Site']['latitude']
|
@@ -183,36 +204,57 @@ module URBANopt # :nodoc:
|
|
183
204
|
scenario_report.timesteps_per_hour = reopt_output['inputs']['Scenario']['time_steps_per_hour']
|
184
205
|
|
185
206
|
# Update distributed generation sizing and financials
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
207
|
+
|
208
|
+
scenario_report.distributed_generation.lcc_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['lcc_us_dollars'] || 0
|
209
|
+
scenario_report.distributed_generation.npv_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['npv_us_dollars'] || 0
|
210
|
+
scenario_report.distributed_generation.year_one_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_energy_cost_us_dollars'] || 0
|
211
|
+
scenario_report.distributed_generation.year_one_demand_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_demand_cost_us_dollars'] || 0
|
212
|
+
scenario_report.distributed_generation.year_one_bill_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_bill_us_dollars'] || 0
|
213
|
+
scenario_report.distributed_generation.total_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['total_energy_cost_us_dollars'] || 0
|
214
|
+
|
215
|
+
if reopt_output['outputs']['Scenario']['Site']['PV'].class == Hash
|
216
|
+
reopt_output['outputs']['Scenario']['Site']['PV'] = [reopt_output['outputs']['Scenario']['Site']['PV']]
|
217
|
+
elsif reopt_output['outputs']['Scenario']['Site']['PV'].nil?
|
218
|
+
reopt_output['outputs']['Scenario']['Site']['PV'] = []
|
219
|
+
end
|
220
|
+
|
221
|
+
reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
|
222
|
+
scenario_report.distributed_generation.add_tech 'solar_pv', URBANopt::Scenario::DefaultReports::SolarPV.new( {size_kw: (pv['size_kw'] || 0), id: i })
|
223
|
+
end
|
224
|
+
|
225
|
+
wind = reopt_output['outputs']['Scenario']['Site']['Wind']
|
226
|
+
if !wind['size_kw'].nil? and wind['size_kw'] != 0
|
227
|
+
scenario_report.distributed_generation.add_tech 'wind', URBANopt::Scenario::DefaultReports::Wind.new( {size_kw: (wind['size_kw'] || 0) })
|
228
|
+
end
|
229
|
+
|
230
|
+
generator = reopt_output['outputs']['Scenario']['Site']['Generator']
|
231
|
+
if !generator['size_kw'].nil? and generator['size_kw'] != 0
|
232
|
+
scenario_report.distributed_generation.add_tech 'generator', URBANopt::Scenario::DefaultReports::Generator.new( {size_kw: (generator['size_kw'] || 0) })
|
233
|
+
end
|
234
|
+
|
235
|
+
storage = reopt_output['outputs']['Scenario']['Site']['Storage']
|
236
|
+
if !storage['size_kw'].nil? and storage['size_kw'] != 0
|
237
|
+
scenario_report.distributed_generation.add_tech 'storage', URBANopt::Scenario::DefaultReports::Storage.new( {size_kwh: (storage['size_kwh'] || 0), size_kw: (storage['size_kw'] || 0) })
|
238
|
+
end
|
239
|
+
|
200
240
|
generation_timeseries_kwh = Matrix[[0] * 8760]
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
241
|
+
|
242
|
+
|
243
|
+
reopt_output['outputs']['Scenario']['Site']['PV'].each do |pv|
|
244
|
+
if (pv['size_kw'] || 0) > 0
|
245
|
+
if !pv['year_one_power_production_series_kw'].nil?
|
246
|
+
generation_timeseries_kwh += Matrix[pv['year_one_power_production_series_kw']]
|
205
247
|
end
|
206
248
|
end
|
207
|
-
|
249
|
+
end
|
208
250
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
251
|
+
unless reopt_output['outputs']['Scenario']['Site']['Storage'].nil?
|
252
|
+
if (reopt_output['outputs']['Scenario']['Site']['Storage']['size_kw'] or 0) > 0
|
253
|
+
if !reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'].nil?
|
254
|
+
generation_timeseries_kwh = generation_timeseries_kwh + Matrix[reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']]
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
216
258
|
|
217
259
|
unless reopt_output['outputs']['Scenario']['Site']['Wind'].nil?
|
218
260
|
if (reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) > 0
|
@@ -231,136 +273,151 @@ module URBANopt # :nodoc:
|
|
231
273
|
end
|
232
274
|
|
233
275
|
$generation_timeseries_kwh = generation_timeseries_kwh.to_a[0]
|
234
|
-
$generation_timeseries_kwh_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Total')
|
276
|
+
$generation_timeseries_kwh_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Total(kw)')
|
235
277
|
if $generation_timeseries_kwh_col.nil?
|
236
278
|
$generation_timeseries_kwh_col = scenario_report.timeseries_csv.column_names.length
|
237
|
-
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Total')
|
279
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Total(kw)')
|
238
280
|
end
|
239
281
|
|
240
|
-
$load = reopt_output['outputs']['Scenario']['Site']['LoadProfile']['year_one_electric_load_series_kw'] || [0] * 8760
|
241
|
-
$load_col = scenario_report.timeseries_csv.column_names.index('Electricity:Load:Total')
|
282
|
+
$load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['LoadProfile']['year_one_electric_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
283
|
+
$load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Load:Total(kw)')
|
242
284
|
if $load_col.nil?
|
243
285
|
$load_col = scenario_report.timeseries_csv.column_names.length
|
244
|
-
scenario_report.timeseries_csv.column_names.push('Electricity:Load:Total')
|
286
|
+
scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Load:Total(kw)')
|
245
287
|
end
|
246
288
|
|
247
|
-
$utility_to_load = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_load_series_kw'] || [0] * 8760
|
248
|
-
$utility_to_load_col = scenario_report.timeseries_csv.column_names.index('Electricity:Grid:ToLoad')
|
289
|
+
$utility_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
290
|
+
$utility_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToLoad(kw)')
|
249
291
|
if $utility_to_load_col.nil?
|
250
292
|
$utility_to_load_col = scenario_report.timeseries_csv.column_names.length
|
251
|
-
scenario_report.timeseries_csv.column_names.push('Electricity:Grid:ToLoad')
|
293
|
+
scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToLoad(kw)')
|
252
294
|
end
|
253
295
|
|
254
|
-
$utility_to_battery = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_battery_series_kw'] || [0] * 8760
|
255
|
-
$utility_to_battery_col = scenario_report.timeseries_csv.column_names.index('Electricity:Grid:ToBattery')
|
296
|
+
$utility_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
297
|
+
$utility_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToBattery(kw)')
|
256
298
|
if $utility_to_battery_col.nil?
|
257
299
|
$utility_to_battery_col = scenario_report.timeseries_csv.column_names.length
|
258
|
-
scenario_report.timeseries_csv.column_names.push('Electricity:Grid:ToBattery')
|
300
|
+
scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToBattery(kw)')
|
259
301
|
end
|
260
302
|
|
261
|
-
$storage_to_load = reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw'] || [0] * 8760
|
262
|
-
$storage_to_load_col = scenario_report.timeseries_csv.column_names.index('Electricity:Storage:ToLoad')
|
303
|
+
$storage_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
304
|
+
$storage_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToLoad(kw)')
|
263
305
|
if $storage_to_load_col.nil?
|
264
306
|
$storage_to_load_col = scenario_report.timeseries_csv.column_names.length
|
265
|
-
scenario_report.timeseries_csv.column_names.push('Electricity:Storage:ToLoad')
|
307
|
+
scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToLoad(kw)')
|
266
308
|
end
|
267
309
|
|
268
|
-
$storage_to_grid = reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'] || [0] * 8760
|
269
|
-
$storage_to_grid_col = scenario_report.timeseries_csv.column_names.index('Electricity:Storage:ToGrid')
|
310
|
+
$storage_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
311
|
+
$storage_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToGrid(kw)')
|
270
312
|
if $storage_to_grid_col.nil?
|
271
313
|
$storage_to_grid_col = scenario_report.timeseries_csv.column_names.length
|
272
|
-
scenario_report.timeseries_csv.column_names.push('Electricity:Storage:ToGrid')
|
314
|
+
scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToGrid(kw)')
|
273
315
|
end
|
274
316
|
|
275
|
-
$storage_soc = reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct'] || [0] * 8760
|
276
|
-
$storage_soc_col = scenario_report.timeseries_csv.column_names.index('Electricity:Storage:StateOfCharge')
|
317
|
+
$storage_soc = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
318
|
+
$storage_soc_col = scenario_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:StateOfCharge(pct)')
|
277
319
|
if $storage_soc_col.nil?
|
278
320
|
$storage_soc_col = scenario_report.timeseries_csv.column_names.length
|
279
|
-
scenario_report.timeseries_csv.column_names.push('Electricity:Storage:StateOfCharge')
|
321
|
+
scenario_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:StateOfCharge(pct)')
|
280
322
|
end
|
281
323
|
|
282
|
-
$generator_total = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'] || [0] * 8760
|
283
|
-
$generator_total_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:Total')
|
324
|
+
$generator_total = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
325
|
+
$generator_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:Total(kw)')
|
284
326
|
if $generator_total_col.nil?
|
285
327
|
$generator_total_col = scenario_report.timeseries_csv.column_names.length
|
286
|
-
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:Total')
|
328
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:Total(kw)')
|
287
329
|
end
|
288
330
|
|
289
|
-
$generator_to_battery = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_battery_series_kw'] || [0] * 8760
|
290
|
-
$generator_to_battery_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:ToBattery')
|
331
|
+
$generator_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
332
|
+
$generator_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToBattery(kw)')
|
291
333
|
if $generator_to_battery_col.nil?
|
292
334
|
$generator_to_battery_col = scenario_report.timeseries_csv.column_names.length
|
293
|
-
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToBattery')
|
335
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToBattery(kw)')
|
294
336
|
end
|
295
337
|
|
296
|
-
$generator_to_load = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw'] || [0] * 8760
|
297
|
-
$generator_to_load_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:ToLoad')
|
338
|
+
$generator_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
339
|
+
$generator_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToLoad(kw)')
|
298
340
|
if $generator_to_load_col.nil?
|
299
341
|
$generator_to_load_col = scenario_report.timeseries_csv.column_names.length
|
300
|
-
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToLoad')
|
342
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToLoad(kw)')
|
301
343
|
end
|
302
344
|
|
303
|
-
$generator_to_grid = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_grid_series_kw'] || [0] * 8760
|
304
|
-
$generator_to_grid_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:ToGrid')
|
345
|
+
$generator_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
346
|
+
$generator_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToGrid(kw)')
|
305
347
|
if $generator_to_grid_col.nil?
|
306
348
|
$generator_to_grid_col = scenario_report.timeseries_csv.column_names.length
|
307
|
-
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToGrid')
|
349
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToGrid(kw)')
|
308
350
|
end
|
309
351
|
|
310
|
-
$
|
311
|
-
$pv_total_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:PV:Total')
|
352
|
+
$pv_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:Total(kw)')
|
312
353
|
if $pv_total_col.nil?
|
313
354
|
$pv_total_col = scenario_report.timeseries_csv.column_names.length
|
314
|
-
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:PV:Total')
|
355
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:Total(kw)')
|
315
356
|
end
|
316
357
|
|
317
|
-
$
|
318
|
-
$pv_to_battery_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToBattery')
|
358
|
+
$pv_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToBattery(kw)')
|
319
359
|
if $pv_to_battery_col.nil?
|
320
360
|
$pv_to_battery_col = scenario_report.timeseries_csv.column_names.length
|
321
|
-
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToBattery')
|
361
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToBattery(kw)')
|
322
362
|
end
|
323
363
|
|
324
|
-
$
|
325
|
-
$pv_to_load_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToLoad')
|
364
|
+
$pv_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToLoad(kw)')
|
326
365
|
if $pv_to_load_col.nil?
|
327
366
|
$pv_to_load_col = scenario_report.timeseries_csv.column_names.length
|
328
|
-
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToLoad')
|
367
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToLoad(kw)')
|
329
368
|
end
|
330
369
|
|
331
|
-
$
|
332
|
-
$pv_to_grid_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToGrid')
|
370
|
+
$pv_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToGrid(kw)')
|
333
371
|
if $pv_to_grid_col.nil?
|
334
372
|
$pv_to_grid_col = scenario_report.timeseries_csv.column_names.length
|
335
|
-
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToGrid')
|
373
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToGrid(kw)')
|
336
374
|
end
|
337
375
|
|
338
|
-
$
|
339
|
-
$
|
376
|
+
$pv_total = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
|
377
|
+
$pv_to_battery = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
|
378
|
+
$pv_to_load = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
|
379
|
+
$pv_to_grid = Matrix[[0] * (8760 * scenario_report.timesteps_per_hour)]
|
380
|
+
|
381
|
+
reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
|
382
|
+
if (pv['size_kw'] || 0) > 0
|
383
|
+
$pv_total += Matrix[scale_timeseries(pv['year_one_power_production_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
|
384
|
+
$pv_to_battery += Matrix[scale_timeseries(pv['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
|
385
|
+
$pv_to_load += Matrix[scale_timeseries(pv['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
|
386
|
+
$pv_to_grid += Matrix[scale_timeseries(pv['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)]
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
$pv_total = $pv_total.to_a[0]
|
391
|
+
$pv_to_battery = $pv_to_battery.to_a[0]
|
392
|
+
$pv_to_load = $pv_to_load.to_a[0]
|
393
|
+
$pv_to_grid = $pv_to_grid.to_a[0]
|
394
|
+
|
395
|
+
$wind_total = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
396
|
+
$wind_total_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:Total(kw)')
|
340
397
|
if $wind_total_col.nil?
|
341
398
|
$wind_total_col = scenario_report.timeseries_csv.column_names.length
|
342
|
-
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:Total')
|
399
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:Total(kw)')
|
343
400
|
end
|
344
401
|
|
345
|
-
$wind_to_battery = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_battery_series_kw'] || [0] * 8760
|
346
|
-
$wind_to_battery_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:ToBattery')
|
402
|
+
$wind_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_battery_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
403
|
+
$wind_to_battery_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToBattery(kw)')
|
347
404
|
if $wind_to_battery_col.nil?
|
348
405
|
$wind_to_battery_col = scenario_report.timeseries_csv.column_names.length
|
349
|
-
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToBattery')
|
406
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToBattery(kw)')
|
350
407
|
end
|
351
408
|
|
352
|
-
$wind_to_load = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_load_series_kw'] || [0] * 8760
|
353
|
-
$wind_to_load_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:ToLoad')
|
409
|
+
$wind_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_load_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
410
|
+
$wind_to_load_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToLoad(kw)')
|
354
411
|
if $wind_to_load_col.nil?
|
355
412
|
$wind_to_load_col = scenario_report.timeseries_csv.column_names.length
|
356
|
-
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToLoad')
|
413
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToLoad(kw)')
|
357
414
|
end
|
358
415
|
|
359
|
-
$wind_to_grid = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_grid_series_kw'] || [0] * 8760
|
360
|
-
$wind_to_grid_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:ToGrid')
|
416
|
+
$wind_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_grid_series_kw']) || [0] * (8760 * scenario_report.timesteps_per_hour)
|
417
|
+
$wind_to_grid_col = scenario_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToGrid(kw)')
|
361
418
|
if $wind_to_grid_col.nil?
|
362
419
|
$wind_to_grid_col = scenario_report.timeseries_csv.column_names.length
|
363
|
-
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToGrid')
|
420
|
+
scenario_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToGrid(kw)')
|
364
421
|
end
|
365
422
|
|
366
423
|
def modrow(x, i) # :nodoc:
|
@@ -387,9 +444,11 @@ module URBANopt # :nodoc:
|
|
387
444
|
end
|
388
445
|
|
389
446
|
old_data = CSV.open(scenario_report.timeseries_csv.path).read
|
447
|
+
start_date = Time.parse(old_data[1][0])
|
448
|
+
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) / (( 60 / scenario_report.timesteps_per_hour ) * 60)).to_int
|
390
449
|
mod_data = old_data.map.with_index do |x, i|
|
391
450
|
if i > 0
|
392
|
-
modrow(x, i)
|
451
|
+
modrow(x, start_ts + i -2)
|
393
452
|
else
|
394
453
|
x
|
395
454
|
end
|
data/urbanopt-reopt.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: urbanopt-reopt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ''
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -94,20 +94,6 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: urbanopt-scenario
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - '='
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: 0.1.1
|
104
|
-
type: :runtime
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - '='
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: 0.1.1
|
111
97
|
description: Classes and measures for utilizing the REopt Lite API within OpenStudio
|
112
98
|
workflows.
|
113
99
|
email:
|
@@ -116,6 +102,9 @@ executables: []
|
|
116
102
|
extensions: []
|
117
103
|
extra_rdoc_files: []
|
118
104
|
files:
|
105
|
+
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
106
|
+
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
107
|
+
- ".github/pull_request_template.md"
|
119
108
|
- ".gitignore"
|
120
109
|
- ".rakeTasks"
|
121
110
|
- ".rdoc_options"
|
@@ -123,6 +112,7 @@ files:
|
|
123
112
|
- ".rubocop.yml"
|
124
113
|
- ".travis.yml"
|
125
114
|
- CHANGELOG.md
|
115
|
+
- CONTRIBUTING.md
|
126
116
|
- Gemfile
|
127
117
|
- Jenkinsfile
|
128
118
|
- LICENSE.md
|