urbanopt-reopt 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +27 -0
- data/.rakeTasks +7 -0
- data/.rdoc_options +37 -0
- data/.rspec +3 -0
- data/.rubocop.yml +9 -0
- data/.travis.yml +22 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +67 -0
- data/Jenkinsfile +10 -0
- data/LICENSE.md +27 -0
- data/RDOC_MAIN.md +176 -0
- data/README.md +177 -0
- data/Rakefile +30 -0
- data/deploy_docs.sh +5 -0
- data/developer_nrel_key.rb +31 -0
- data/doc_templates/LICENSE.md +27 -0
- data/doc_templates/README.md.erb +42 -0
- data/doc_templates/copyright_erb.txt +31 -0
- data/doc_templates/copyright_js.txt +4 -0
- data/doc_templates/copyright_ruby.txt +29 -0
- data/docs/.gitignore +3 -0
- data/docs/.vuepress/components/InnerJsonSchema.vue +78 -0
- data/docs/.vuepress/components/JsonSchema.vue +12 -0
- data/docs/.vuepress/components/ReoptInputSchema.vue +12 -0
- data/docs/.vuepress/components/ReoptOutputSchema.vue +12 -0
- data/docs/.vuepress/components/StaticLink.vue +8 -0
- data/docs/.vuepress/config.js +16 -0
- data/docs/.vuepress/highlight.js +8 -0
- data/docs/.vuepress/public/custom_rdoc_styles.css +58 -0
- data/docs/.vuepress/utils.js +17 -0
- data/docs/README.md +196 -0
- data/docs/package-lock.json +254 -0
- data/docs/package.json +22 -0
- data/docs/schemas/reopt-input-schema.md +57 -0
- data/docs/schemas/reopt-output-schema.md +66 -0
- data/index.html +1 -0
- data/index.md +176 -0
- data/lib/files/.gitkeep +0 -0
- data/lib/urbanopt/reopt/extension.rb +44 -0
- data/lib/urbanopt/reopt/feature_report_adapter.rb +364 -0
- data/lib/urbanopt/reopt/reopt_lite_api.rb +230 -0
- data/lib/urbanopt/reopt/reopt_logger.rb +42 -0
- data/lib/urbanopt/reopt/reopt_post_processor.rb +245 -0
- data/lib/urbanopt/reopt/reopt_schema/reopt_input_schema.json +1111 -0
- data/lib/urbanopt/reopt/reopt_schema/reopt_output_schema.json +538 -0
- data/lib/urbanopt/reopt/scenario/reopt_scenario_csv.rb +115 -0
- data/lib/urbanopt/reopt/scenario_report_adapter.rb +404 -0
- data/lib/urbanopt/reopt/version.rb +35 -0
- data/lib/urbanopt/reopt.rb +36 -0
- data/lib/urbanopt/reopt_scenario.rb +31 -0
- data/lib/urbanopt-reopt.rb +31 -0
- data/urbanopt-reopt.gemspec +33 -0
- metadata +194 -0
@@ -0,0 +1,404 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt, 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
|
+
|
31
|
+
require 'urbanopt/scenario/default_reports'
|
32
|
+
require 'urbanopt/reopt/reopt_logger'
|
33
|
+
|
34
|
+
require 'csv'
|
35
|
+
|
36
|
+
module URBANopt # :nodoc:
|
37
|
+
module REopt # :nodoc:
|
38
|
+
class ScenarioReportAdapter
|
39
|
+
##
|
40
|
+
# ScenarioReportAdapter can convert a ScenarioReport into a \REopt Lite posts or updates a ScenarioReport and its FeatureReports from \REopt Lite response(s)
|
41
|
+
##
|
42
|
+
# [*parameters:*]
|
43
|
+
def initialize
|
44
|
+
# initialize @@logger
|
45
|
+
@@logger ||= URBANopt::REopt.reopt_logger
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Convert a ScenarioReport into a \REopt Lite post
|
50
|
+
#
|
51
|
+
# [*parameters:*]
|
52
|
+
#
|
53
|
+
# * +scenario_report+ - _URBANopt::Scenario::DefaultReports::ScenarioReport_ - ScenarioReport to use in converting the +reopt_assumptions_hash+, if provided, to a \REopt Lite post. Otherwise, if the +reopt_assumptions_hash+ is nil a default post will be updated from this ScenarioReport and submitted to the \REopt Lite API.
|
54
|
+
# * +reopt_assumptions_hash+ - _Hash_ - Optional. A hash formatted for submittal to the \REopt Lite API containing default values. Values will be overwritten from the ScenarioReport where available (i.e. latitude, roof_squarefeet). Missing optional parameters will be filled in with default values by the API.
|
55
|
+
#
|
56
|
+
# [*return:*] _Hash_ - Returns hash formatted for submittal to the \REopt Lite API
|
57
|
+
##
|
58
|
+
def reopt_json_from_scenario_report(scenario_report, reopt_assumptions_json = nil)
|
59
|
+
name = scenario_report.name.delete ' '
|
60
|
+
scenario_id = scenario_report.id.delete ' '
|
61
|
+
description = "scenario_report_#{name}_#{scenario_id}"
|
62
|
+
|
63
|
+
# Create base REpopt Lite post
|
64
|
+
reopt_inputs = { Scenario: { Site: { ElectricTariff: { blended_monthly_demand_charges_us_dollars_per_kw: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], blended_monthly_rates_us_dollars_per_kwh: [0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13] }, LoadProfile: {}, Wind: { max_kw: 0 } } } }
|
65
|
+
if !reopt_assumptions_json.nil?
|
66
|
+
reopt_inputs = reopt_assumptions_json
|
67
|
+
else
|
68
|
+
@@logger.info('Using default REopt Lite assumptions')
|
69
|
+
end
|
70
|
+
|
71
|
+
# Update required info
|
72
|
+
if scenario_report.location.latitude.nil? || scenario_report.location.longitude.nil? || (scenario_report.location.latitude == 0) || (scenario_report.location.longitude == 0)
|
73
|
+
if !scenario_report.feature_reports.nil? && (scenario_report.feature_reports != [])
|
74
|
+
lats = []
|
75
|
+
longs = []
|
76
|
+
scenario_report.feature_reports.each do |x|
|
77
|
+
if ![nil, 0].include?(x[:location][:latitude]) && ![nil, 0].include?(x[:location][:longitude])
|
78
|
+
lats.push(x[:location][:latitude])
|
79
|
+
longs.push(x[:location][:longitude])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
if !lats.empty? && !longs.empty?
|
84
|
+
scenario_report.location.latitude = lats.reduce(:+) / lats.size.to_f
|
85
|
+
scenario_report.location.longitude = longs.reduce(:+) / longs.size.to_f
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Update required info
|
91
|
+
requireds_names = ['latitude', 'longitude']
|
92
|
+
requireds = [scenario_report.location.latitude, scenario_report.location.longitude]
|
93
|
+
|
94
|
+
if requireds.include?(nil) || requireds.include?(0)
|
95
|
+
requireds.each_with_index do |i, x|
|
96
|
+
if [nil, 0].include? x
|
97
|
+
n = requireds_names[i]
|
98
|
+
raise "Missing value for #{n} - this is a required input"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
reopt_inputs[:Scenario][:description] = description
|
104
|
+
|
105
|
+
reopt_inputs[:Scenario][:Site][:latitude] = scenario_report.location.latitude
|
106
|
+
reopt_inputs[:Scenario][:Site][:longitude] = scenario_report.location.longitude
|
107
|
+
|
108
|
+
# Update optional info
|
109
|
+
if !scenario_report.program.roof_area.nil?
|
110
|
+
reopt_inputs[:Scenario][:Site][:roof_squarefeet] = scenario_report.program.roof_area[:available_roof_area]
|
111
|
+
end
|
112
|
+
|
113
|
+
if !scenario_report.program.site_area.nil?
|
114
|
+
reopt_inputs[:Scenario][:Site][:land_acres] = scenario_report.program.site_area * 1.0 / 43560 # acres/sqft
|
115
|
+
end
|
116
|
+
|
117
|
+
# Update load profile info
|
118
|
+
begin
|
119
|
+
col_num = scenario_report.timeseries_csv.column_names.index('Electricity:Facility')
|
120
|
+
t = CSV.read(scenario_report.timeseries_csv.path, headers: true, converters: :numeric)
|
121
|
+
energy_timeseries_kwh = t.by_col[col_num].map { |e| ((e || 0) * 0.293071) } # convert kBTU to KWH
|
122
|
+
|
123
|
+
if (scenario_report.timesteps_per_hour || 1) > 1
|
124
|
+
energy_timeseries_kwh = energy_timeseries_kwh.each_slice(scenario_report.timesteps_per_hour).to_a.map { |x| x.inject(0, :+) / x.length.to_f }
|
125
|
+
end
|
126
|
+
|
127
|
+
if energy_timeseries_kwh.length < scenario_report.timesteps_per_hour * 8760
|
128
|
+
energy_timeseries_kwh += [0] * ((scenario_report.timesteps_per_hour * 8760) - energy_timeseries_kwh.length)
|
129
|
+
@@logger.info("Assuming load profile for Scenario Report #{scenario_report.name} #{scenario_report.id} starts January 1 - filling in rest with zeros")
|
130
|
+
end
|
131
|
+
reopt_inputs[:Scenario][:Site][:LoadProfile][:loads_kw] = energy_timeseries_kwh
|
132
|
+
rescue StandardError
|
133
|
+
raise "Could not parse the annual electric load from the timeseries csv - #{scenario_report.timeseries_csv.path}"
|
134
|
+
end
|
135
|
+
|
136
|
+
return reopt_inputs
|
137
|
+
end
|
138
|
+
|
139
|
+
##
|
140
|
+
# Converts a FeatureReport list from a ScenarioReport into an array of \REopt Lite posts
|
141
|
+
#
|
142
|
+
# [*parameters:*]
|
143
|
+
#
|
144
|
+
# * +scenario_report+ - _URBANopt::Scenario::DefaultReports::ScenarioReport_ - ScenarioReport to use in converting FeatureReports and respecitive +reopt_assumptions_hashes+, if provided, to a \REopt Lite post. If no +reopt_assumptions_hashes+ are provided default posts will be updated from these FeatureReports and submitted to the \REopt Lite API.
|
145
|
+
# * +reopt_assumptions_hashes+ - _Array_ - Optional. An array of hashes formatted for submittal to the \REopt Lite API containing default values. Values will be overwritten from the ScenarioReport where available (i.e. latitude, roof_squarefeet). Missing optional parameters will be filled in with default values by the API. The order should match the list in ScenarioReport.feature_reports.
|
146
|
+
#
|
147
|
+
# [*return:*] _Array_ - Returns an array of hashes formatted for submittal to the \REopt Lite API in the order of the FeatureReports lited in ScenarioReport.feature_reports.
|
148
|
+
##
|
149
|
+
def reopt_jsons_from_scenario_feature_reports(scenario_report, reopt_assumptions_hashes = [])
|
150
|
+
results = []
|
151
|
+
adapter = URBANopt::REopt::FeatureReportAdapter.new
|
152
|
+
|
153
|
+
scenario_report.feature_reports.each_with_index do |feature_report, idx|
|
154
|
+
fr = adapter.reopt_json_from_feature_report(feature_report, reopt_assumptions_hashes[idx])
|
155
|
+
results << fr
|
156
|
+
end
|
157
|
+
|
158
|
+
return results
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# Updates a ScenarioReport from a \REopt Lite response
|
163
|
+
#
|
164
|
+
# [*parameters:*]
|
165
|
+
#
|
166
|
+
# * +scenario_report+ - _URBANopt::Scenario::DefaultReports::ScenarioReport_ - ScenarioReport to update from a \REopt Lite response.
|
167
|
+
# * +reopt_output+ - _Hash_ - A hash response from the \REopt Lite API.
|
168
|
+
# * +timeseries_csv_path+ - _String_ - Optional. The path to a file at which new timeseries data will be written. If not provided a file is created based on the run_uuid of the \REopt Lite optimization task.
|
169
|
+
#
|
170
|
+
# [*return:*] _URBANopt::Scenario::DefaultReports::ScenarioReport_ - Returns an updated ScenarioReport
|
171
|
+
##
|
172
|
+
def update_scenario_report(scenario_report, reopt_output, timeseries_csv_path = nil)
|
173
|
+
if reopt_output['outputs']['Scenario']['status'] != 'optimal'
|
174
|
+
@@logger.info("Warning cannot Feature Report #{scenario_report.name} #{scenario_report.id} - REopt optimization was non-optimal")
|
175
|
+
return scenario_report
|
176
|
+
end
|
177
|
+
|
178
|
+
# Update location
|
179
|
+
scenario_report.location.latitude = reopt_output['inputs']['Scenario']['Site']['latitude']
|
180
|
+
scenario_report.location.longitude = reopt_output['inputs']['Scenario']['Site']['longitude']
|
181
|
+
|
182
|
+
# Update timeseries csv from \REopt Lite dispatch data
|
183
|
+
scenario_report.timesteps_per_hour = reopt_output['inputs']['Scenario']['time_steps_per_hour']
|
184
|
+
|
185
|
+
# Update distributed generation sizing and financials
|
186
|
+
(scenario_report.distributed_generation.lcc_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['lcc_us_dollars']) || 0
|
187
|
+
(scenario_report.distributed_generation.npv_us_dollars = reopt_output['outputs']['Scenario']['Site']['Financial']['npv_us_dollars']) || 0
|
188
|
+
(scenario_report.distributed_generation.year_one_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_energy_cost_us_dollars']) || 0
|
189
|
+
(scenario_report.distributed_generation.year_one_demand_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_demand_cost_us_dollars']) || 0
|
190
|
+
(scenario_report.distributed_generation.year_one_bill_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_bill_us_dollars']) || 0
|
191
|
+
(scenario_report.distributed_generation.total_energy_cost_us_dollars = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['total_energy_cost_us_dollars']) || 0
|
192
|
+
|
193
|
+
(scenario_report.distributed_generation.solar_pv.size_kw = reopt_output['outputs']['Scenario']['Site']['PV']['size_kw']) || 0
|
194
|
+
(scenario_report.distributed_generation.wind.size_kw = reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw']) || 0
|
195
|
+
(scenario_report.distributed_generation.generator.size_kw = reopt_output['outputs']['Scenario']['Site']['Generator']['size_kw']) || 0
|
196
|
+
(scenario_report.distributed_generation.storage.size_kw = reopt_output['outputs']['Scenario']['Site']['Storage']['size_kw']) || 0
|
197
|
+
(scenario_report.distributed_generation.storage.size_kwh = reopt_output['outputs']['Scenario']['Site']['Storage']['size_kwh']) || 0
|
198
|
+
|
199
|
+
# Update dispatch
|
200
|
+
generation_timeseries_kwh = Matrix[[0] * 8760]
|
201
|
+
unless reopt_output['outputs']['Scenario']['Site']['PV'].nil?
|
202
|
+
if (reopt_output['outputs']['Scenario']['Site']['PV']['size_kw'] || 0) > 0
|
203
|
+
if !reopt_output['outputs']['Scenario']['Site']['PV']['year_one_power_production_series_kw'].nil?
|
204
|
+
generation_timeseries_kwh += Matrix[reopt_output['outputs']['Scenario']['Site']['PV']['year_one_power_production_series_kw']]
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# unless reopt_output['outputs']['Scenario']['Site']['Storage'].nil?
|
210
|
+
# if (reopt_output['outputs']['Scenario']['Site']['Storage']['size_kw'] or 0) > 0
|
211
|
+
# if !reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'].nil?
|
212
|
+
# generation_timeseries_kwh = generation_timeseries_kwh + Matrix[reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw']]
|
213
|
+
# end
|
214
|
+
# end
|
215
|
+
# end
|
216
|
+
|
217
|
+
unless reopt_output['outputs']['Scenario']['Site']['Wind'].nil?
|
218
|
+
if (reopt_output['outputs']['Scenario']['Site']['Wind']['size_kw'] || 0) > 0
|
219
|
+
if !reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'].nil?
|
220
|
+
generation_timeseries_kwh += Matrix[reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw']]
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
unless reopt_output['outputs']['Scenario']['Site']['Generator'].nil?
|
226
|
+
if (reopt_output['outputs']['Scenario']['Site']['Generator']['size_kw'] || 0) > 0
|
227
|
+
if !reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'].nil?
|
228
|
+
generation_timeseries_kwh += Matrix[reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw']]
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
$generation_timeseries_kwh = generation_timeseries_kwh.to_a[0]
|
234
|
+
$generation_timeseries_kwh_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Total')
|
235
|
+
if $generation_timeseries_kwh_col.nil?
|
236
|
+
$generation_timeseries_kwh_col = scenario_report.timeseries_csv.column_names.length
|
237
|
+
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Total')
|
238
|
+
end
|
239
|
+
|
240
|
+
$load = reopt_output['outputs']['Scenario']['Site']['LoadProfile']['year_one_electric_load_series_kw'] || [0] * 8760
|
241
|
+
$load_col = scenario_report.timeseries_csv.column_names.index('Electricity:Load:Total')
|
242
|
+
if $load_col.nil?
|
243
|
+
$load_col = scenario_report.timeseries_csv.column_names.length
|
244
|
+
scenario_report.timeseries_csv.column_names.push('Electricity:Load:Total')
|
245
|
+
end
|
246
|
+
|
247
|
+
$utility_to_load = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_load_series_kw'] || [0] * 8760
|
248
|
+
$utility_to_load_col = scenario_report.timeseries_csv.column_names.index('Electricity:Grid:ToLoad')
|
249
|
+
if $utility_to_load_col.nil?
|
250
|
+
$utility_to_load_col = scenario_report.timeseries_csv.column_names.length
|
251
|
+
scenario_report.timeseries_csv.column_names.push('Electricity:Grid:ToLoad')
|
252
|
+
end
|
253
|
+
|
254
|
+
$utility_to_battery = reopt_output['outputs']['Scenario']['Site']['ElectricTariff']['year_one_to_battery_series_kw'] || [0] * 8760
|
255
|
+
$utility_to_battery_col = scenario_report.timeseries_csv.column_names.index('Electricity:Grid:ToBattery')
|
256
|
+
if $utility_to_battery_col.nil?
|
257
|
+
$utility_to_battery_col = scenario_report.timeseries_csv.column_names.length
|
258
|
+
scenario_report.timeseries_csv.column_names.push('Electricity:Grid:ToBattery')
|
259
|
+
end
|
260
|
+
|
261
|
+
$storage_to_load = reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw'] || [0] * 8760
|
262
|
+
$storage_to_load_col = scenario_report.timeseries_csv.column_names.index('Electricity:Storage:ToLoad')
|
263
|
+
if $storage_to_load_col.nil?
|
264
|
+
$storage_to_load_col = scenario_report.timeseries_csv.column_names.length
|
265
|
+
scenario_report.timeseries_csv.column_names.push('Electricity:Storage:ToLoad')
|
266
|
+
end
|
267
|
+
|
268
|
+
$storage_to_grid = reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_to_grid_series_kw'] || [0] * 8760
|
269
|
+
$storage_to_grid_col = scenario_report.timeseries_csv.column_names.index('Electricity:Storage:ToGrid')
|
270
|
+
if $storage_to_grid_col.nil?
|
271
|
+
$storage_to_grid_col = scenario_report.timeseries_csv.column_names.length
|
272
|
+
scenario_report.timeseries_csv.column_names.push('Electricity:Storage:ToGrid')
|
273
|
+
end
|
274
|
+
|
275
|
+
$storage_soc = reopt_output['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct'] || [0] * 8760
|
276
|
+
$storage_soc_col = scenario_report.timeseries_csv.column_names.index('Electricity:Storage:StateOfCharge')
|
277
|
+
if $storage_soc_col.nil?
|
278
|
+
$storage_soc_col = scenario_report.timeseries_csv.column_names.length
|
279
|
+
scenario_report.timeseries_csv.column_names.push('Electricity:Storage:StateOfCharge')
|
280
|
+
end
|
281
|
+
|
282
|
+
$generator_total = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_power_production_series_kw'] || [0] * 8760
|
283
|
+
$generator_total_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:Total')
|
284
|
+
if $generator_total_col.nil?
|
285
|
+
$generator_total_col = scenario_report.timeseries_csv.column_names.length
|
286
|
+
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:Total')
|
287
|
+
end
|
288
|
+
|
289
|
+
$generator_to_battery = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_battery_series_kw'] || [0] * 8760
|
290
|
+
$generator_to_battery_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:ToBattery')
|
291
|
+
if $generator_to_battery_col.nil?
|
292
|
+
$generator_to_battery_col = scenario_report.timeseries_csv.column_names.length
|
293
|
+
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToBattery')
|
294
|
+
end
|
295
|
+
|
296
|
+
$generator_to_load = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw'] || [0] * 8760
|
297
|
+
$generator_to_load_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:ToLoad')
|
298
|
+
if $generator_to_load_col.nil?
|
299
|
+
$generator_to_load_col = scenario_report.timeseries_csv.column_names.length
|
300
|
+
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToLoad')
|
301
|
+
end
|
302
|
+
|
303
|
+
$generator_to_grid = reopt_output['outputs']['Scenario']['Site']['Generator']['year_one_to_grid_series_kw'] || [0] * 8760
|
304
|
+
$generator_to_grid_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Generator:ToGrid')
|
305
|
+
if $generator_to_grid_col.nil?
|
306
|
+
$generator_to_grid_col = scenario_report.timeseries_csv.column_names.length
|
307
|
+
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Generator:ToGrid')
|
308
|
+
end
|
309
|
+
|
310
|
+
$pv_total = reopt_output['outputs']['Scenario']['Site']['PV']['year_one_power_production_series_kw'] || [0] * 8760
|
311
|
+
$pv_total_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:PV:Total')
|
312
|
+
if $pv_total_col.nil?
|
313
|
+
$pv_total_col = scenario_report.timeseries_csv.column_names.length
|
314
|
+
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:PV:Total')
|
315
|
+
end
|
316
|
+
|
317
|
+
$pv_to_battery = reopt_output['outputs']['Scenario']['Site']['PV']['year_one_to_battery_series_kw'] || [0] * 8760
|
318
|
+
$pv_to_battery_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToBattery')
|
319
|
+
if $pv_to_battery_col.nil?
|
320
|
+
$pv_to_battery_col = scenario_report.timeseries_csv.column_names.length
|
321
|
+
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToBattery')
|
322
|
+
end
|
323
|
+
|
324
|
+
$pv_to_load = reopt_output['outputs']['Scenario']['Site']['PV']['year_one_to_load_series_kw'] || [0] * 8760
|
325
|
+
$pv_to_load_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToLoad')
|
326
|
+
if $pv_to_load_col.nil?
|
327
|
+
$pv_to_load_col = scenario_report.timeseries_csv.column_names.length
|
328
|
+
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToLoad')
|
329
|
+
end
|
330
|
+
|
331
|
+
$pv_to_grid = reopt_output['outputs']['Scenario']['Site']['PV']['year_one_to_grid_series_kw'] || [0] * 8760
|
332
|
+
$pv_to_grid_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:PV:ToGrid')
|
333
|
+
if $pv_to_grid_col.nil?
|
334
|
+
$pv_to_grid_col = scenario_report.timeseries_csv.column_names.length
|
335
|
+
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:PV:ToGrid')
|
336
|
+
end
|
337
|
+
|
338
|
+
$wind_total = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_power_production_series_kw'] || [0] * 8760
|
339
|
+
$wind_total_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:Total')
|
340
|
+
if $wind_total_col.nil?
|
341
|
+
$wind_total_col = scenario_report.timeseries_csv.column_names.length
|
342
|
+
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:Total')
|
343
|
+
end
|
344
|
+
|
345
|
+
$wind_to_battery = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_battery_series_kw'] || [0] * 8760
|
346
|
+
$wind_to_battery_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:ToBattery')
|
347
|
+
if $wind_to_battery_col.nil?
|
348
|
+
$wind_to_battery_col = scenario_report.timeseries_csv.column_names.length
|
349
|
+
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToBattery')
|
350
|
+
end
|
351
|
+
|
352
|
+
$wind_to_load = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_load_series_kw'] || [0] * 8760
|
353
|
+
$wind_to_load_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:ToLoad')
|
354
|
+
if $wind_to_load_col.nil?
|
355
|
+
$wind_to_load_col = scenario_report.timeseries_csv.column_names.length
|
356
|
+
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToLoad')
|
357
|
+
end
|
358
|
+
|
359
|
+
$wind_to_grid = reopt_output['outputs']['Scenario']['Site']['Wind']['year_one_to_grid_series_kw'] || [0] * 8760
|
360
|
+
$wind_to_grid_col = scenario_report.timeseries_csv.column_names.index('ElectricityProduced:Wind:ToGrid')
|
361
|
+
if $wind_to_grid_col.nil?
|
362
|
+
$wind_to_grid_col = scenario_report.timeseries_csv.column_names.length
|
363
|
+
scenario_report.timeseries_csv.column_names.push('ElectricityProduced:Wind:ToGrid')
|
364
|
+
end
|
365
|
+
|
366
|
+
def modrow(x, i) # :nodoc:
|
367
|
+
x[$generation_timeseries_kwh_col] = $generation_timeseries_kwh[i] || 0
|
368
|
+
x[$load_col] = $load[i] || 0
|
369
|
+
x[$utility_to_load_col] = $utility_to_load[i] || 0
|
370
|
+
x[$utility_to_battery_col] = $utility_to_battery[i] || 0
|
371
|
+
x[$storage_to_load_col] = $storage_to_load[i] || 0
|
372
|
+
x[$storage_to_grid_col] = $storage_to_grid[i] || 0
|
373
|
+
x[$storage_soc_col] = $storage_soc[i] || 0
|
374
|
+
x[$generator_total_col] = $generator_total[i] || 0
|
375
|
+
x[$generator_to_battery_col] = $generator_to_battery[i] || 0
|
376
|
+
x[$generator_to_load_col] = $generator_to_load[i] || 0
|
377
|
+
x[$generator_to_grid_col] = $generator_to_grid[i] || 0
|
378
|
+
x[$pv_total_col] = $pv_total[i] || 0
|
379
|
+
x[$pv_to_battery_col] = $pv_to_battery[i] || 0
|
380
|
+
x[$pv_to_load_col] = $pv_to_load[i] || 0
|
381
|
+
x[$pv_to_grid_col] = $pv_to_grid[i] || 0
|
382
|
+
x[$wind_total_col] = $wind_total[i] || 0
|
383
|
+
x[$wind_to_battery_col] = $wind_to_battery[i] || 0
|
384
|
+
x[$wind_to_load_col] = $wind_to_load[i] || 0
|
385
|
+
x[$wind_to_grid_col] = $wind_to_grid[i] || 0
|
386
|
+
return x
|
387
|
+
end
|
388
|
+
|
389
|
+
old_data = CSV.open(scenario_report.timeseries_csv.path).read
|
390
|
+
mod_data = old_data.map.with_index do |x, i|
|
391
|
+
if i > 0
|
392
|
+
modrow(x, i)
|
393
|
+
else
|
394
|
+
x
|
395
|
+
end
|
396
|
+
end
|
397
|
+
mod_data[0] = scenario_report.timeseries_csv.column_names
|
398
|
+
|
399
|
+
scenario_report.timeseries_csv.reload_data(mod_data)
|
400
|
+
return scenario_report
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt, 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
|
+
|
31
|
+
module URBANopt # :nodoc:
|
32
|
+
module REopt # :nodoc:
|
33
|
+
VERSION = '0.1.0'.freeze
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt, 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
|
+
|
31
|
+
require 'urbanopt/reopt/extension'
|
32
|
+
require 'urbanopt/reopt/reopt_lite_api'
|
33
|
+
require 'urbanopt/reopt/feature_report_adapter'
|
34
|
+
require 'urbanopt/reopt/scenario_report_adapter'
|
35
|
+
require 'urbanopt/reopt/reopt_post_processor'
|
36
|
+
require 'urbanopt/reopt/version'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt, 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
|
+
|
31
|
+
require 'urbanopt/reopt/scenario/reopt_scenario_csv'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt, 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
|
+
|
31
|
+
require_relative 'urbanopt/reopt'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path('lib', __dir__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'urbanopt/reopt/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'urbanopt-reopt'
|
8
|
+
spec.version = URBANopt::REopt::VERSION
|
9
|
+
spec.authors = ['']
|
10
|
+
spec.email = ['']
|
11
|
+
|
12
|
+
spec.summary = 'Classes and measures for utilizing the REopt Lite API within OpenStudio workflows.'
|
13
|
+
spec.description = 'Classes and measures for utilizing the REopt Lite API within OpenStudio workflows.'
|
14
|
+
spec.homepage = 'https://github.com/urbanopt/urbanopt-reopt-gem'
|
15
|
+
|
16
|
+
# Specify which files should be added to the gem when it is released.
|
17
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
18
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
19
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
20
|
+
end
|
21
|
+
spec.bindir = 'exe'
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.14'
|
26
|
+
spec.add_development_dependency 'rake', '12.3.1'
|
27
|
+
spec.add_development_dependency 'rspec', '3.7.0'
|
28
|
+
spec.add_development_dependency 'rubocop', '~> 0.54.0'
|
29
|
+
|
30
|
+
spec.add_dependency 'certified'
|
31
|
+
spec.add_dependency 'json_pure'
|
32
|
+
spec.add_dependency 'urbanopt-scenario', '0.1.1'
|
33
|
+
end
|