urbanopt-reopt 0.1.0 → 0.4.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/Rakefile CHANGED
@@ -1,3 +1,33 @@
1
+ # *********************************************************************************
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
+ # contributors. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without modification,
6
+ # are permitted provided that the following conditions are met:
7
+ #
8
+ # Redistributions of source code must retain the above copyright notice, this list
9
+ # of conditions and the following disclaimer.
10
+ #
11
+ # Redistributions in binary form must reproduce the above copyright notice, this
12
+ # list of conditions and the following disclaimer in the documentation and/or other
13
+ # materials provided with the distribution.
14
+ #
15
+ # Neither the name of the copyright holder nor the names of its contributors may be
16
+ # used to endorse or promote products derived from this software without specific
17
+ # prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
+ # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24
+ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
+ # OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ # *********************************************************************************
30
+
1
31
  require 'bundler/gem_tasks'
2
32
  require 'rspec/core/rake_task'
3
33
 
@@ -10,7 +40,7 @@ RuboCop::RakeTask.new
10
40
  require 'openstudio/extension/rake_task'
11
41
  require 'urbanopt/reopt/extension'
12
42
  os_extension = OpenStudio::Extension::RakeTask.new
13
- os_extension.set_extension_class(URBANopt::REopt::Extension)
43
+ os_extension.set_extension_class(URBANopt::REopt::Extension, 'urbanopt/urbanopt-reopt-gem')
14
44
 
15
45
  desc 'CLI OpenSSL test'
16
46
  task :cli_openssl_test do
data/a.txt ADDED
@@ -0,0 +1 @@
1
+ 123
@@ -1,4 +1,4 @@
1
- URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
1
+ URBANopt™, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
2
  contributors. All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without modification,
@@ -1,6 +1,6 @@
1
1
  <%
2
2
  # *********************************************************************************
3
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
+ # URBANopt™, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
4
4
  # contributors. All rights reserved.
5
5
  #
6
6
  # Redistribution and use in source and binary forms, with or without modification,
@@ -1,4 +1,4 @@
1
1
  /* @preserve
2
- * URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
2
+ * URBANopt™, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
3
3
  * Use of this source code is governed by the BSD 3-Clause license.
4
4
  */
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2020, 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,
@@ -2,8 +2,8 @@
2
2
 
3
3
  ### <StaticLink target="\_blank" href="rdoc/">Rdocs</StaticLink>
4
4
 
5
- The **URBANopt REopt Gem** extends a **URBANopt::Scenario::DefaultReports::ScenarioReport** and **URBANopt::Scenario::DefaultReports::FeatureReport** with the ability to derive cost-optimal distributed energy resource (DER) technology sizes and annual dispatch strageties via the <StaticLink target="\_blank" href="https://reopt.nrel.gov/tool">REopt Lite</StaticLink> decision support platform.
6
- 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 <StaticLink target="\_blank" href="https://developer.nrel.gov/docs/energy-optimization/reopt-v1/">https://developer.nrel.gov/docs/energy-optimization/reopt-v1/</StaticLink> for more detailed information on input parameters and default assumptions.
5
+ The **URBANopt<sup>&trade;</sup> REopt Gem** extends a **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 <StaticLink target="\_blank" href="https://reopt.nrel.gov/tool">REopt Lite</StaticLink> decision support platform.
6
+ 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 <StaticLink target="\_blank" href="https://developer.nrel.gov/docs/energy-optimization/reopt-v1/">https://developer.nrel.gov/docs/energy-optimization/reopt-v1/</StaticLink> for more detailed information on input parameters and default assumptions.
7
7
 
8
8
  The REopt Gem accomplishes three basic functions (described more below in the _Functionality_ section):
9
9
 
@@ -13,8 +13,8 @@ The REopt Gem accomplishes three basic functions (described more below in the _F
13
13
 
14
14
  Moreover, the REopt Gem can be run in several modes, either on:
15
15
 
16
- * A Feature Report,
17
- * A collection of Feature Reports
16
+ * A Feature Report,
17
+ * A collection of Feature Reports
18
18
  * All the features in a Scenario Report before aggregating results at the scenario level
19
19
  * The collection of features in aggregate as summarized in a Scenario Report
20
20
 
@@ -27,7 +27,7 @@ See the <StaticLink target="\_blank" href="https://github.com/urbanopt/urbanopt-
27
27
 
28
28
  ## Installation
29
29
 
30
- See [https://docs.urbanopt.net/installation/installation.html](https://docs.urbanopt.net/installation/installation.html) for instructions on prerequiste software, including:
30
+ See [https://docs.urbanopt.net/installation/installation.html](https://docs.urbanopt.net/installation/installation.html) for instructions on prerequiste software, including:
31
31
  - Ruby 2.2.6
32
32
  - Bundler 1.17.0
33
33
  - OpenStudio 2.8.1
@@ -49,7 +49,7 @@ Or install it yourself as:
49
49
 
50
50
  ## Functionality
51
51
 
52
- This gem is used to call the REopt Lite API on a Scenario Report or Feature Report to update the object's Distributed Generation attributes (including system financial and sizing metrics) as shown in an example below:
52
+ This gem is used to call the REopt Lite API on a Scenario Report or Feature Report to update the object's Distributed Generation attributes (including system financial and sizing metrics) as shown in an example below:
53
53
  ```
54
54
  "distributed_generation": {
55
55
  "lcc_us_dollars": 100000000.0,
@@ -97,9 +97,9 @@ Moreover, the following optimal dispatch fields are added to its timeseries CSV.
97
97
  | ElectricityProduced:Wind:ToBattery | kWh |
98
98
  | ElectricityProduced:Wind:ToLoad | kWh |
99
99
  | ElectricityProduced:Wind:ToGrid | kWh |
100
-
101
100
 
102
- The REopt Lite has default values for all non-required input parameters that are used unless the user specifies custom assumptions. See <StaticLink target="\_blank" href="https://developer.nrel.gov/docs/energy-optimization/reopt-v1/">https://developer.nrel.gov/docs/energy-optimization/reopt-v1/</StaticLink> for more detailed information on input parameters and default assumptions.
101
+
102
+ The REopt Lite has default values for all non-required input parameters that are used unless the user specifies custom assumptions. See <StaticLink target="\_blank" href="https://developer.nrel.gov/docs/energy-optimization/reopt-v1/">https://developer.nrel.gov/docs/energy-optimization/reopt-v1/</StaticLink> for more detailed information on input parameters and default assumptions.
103
103
 
104
104
  <b>Note:</b> Required attributes for a REopt run include latitude and longitude, parsed from the Feature or Scenario Report attributes. If no utility rate is specified in your assumptions, then a constant 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).
105
105
 
@@ -118,7 +118,7 @@ DEVELOPER_NREL_KEY = "" # <insert a valid API key from https://developer.nrel.go
118
118
  feature_reports_hash = {} # <insert a valid Feature Report hash here with latitude and longitude filled in>
119
119
 
120
120
  #Create a Feature Report
121
- feature_report = URBANopt::Scenario::DefaultReports::FeatureReport.new(feature_reports_hash)
121
+ feature_report = URBANopt::Reporting::DefaultReports::FeatureReport.new(feature_reports_hash)
122
122
 
123
123
  #Specify a file name where REopt Lite results will be written in JSON format
124
124
  reopt_output_file = File.join(feature_report.directory_name, 'feature_report_reopt_run.json')
@@ -134,7 +134,7 @@ reopt_post_processor = URBANopt::REopt::REoptPostProcessor.new(nil, nil, nil, DE
134
134
 
135
135
  #Call REopt Lite with the post processor to update the feature's distributed generation attributes and timeseries CSV.
136
136
  updated_feature_report = reopt_post_processor.run_feature_report(feature_report,reopt_assumptions_file,reopt_output_file,timeseries_output_file)
137
-
137
+
138
138
  ```
139
139
 
140
140
  More commonly, this gem can be used to run REopt a collection of features stored in a Scenario Report as show here:
@@ -143,9 +143,9 @@ require 'urbanopt/reopt'
143
143
  DEVELOPER_NREL_KEY = "" # <insert a valid API key from https://developer.nrel.gov/signup >
144
144
 
145
145
  #Create a Scenario Report
146
- scenario_report = URBANopt::Scenario::DefaultReports::ScenarioReport.new({:directory_name => File.join(File.dirname(__FILE__), 'run/example_scenario'), :timeseries_csv => {:path => File.join(File.dirname(__FILE__), 'run/example_scenario/timeseries.csv') }})
146
+ scenario_report = URBANopt::Reporting::DefaultReports::ScenarioReport.new({:directory_name => File.join(File.dirname(__FILE__), 'run/example_scenario'), :timeseries_csv => {:path => File.join(File.dirname(__FILE__), 'run/example_scenario/timeseries.csv') }})
147
147
 
148
- #Load Feature Reports into the Scenario Report
148
+ #Load Feature Reports into the Scenario Report
149
149
  (1..2).each do |i|
150
150
  feature_reports_path = File.join(File.dirname(__FILE__), "run/example_scenario/#{i}/010_default_feature_reports/default_feature_reports.json")
151
151
 
@@ -154,8 +154,8 @@ scenario_report = URBANopt::Scenario::DefaultReports::ScenarioReport.new({:direc
154
154
  feature_reports_hash = JSON.parse(file.read, symbolize_names: true)
155
155
  end
156
156
 
157
- feature_report = URBANopt::Scenario::DefaultReports::FeatureReport.new(feature_reports_hash)
158
-
157
+ feature_report = URBANopt::Reporting::DefaultReports::FeatureReport.new(feature_reports_hash)
158
+
159
159
  feature_report_dir = File.join(File.dirname(__FILE__), "run/example_scenario/#{i}")
160
160
  feature_report.directory_name = feature_report_dir
161
161
 
@@ -170,7 +170,7 @@ reopt_post_processor = URBANopt::REopt::REoptPostProcessor.new(scenario_report,
170
170
 
171
171
  #Call REopt Lite with the post processor once on the sceanrio's aggregated load to update the scenario's distributed generation attributes and timeseries CSV.
172
172
  updated_scenario_report = reopt_post_processor.run_scenario_report(scenario_report)
173
-
173
+
174
174
  ```
175
175
 
176
176
  ## Testing
@@ -184,7 +184,7 @@ Next, obtain a developer.nrel.gov API key from the [NREL Developer Network](http
184
184
  Finally, execute:
185
185
 
186
186
  $ bundle install
187
- $ bundle update
187
+ $ bundle update
188
188
  $ bundle exec rake
189
189
 
190
190
 
data/index.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # **URBANopt REopt Gem**
2
2
 
3
- The **URBANopt REopt Gem** extends **URBANopt::Scenario::DefaultReports::ScenarioReport** and **URBANopt::Scenario::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.
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.
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
 
@@ -9,7 +9,7 @@ See the [example project](https://github.com/urbanopt/urbanopt-example-reopt-pro
9
9
 
10
10
  ## Installation
11
11
 
12
- See [https://docs.urbanopt.net/installation/installation.html](https://docs.urbanopt.net/installation/installation.html) for instructions on prerequiste software, including:
12
+ See [https://docs.urbanopt.net/installation/installation.html](https://docs.urbanopt.net/installation/installation.html) for instructions on prerequiste software, including:
13
13
  - Ruby 2.2.6
14
14
  - Bundler 1.17.0
15
15
  - OpenStudio 2.8.1
@@ -31,7 +31,7 @@ Or install it yourself as:
31
31
 
32
32
  ## Functionality
33
33
 
34
- This gem is used to call the REopt Lite API on a Scenario Report or Feature Report to update the object's Distributed Generation attributes (including system financial and sizing metrics) as shown in an example below:
34
+ This gem is used to call the REopt Lite API on a Scenario Report or Feature Report to update the object's Distributed Generation attributes (including system financial and sizing metrics) as shown in an example below:
35
35
 
36
36
  ```
37
37
  "distributed_generation": {
@@ -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-v1/](https://developer.nrel.gov/docs/energy-optimization/reopt-v1/) 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
 
@@ -99,7 +99,7 @@ require 'urbanopt/reopt'
99
99
  feature_reports_hash = {} # <insert a Feature Report hash here>
100
100
 
101
101
  #Create a Feature Report
102
- feature_report = URBANopt::Scenario::DefaultReports::FeatureReport.new(feature_reports_hash)
102
+ feature_report = URBANopt::Reporting::DefaultReports::FeatureReport.new(feature_reports_hash)
103
103
 
104
104
  #Specify a file name where REopt Lite results will be written in JSON format
105
105
  reopt_output_file = File.join(feature_report.directory_name, 'feature_report_reopt_run1.json')
@@ -115,7 +115,7 @@ reopt_post_processor = URBANopt::REopt::REoptPostProcessor.new(nil, nil, nil, DE
115
115
 
116
116
  #Call REopt Lite with the post processor to update the feature's distributed generation attributes and timeseries CSV.
117
117
  updated_feature_report = reopt_post_processor.run_feature_report(feature_report,reopt_assumptions_file,reopt_output_file,timeseries_output_file)
118
-
118
+
119
119
  ```
120
120
 
121
121
  More commonly, this gem can be used to run REopt a collection of features stored in a Scenario Report as show here:
@@ -123,9 +123,9 @@ More commonly, this gem can be used to run REopt a collection of features stored
123
123
  ```ruby
124
124
  require 'urbanopt/reopt'
125
125
  #Create a Scenario Report
126
- scenario_report = URBANopt::Scenario::DefaultReports::ScenarioReport.new({:directory_name => File.join(File.dirname(__FILE__), '../run/example_scenario'), :timeseries_csv => {:path => File.join(File.dirname(__FILE__), '../run/example_scenario/timeseries.csv') }})
126
+ scenario_report = URBANopt::Reporting::DefaultReports::ScenarioReport.new({:directory_name => File.join(File.dirname(__FILE__), '../run/example_scenario'), :timeseries_csv => {:path => File.join(File.dirname(__FILE__), '../run/example_scenario/timeseries.csv') }})
127
127
 
128
- #Load Feature Reports into the Scenario Report
128
+ #Load Feature Reports into the Scenario Report
129
129
  (1..2).each do |i|
130
130
  feature_reports_path = File.join(File.dirname(__FILE__), "../run/example_scenario/#{i}/010_default_feature_reports/default_feature_reports.json")
131
131
 
@@ -134,8 +134,8 @@ scenario_report = URBANopt::Scenario::DefaultReports::ScenarioReport.new({:direc
134
134
  feature_reports_hash = JSON.parse(file.read, symbolize_names: true)
135
135
  end
136
136
 
137
- feature_report = URBANopt::Scenario::DefaultReports::FeatureReport.new(feature_reports_hash)
138
-
137
+ feature_report = URBANopt::Reporting::DefaultReports::FeatureReport.new(feature_reports_hash)
138
+
139
139
  feature_report_dir = File.join(File.dirname(__FILE__), "../run/example_scenario/#{i}")
140
140
  feature_report.directory_name = feature_report_dir
141
141
 
@@ -150,7 +150,7 @@ reopt_post_processor = URBANopt::REopt::REoptPostProcessor.new(scenario_report,
150
150
 
151
151
  #Call REopt Lite with the post processor once on the sceanrio's aggregated load to update the scenario's distributed generation attributes and timeseries CSV.
152
152
  updated_scenario_report = reopt_post_processor.run_scenario_report(scenario_report)
153
-
153
+
154
154
  ```
155
155
 
156
156
  ## Testing
@@ -164,7 +164,7 @@ Next, obtain a developer.nrel.gov API key from the [NREL Developer Network](http
164
164
  Finally, execute:
165
165
 
166
166
  $ bundle install
167
- $ bundle update
167
+ $ bundle update
168
168
  $ bundle exec rake
169
169
 
170
170
 
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, 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,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, 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,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, 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,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, 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,
@@ -28,16 +28,17 @@
28
28
  # OF THE POSSIBILITY OF SUCH DAMAGE.
29
29
  # *********************************************************************************
30
30
 
31
- require 'urbanopt/scenario/default_reports'
31
+ require 'urbanopt/reporting/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:
38
39
  class FeatureReportAdapter
39
40
  ##
40
- # FeatureReportAdapter can convert a URBANopt::Scenario::DefaultReports::FeatureReport into a \REopt Lite posts or update a URBANopt::Scenario::DefaultReports::FeatureReport from a \REopt Lite response.
41
+ # FeatureReportAdapter can convert a URBANopt::Reporting::DefaultReports::FeatureReport into a \REopt Lite posts or update a URBANopt::Reporting::DefaultReports::FeatureReport from a \REopt Lite response.
41
42
  ##
42
43
  # [*parameters:*]
43
44
  ##
@@ -51,7 +52,7 @@ module URBANopt # :nodoc:
51
52
  #
52
53
  # [*parameters:*]
53
54
  #
54
- # * +feature_report+ - _URBANopt::Scenario::DefaultReports::FeatureReport_ - FeatureReport to use in converting the optional +reopt_assumptions_hash+ to a \REopt Lite post. If a +reopt_assumptions_hash+ is not provided, a default post will be updated from this FeatureReport and submitted to the \REopt Lite API.
55
+ # * +feature_report+ - _URBANopt::Reporting::DefaultReports::FeatureReport_ - FeatureReport to use in converting the optional +reopt_assumptions_hash+ to a \REopt Lite post. If a +reopt_assumptions_hash+ is not provided, a default post will be updated from this FeatureReport and submitted to the \REopt Lite API.
55
56
  # * +reopt_assumptions_hash+ - _Hash_ - Optional. A hash formatted for submittal to the \REopt Lite API containing default values. Values will be overwritten from the FeatureReport where available (i.e. latitude, roof_squarefeet). Missing optional parameters will be filled in with default values by the API.
56
57
  #
57
58
  # [*return:*] _Hash_ - Returns hash formatted for submittal to the \REopt Lite API
@@ -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
- p 'a' # @@logger.error("Missing value for #{n} - this is a required input")
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) * 0.293071) } # convert kBTU to KWH
103
- if (feature_report.timesteps_per_hour || 1) > 1
104
- energy_timeseries_kwh = energy_timeseries_kwh.each_slice(feature_report.timesteps_per_hour).to_a.map { |x| x.inject(0, :+) / x.length.to_f }
105
- end
106
-
107
- if energy_timeseries_kwh.length < feature_report.timesteps_per_hour * 8760
108
- energy_timeseries_kwh += [0] * ((feature_report.timesteps_per_hour * 8760) - energy_timeseries_kwh.length)
109
- @@logger.info("Assuming load profile for Feature Report #{feature_report.name} #{feature_report.id} starts January 1 - filling in rest with zeros")
107
+ energy_timeseries_kw = t.by_col[col_num].map { |e| ((e * feature_report.timesteps_per_hour || 0) ) }
108
+ if energy_timeseries_kw.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_kw = [0.0]*(start_ts-1) + energy_timeseries_kw + [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_kw.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}"
@@ -121,19 +127,39 @@ module URBANopt # :nodoc:
121
127
  #
122
128
  # [*parameters:*]
123
129
  #
124
- # * +feature_report+ - _URBANopt::Scenario::DefaultReports::FeatureReport_ - FeatureReport to update from a \REopt Lite reponse hash.
130
+ # * +feature_report+ - _URBANopt::Reporting::DefaultReports::FeatureReport_ - FeatureReport to update from a \REopt Lite reponse hash.
125
131
  # * +reopt_output+ - _Hash_ - A reponse hash from the \REopt Lite API to use in overwriting FeatureReport technology sizes, costs and dispatch strategies.
126
132
  # * +timeseries_csv_path+ - _String_ - Optional. The path to a file at which a new timeseries CSV will be written. If not provided a file is created based on the run_uuid of the \REopt Lite optimization task.
127
133
  #
128
- # [*return:*] _URBANopt::Scenario::DefaultReports::FeatureReport_ - Returns an updated FeatureReport.
134
+ # [*return:*] _URBANopt::Reporting::DefaultReports::FeatureReport_ - Returns an updated FeatureReport.
129
135
  ##
130
- def update_feature_report(feature_report, reopt_output, timeseries_csv_path = nil)
136
+ def update_feature_report(feature_report, reopt_output, timeseries_csv_path=nil, resilience_stats=nil)
131
137
  # Check if the \REopt Lite response is valid
132
138
  if reopt_output['outputs']['Scenario']['status'] != 'optimal'
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
136
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
162
+
137
163
  # Update location
138
164
  feature_report.location.latitude = reopt_output['inputs']['Scenario']['Site']['latitude']
139
165
  feature_report.location.longitude = reopt_output['inputs']['Scenario']['Site']['longitude']
@@ -142,36 +168,71 @@ 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
- (feature_report.distributed_generation.lcc_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['lcc_us_dollars']) || 0
146
- (feature_report.distributed_generation.npv_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['npv_us_dollars']) || 0
147
- (feature_report.distributed_generation.year_one_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_energy_cost_us_dollars']) || 0
148
- (feature_report.distributed_generation.year_one_demand_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_demand_cost_us_dollars']) || 0
149
- (feature_report.distributed_generation.year_one_bill_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_bill_us_dollars']) || 0
150
- (feature_report.distributed_generation.total_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['total_energy_cost_us_dollars']) || 0
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
+ feature_report.distributed_generation.total_demand_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['total_demand_cost_us_dollars'] || 0
178
+ feature_report.distributed_generation.year_one_energy_cost_bau_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_energy_cost_bau_us_dollars'] || 0
179
+ feature_report.distributed_generation.year_one_demand_cost_bau_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_demand_cost_bau_us_dollars'] || 0
180
+ feature_report.distributed_generation.year_one_bill_bau_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_bill_bau_us_dollars'] || 0
181
+ feature_report.distributed_generation.total_demand_cost_bau_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['total_demand_cost_bau_us_dollars'] || 0
182
+ feature_report.distributed_generation.total_energy_cost_bau_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['total_energy_cost_bau_us_dollars'] || 0
183
+ if !resilience_stats.nil?
184
+ feature_report.distributed_generation.resilience_hours_min = resilience_stats['resilience_hours_min']
185
+ feature_report.distributed_generation.resilience_hours_max = resilience_stats['resilience_hours_max']
186
+ feature_report.distributed_generation.resilience_hours_avg = resilience_stats['resilience_hours_avg']
187
+ feature_report.distributed_generation.probs_of_surviving = resilience_stats['probs_of_surviving']
188
+ feature_report.distributed_generation.probs_of_surviving_by_month = resilience_stats['probs_of_surviving_by_month']
189
+ feature_report.distributed_generation.probs_of_surviving_by_hour_of_the_day = resilience_stats['probs_of_surviving_by_hour_of_the_day']
190
+ end
191
+
192
+ if reopt_output['outputs']['Scenario']['Site']['PV'].class == Hash
193
+ reopt_output['outputs']['Scenario']['Site']['PV'] = [reopt_output['outputs']['Scenario']['Site']['PV']]
194
+ elsif reopt_output['outputs']['Scenario']['Site']['PV'].nil?
195
+ reopt_output['outputs']['Scenario']['Site']['PV'] = []
196
+ end
197
+
198
+ reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
199
+ feature_report.distributed_generation.add_tech 'solar_pv', URBANopt::Reporting::DefaultReports::SolarPV.new( {size_kw: (pv['size_kw'] || 0), id: i })
200
+ end
151
201
 
152
- (feature_report.distributed_generation.solar_pv.size_kw = reopt_output['outputs']['Scenario']['Site']['PV']['size_kw']) || 0
153
- (feature_report.distributed_generation.wind.size_kw = reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw']) || 0
154
- (feature_report.distributed_generation.generator.size_kw = reopt_output['outputs']['Scenario']['Site']['Generator']['size_kw']) || 0
155
- (feature_report.distributed_generation.storage.size_kw = reopt_output['outputs']['Scenario']['Site']['Storage']['size_kw']) || 0
156
- (feature_report.distributed_generation.storage.size_kwh = reopt_output['outputs']['Scenario']['Site']['Storage']['size_kwh']) || 0
202
+ wind = reopt_output['outputs']['Scenario']['Site']['Wind']
203
+ if !wind['size_kw'].nil? and wind['size_kw'] != 0
204
+ feature_report.distributed_generation.add_tech 'wind', URBANopt::Reporting::DefaultReports::Wind.new( {size_kw: (wind['size_kw'] || 0) })
205
+ end
206
+
207
+ generator = reopt_output['outputs']['Scenario']['Site']['Generator']
208
+ if !generator['size_kw'].nil? and generator['size_kw'] != 0
209
+ feature_report.distributed_generation.add_tech 'generator', URBANopt::Reporting::DefaultReports::Generator.new( {size_kw: (generator['size_kw'] || 0) })
210
+ end
211
+
212
+ storage = reopt_output['outputs']['Scenario']['Site']['Storage']
213
+ if !storage['size_kw'].nil? and storage['size_kw'] != 0
214
+ feature_report.distributed_generation.add_tech 'storage', URBANopt::Reporting::DefaultReports::Storage.new( {size_kwh: (storage['size_kwh'] || 0), size_kw: (storage['size_kw'] || 0) })
215
+ end
157
216
 
158
- generation_timeseries_kwh = Matrix[[0] * 8760]
217
+ generation_timeseries_kwh = Matrix[[0] * (8760 * feature_report.timesteps_per_hour)]
159
218
 
160
219
  unless reopt_output['outputs']['Scenario']['Site']['PV'].nil?
161
- if (reopt_output['outputs']['Scenario']['Site']['PV']['size_kw'] || 0) > 0
162
- if !reopt_output['outputs']['Scenario']['Site']['PV']['year_one_power_production_series_kw'].nil?
163
- generation_timeseries_kwh += Matrix[reopt_output['outputs']['Scenario']['Site']['PV']['year_one_power_production_series_kw']]
220
+ reopt_output['outputs']['Scenario']['Site']['PV'].each do |pv|
221
+ if (pv['size_kw'] || 0) > 0
222
+ if !pv['year_one_power_production_series_kw'].nil?
223
+ generation_timeseries_kwh += Matrix[pv['year_one_power_production_series_kw']]
224
+ end
164
225
  end
165
- end
226
+ end
166
227
  end
167
228
 
168
- # unless reopt_output['outputs']['Scenario']['Site']['Storage'].nil?
169
- # if (reopt_output['outputs']['Scenario']['Site']['Storage']['size_kw'] or 0) > 0
170
- # if !reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'].nil?
171
- # generation_timeseries_kwh = generation_timeseries_kwh + Matrix[reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']]
172
- # end
173
- # end
174
- # end
229
+ unless reopt_output['outputs']['Scenario']['Site']['Storage'].nil?
230
+ if (reopt_output['outputs']['Scenario']['Site']['Storage']['size_kw'] or 0) > 0
231
+ if !reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'].nil?
232
+ generation_timeseries_kwh = generation_timeseries_kwh + Matrix[reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']]
233
+ end
234
+ end
235
+ end
175
236
 
176
237
  unless reopt_output['outputs']['Scenario']['Site']['Wind'].nil?
177
238
  if (reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) > 0
@@ -189,137 +250,153 @@ module URBANopt # :nodoc:
189
250
  end
190
251
  end
191
252
 
192
- $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')
253
+ $generation_timeseries_kwh = generation_timeseries_kwh.to_a[0] || [0] * (8760 * feature_report.timesteps_per_hour)
254
+ $generation_timeseries_kwh_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Total(kw)')
194
255
  if $generation_timeseries_kwh_col.nil?
195
256
  $generation_timeseries_kwh_col = feature_report.timeseries_csv.column_names.length
196
- feature_report.timeseries_csv.column_names.push('ElectricityProduced:Total')
257
+ feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Total(kw)')
197
258
  end
198
259
 
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')
260
+ $load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['LoadProfile']['year_one_electric_load_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
261
+ $load_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Load:Total(kw)')
201
262
  if $load_col.nil?
202
263
  $load_col = feature_report.timeseries_csv.column_names.length
203
- feature_report.timeseries_csv.column_names.push('Electricity:Load:Total')
264
+ feature_report.timeseries_csv.column_names.push('REopt:Electricity:Load:Total(kw)')
204
265
  end
205
266
 
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')
267
+ $utility_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_load_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
268
+ $utility_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToLoad(kw)')
208
269
  if $utility_to_load_col.nil?
209
270
  $utility_to_load_col = feature_report.timeseries_csv.column_names.length
210
- feature_report.timeseries_csv.column_names.push('Electricity:Grid:ToLoad')
271
+ feature_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToLoad(kw)')
211
272
  end
212
273
 
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')
274
+ $utility_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_battery_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
275
+ $utility_to_battery_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Grid:ToBattery(kw)')
215
276
  if $utility_to_battery_col.nil?
216
277
  $utility_to_battery_col = feature_report.timeseries_csv.column_names.length
217
- feature_report.timeseries_csv.column_names.push('Electricity:Grid:ToBattery')
278
+ feature_report.timeseries_csv.column_names.push('REopt:Electricity:Grid:ToBattery(kw)')
218
279
  end
219
280
 
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')
281
+ $storage_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
282
+ $storage_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToLoad(kw)')
222
283
  if $storage_to_load_col.nil?
223
284
  $storage_to_load_col = feature_report.timeseries_csv.column_names.length
224
- feature_report.timeseries_csv.column_names.push('Electricity:Storage:ToLoad')
285
+ feature_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToLoad(kw)')
225
286
  end
226
287
 
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')
288
+ $storage_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
289
+ $storage_to_grid_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:ToGrid(kw)')
229
290
  if $storage_to_grid_col.nil?
230
291
  $storage_to_grid_col = feature_report.timeseries_csv.column_names.length
231
- feature_report.timeseries_csv.column_names.push('Electricity:Storage:ToGrid')
292
+ feature_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:ToGrid(kw)')
232
293
  end
233
294
 
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')
295
+ $storage_soc = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct']) || [0] * (8760 * feature_report.timesteps_per_hour)
296
+ $storage_soc_col = feature_report.timeseries_csv.column_names.index('REopt:Electricity:Storage:StateOfCharge(pct)')
236
297
  if $storage_soc_col.nil?
237
298
  $storage_soc_col = feature_report.timeseries_csv.column_names.length
238
- feature_report.timeseries_csv.column_names.push('Electricity:Storage:StateOfCharge')
299
+ feature_report.timeseries_csv.column_names.push('REopt:Electricity:Storage:StateOfCharge(pct)')
239
300
  end
240
301
 
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')
302
+ $generator_total = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
303
+ $generator_total_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:Total(kw)')
243
304
  if $generator_total_col.nil?
244
305
  $generator_total_col = feature_report.timeseries_csv.column_names.length
245
- feature_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:Total')
306
+ feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:Total(kw)')
246
307
  end
247
308
 
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')
309
+ $generator_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_battery_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
310
+ $generator_to_battery_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToBattery(kw)')
250
311
  if $generator_to_battery_col.nil?
251
312
  $generator_to_battery_col = feature_report.timeseries_csv.column_names.length
252
- feature_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToBattery')
313
+ feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToBattery(kw)')
253
314
  end
254
315
 
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')
316
+ $generator_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
317
+ $generator_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToLoad(kw)')
257
318
  if $generator_to_load_col.nil?
258
319
  $generator_to_load_col = feature_report.timeseries_csv.column_names.length
259
- feature_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToLoad')
320
+ feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToLoad(kw)')
260
321
  end
261
322
 
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')
323
+ $generator_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_grid_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
324
+ $generator_to_grid_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Generator:ToGrid(kw)')
264
325
  if $generator_to_grid_col.nil?
265
326
  $generator_to_grid_col = feature_report.timeseries_csv.column_names.length
266
- feature_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToGrid')
327
+ feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Generator:ToGrid(kw)')
267
328
  end
268
329
 
269
- $pv_total = reopt_output['outputs']['Scenario']['Site']['PV']['year_one_power_production_series_kw'] || [0] * 8760
270
- $pv_total_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:PV:Total')
330
+ $pv_total_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:Total(kw)')
271
331
  if $pv_total_col.nil?
272
332
  $pv_total_col = feature_report.timeseries_csv.column_names.length
273
- feature_report.timeseries_csv.column_names.push('ElectricityProduced:PV:Total')
333
+ feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:Total(kw)')
274
334
  end
275
335
 
276
- $pv_to_battery = reopt_output['outputs']['Scenario']['Site']['PV']['year_one_to_battery_series_kw'] || [0] * 8760
277
- $pv_to_battery_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToBattery')
336
+ $pv_to_battery_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToBattery(kw)')
278
337
  if $pv_to_battery_col.nil?
279
338
  $pv_to_battery_col = feature_report.timeseries_csv.column_names.length
280
- feature_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToBattery')
339
+ feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToBattery(kw)')
281
340
  end
282
341
 
283
- $pv_to_load = reopt_output['outputs']['Scenario']['Site']['PV']['year_one_to_load_series_kw'] || [0] * 8760
284
- $pv_to_load_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToLoad')
342
+ $pv_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToLoad(kw)')
285
343
  if $pv_to_load_col.nil?
286
344
  $pv_to_load_col = feature_report.timeseries_csv.column_names.length
287
- feature_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToLoad')
345
+ feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToLoad(kw)')
288
346
  end
289
347
 
290
- $pv_to_grid = reopt_output['outputs']['Scenario']['Site']['PV']['year_one_to_grid_series_kw'] || [0] * 8760
291
- $pv_to_grid_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToGrid')
348
+
349
+ $pv_to_grid_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:PV:ToGrid(kw)')
292
350
  if $pv_to_grid_col.nil?
293
351
  $pv_to_grid_col = feature_report.timeseries_csv.column_names.length
294
- feature_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToGrid')
352
+ feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:PV:ToGrid(kw)')
295
353
  end
296
354
 
297
- $wind_total = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'] || [0] * 8760
298
- $wind_total_col = feature_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:Total')
355
+ $pv_total = Matrix[[0] * (8760 * feature_report.timesteps_per_hour)]
356
+ $pv_to_battery = Matrix[[0] * (8760 * feature_report.timesteps_per_hour)]
357
+ $pv_to_load = Matrix[[0] * (8760 * feature_report.timesteps_per_hour)]
358
+ $pv_to_grid = Matrix[[0] * (8760 * feature_report.timesteps_per_hour)]
359
+
360
+ reopt_output['outputs']['Scenario']['Site']['PV'].each_with_index do |pv, i|
361
+ if (pv['size_kw'] || 0) > 0
362
+ $pv_total += Matrix[scale_timeseries(pv['year_one_power_production_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)]
363
+ $pv_to_battery += Matrix[scale_timeseries(pv['year_one_to_battery_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)]
364
+ $pv_to_load += Matrix[scale_timeseries(pv['year_one_to_load_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)]
365
+ $pv_to_grid += Matrix[scale_timeseries(pv['year_one_to_grid_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)]
366
+ end
367
+ end
368
+
369
+ $pv_total = $pv_total.to_a[0]
370
+ $pv_to_battery = $pv_to_battery.to_a[0]
371
+ $pv_to_load = $pv_to_load.to_a[0]
372
+ $pv_to_grid = $pv_to_grid.to_a[0]
373
+
374
+ $wind_total = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
375
+ $wind_total_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:Total(kw)')
299
376
  if $wind_total_col.nil?
300
377
  $wind_total_col = feature_report.timeseries_csv.column_names.length
301
- feature_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:Total')
378
+ feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:Total(kw)')
302
379
  end
303
380
 
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')
381
+ $wind_to_battery = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_battery_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
382
+ $wind_to_battery_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToBattery(kw)')
306
383
  if $wind_to_battery_col.nil?
307
384
  $wind_to_battery_col = feature_report.timeseries_csv.column_names.length
308
- feature_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToBattery')
385
+ feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToBattery(kw)')
309
386
  end
310
387
 
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')
388
+ $wind_to_load = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_load_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
389
+ $wind_to_load_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToLoad(kw)')
313
390
  if $wind_to_load_col.nil?
314
391
  $wind_to_load_col = feature_report.timeseries_csv.column_names.length
315
- feature_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToLoad')
392
+ feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToLoad(kw)')
316
393
  end
317
394
 
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')
395
+ $wind_to_grid = scale_timeseries(reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_grid_series_kw']) || [0] * (8760 * feature_report.timesteps_per_hour)
396
+ $wind_to_grid_col = feature_report.timeseries_csv.column_names.index('REopt:ElectricityProduced:Wind:ToGrid(kw)')
320
397
  if $wind_to_grid_col.nil?
321
398
  $wind_to_grid_col = feature_report.timeseries_csv.column_names.length
322
- feature_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToGrid')
399
+ feature_report.timeseries_csv.column_names.push('REopt:ElectricityProduced:Wind:ToGrid(kw)')
323
400
  end
324
401
 
325
402
  def modrow(x, i) # :nodoc:
@@ -346,9 +423,12 @@ module URBANopt # :nodoc:
346
423
  end
347
424
 
348
425
  old_data = CSV.open(feature_report.timeseries_csv.path).read
426
+ start_date = Time.parse(old_data[1][0])
427
+ 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
428
+
349
429
  mod_data = old_data.map.with_index do |x, i|
350
430
  if i > 0
351
- modrow(x, i)
431
+ modrow(x, start_ts + i -2)
352
432
  else
353
433
  x
354
434
  end