urbanopt-reopt 0.1.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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