urbanopt-cli 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +10 -1
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +36 -0
- data/Gemfile +30 -26
- data/README.md +27 -14
- data/Rakefile +6 -0
- data/developer_nrel_key.rb +1 -0
- data/example_files/Gemfile +22 -36
- data/example_files/example_project.json +1 -1
- data/example_files/mappers/Baseline.rb +112 -93
- data/example_files/mappers/HighEfficiency.rb +2 -1
- data/lib/uo_cli.rb +207 -167
- data/lib/uo_cli/version.rb +2 -1
- data/uo_cli.gemspec +9 -11
- metadata +30 -33
- data/lib/change_log.rb +0 -152
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
# *********************************************************************************
|
2
3
|
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
4
|
# contributors. All rights reserved.
|
@@ -51,7 +52,7 @@ module URBANopt
|
|
51
52
|
OpenStudio::Extension.set_measure_argument(osw, 'ReduceLightingLoadsByPercentage', '__SKIP__', false)
|
52
53
|
OpenStudio::Extension.set_measure_argument(osw, 'ReduceLightingLoadsByPercentage', 'lighting_power_reduction_percent', 10)
|
53
54
|
|
54
|
-
osw
|
55
|
+
return osw
|
55
56
|
end
|
56
57
|
end
|
57
58
|
end
|
data/lib/uo_cli.rb
CHANGED
@@ -31,7 +31,7 @@
|
|
31
31
|
# *********************************************************************************
|
32
32
|
|
33
33
|
require 'uo_cli/version'
|
34
|
-
require '
|
34
|
+
require 'optimist'
|
35
35
|
require 'urbanopt/geojson'
|
36
36
|
require 'urbanopt/scenario'
|
37
37
|
require 'urbanopt/reopt'
|
@@ -43,101 +43,145 @@ require_relative '../developer_nrel_key'
|
|
43
43
|
|
44
44
|
module URBANopt
|
45
45
|
module CLI
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
46
|
+
class UrbanOptCLI
|
47
|
+
COMMAND_MAP = {
|
48
|
+
'create' => 'Make new things - project directory or files',
|
49
|
+
'run' => 'Use files in your directory to simulate district energy use',
|
50
|
+
'process' => 'Post-process URBANopt simulations for additional insights',
|
51
|
+
'delete' => 'Delete simulations for a specified scenario'
|
52
|
+
}.freeze
|
53
|
+
|
54
|
+
def initialize
|
55
|
+
@subopts = nil
|
56
|
+
@command = nil
|
57
|
+
@mainopts = Optimist.options do
|
58
|
+
version VERSION
|
59
|
+
banner "\nURBANopt CLI version: #{version}"
|
60
|
+
banner "\nUsage:"
|
61
|
+
banner " uo [options] [<command> [suboptions]]\n \n"
|
62
|
+
banner 'Options:'
|
63
|
+
opt :version, 'Print version and exit' ## add this here or it goes to bottom of help
|
64
|
+
opt :help, 'Show this help message' ## add this here or it goes to bottom of help
|
65
|
+
# opt :no_pager, "Disable paging"
|
66
|
+
stop_on COMMAND_MAP.keys
|
67
|
+
banner "\nCommands:"
|
68
|
+
COMMAND_MAP.each { |cmd, desc| banner format(' %-10s %s', cmd, desc) }
|
69
|
+
banner "\nFor help with a specific command: uo <command> --help"
|
70
|
+
banner "\nAdditional config options can be set with the 'runner.conf' file inside your project folder"
|
71
|
+
banner 'Fewer warnings are presented when using full paths and the user is not inside the project folder'
|
72
|
+
end
|
73
|
+
return if ARGV.empty?
|
74
|
+
@command = ARGV.shift
|
75
|
+
send("opt_#{@command}") ## dispatch to command handling method
|
59
76
|
end
|
60
77
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
"
|
66
|
-
|
67
|
-
|
78
|
+
# Define creation commands
|
79
|
+
def opt_create
|
80
|
+
cmd = @command
|
81
|
+
@subopts = Optimist.options do
|
82
|
+
banner "\nURBANopt #{cmd}:\n \n"
|
83
|
+
|
84
|
+
opt :project_folder, "\nCreate project directory in your current folder. Name the directory\n" \
|
85
|
+
'Example: uo create --project urbanopt_example_project', type: String
|
86
|
+
|
87
|
+
opt :empty, "\nUse with --project-folder argument to create an empty project folder\n" \
|
88
|
+
"Then add your own Feature file in the project directory you created,\n" \
|
89
|
+
"add Weather files in the weather folder and add OpenStudio models of Features\n" \
|
90
|
+
"in the Feature File, if any, in the osm_building folder\n" \
|
91
|
+
"Example: uo create --empty --project-folder urbanopt_example_project\n" \
|
92
|
+
|
93
|
+
opt :overwrite, "\nUse with --project-folder argument to overwrite existing project folder and replace with new project folder.\n" \
|
94
|
+
"May be combined with --empty as well to overwrite existing project folder and replace with new empty project folder.\n" \
|
95
|
+
'Example: uo create --overwrite --empty --project-folder urbanopt_project_folder_I_want_destroyed'
|
96
|
+
|
97
|
+
opt :scenario_file, "\nAutomatically create a ScenarioFile containing the features in FeatureFile for each scenario\n" \
|
98
|
+
"Provide the FeatureFile used to create the ScenarioFile\n" \
|
99
|
+
'Example: uo create --scenario-file example_project.json', type: String
|
100
|
+
|
101
|
+
opt :single_feature, "\nCreate a ScenarioFile with only a single feature\n" \
|
102
|
+
"Use the FeatureID from your FeatureFile\n" \
|
103
|
+
"Requires 'scenario-file' also be specified, to say which FeatureFile will create the ScenarioFile\n" \
|
104
|
+
'Example: uo create --single-feature 2 --scenario-file example_project.json', type: String
|
105
|
+
|
106
|
+
opt :reopt_scenario_file, "\nCreate a ScenarioFile that includes a column defining the REopt assumptions file\n" \
|
107
|
+
"Specify the existing ScenarioFile that you want to extend with REopt functionality\n" \
|
108
|
+
'Example: uo create --reopt-scenario-file baseline_scenario.csv', type: String
|
109
|
+
end
|
68
110
|
end
|
69
111
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
@user_input[:overwrite_project_folder] = 'Overwriting existing project folder' # This text does not get displayed to the user
|
76
|
-
end
|
112
|
+
# Define running commands
|
113
|
+
def opt_run
|
114
|
+
cmd = @command
|
115
|
+
@subopts = Optimist.options do
|
116
|
+
banner "\nURBANopt #{cmd}:\n \n"
|
77
117
|
|
78
|
-
|
79
|
-
" Example: uo -m -f example_project.json\n" \
|
80
|
-
" Or, Create Scenario CSV for each MapperFile for a single Feature from Feature File. Must specify -f and -i argument\n" \
|
81
|
-
' Example: uo -m -f example_project.json -i 1') do
|
82
|
-
@user_input[:make_scenario_from] = "Create scenario files from FeatureFiles or for single Feature according to the MapperFiles in the 'mappers' directory" # This text does not get displayed to the user
|
83
|
-
end
|
118
|
+
opt :reopt, "\nSimulate with additional REopt functionality. Must do this before post-processing with REopt"
|
84
119
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
120
|
+
opt :scenario, "\nRun URBANopt simulations for <scenario>\n" \
|
121
|
+
"Requires --feature also be specified\n" \
|
122
|
+
'Example: uo run --scenario baseline_scenario-2.csv --feature example_project.jsonn', default: 'baseline_scenario.csv', required: true
|
89
123
|
|
90
|
-
|
91
|
-
|
92
|
-
|
124
|
+
opt :feature, "\nRun URBANopt simulations according to <featurefile>\n" \
|
125
|
+
"Requires --scenario also be specified\n" \
|
126
|
+
'Example: uo run --scenario baseline_scenario.csv --feature example_project.json', default: 'example_project.json', required: true
|
127
|
+
end
|
93
128
|
end
|
94
129
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
130
|
+
# Define post-processing commands
|
131
|
+
def opt_process
|
132
|
+
cmd = @command
|
133
|
+
@subopts = Optimist.options do
|
134
|
+
banner "\nURBANopt #{cmd}:\n \n"
|
99
135
|
|
100
|
-
|
101
|
-
@user_input[:scenario] = scenario
|
102
|
-
@root_dir, @scenario_file_name = File.split(File.absolute_path(@user_input[:scenario]))
|
103
|
-
end
|
136
|
+
opt :default, "\nStandard post-processing for your scenario"
|
104
137
|
|
105
|
-
|
106
|
-
@user_input[:feature] = feature
|
107
|
-
@feature_path, @feature_name = File.split(File.absolute_path(@user_input[:feature]))
|
108
|
-
end
|
138
|
+
opt :opendss, "\nPost-process with OpenDSS"
|
109
139
|
|
110
|
-
|
111
|
-
|
112
|
-
|
140
|
+
opt :reopt_scenario, "\nOptimize for entire scenario with REopt\n" \
|
141
|
+
'Example: uo process --reopt-scenario'
|
142
|
+
|
143
|
+
opt :reopt_feature, "\nOptimize for each building individually with REopt\n" \
|
144
|
+
'Example: uo process --reopt-feature'
|
113
145
|
|
114
|
-
|
115
|
-
|
116
|
-
"
|
117
|
-
|
118
|
-
" opendss\n") do |type|
|
119
|
-
@user_input[:type] = type
|
146
|
+
opt :scenario, "\nSelect which scenario to optimize", default: 'baseline_scenario.csv', required: true
|
147
|
+
|
148
|
+
opt :feature, "\nSelect which FeatureFile to use", default: 'example_project.json', required: true
|
149
|
+
end
|
120
150
|
end
|
121
151
|
|
122
|
-
|
123
|
-
|
152
|
+
def opt_delete
|
153
|
+
cmd = @command
|
154
|
+
@subopts = Optimist.options do
|
155
|
+
banner "\nURBANopt #{cmd}:\n \n"
|
156
|
+
|
157
|
+
opt :scenario, "\nDelete simulation files for this scenario", default: 'baseline_scenario.csv', required: true
|
158
|
+
end
|
124
159
|
end
|
160
|
+
|
161
|
+
attr_reader :mainopts, :command, :subopts
|
125
162
|
end
|
126
163
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
164
|
+
# Initialize the CLI class
|
165
|
+
@opthash = UrbanOptCLI.new
|
166
|
+
|
167
|
+
# Pull out feature and scenario filenames and paths
|
168
|
+
if @opthash.subopts[:scenario_file]
|
169
|
+
@feature_path, @feature_name = File.split(File.absolute_path(@opthash.subopts[:scenario_file]))
|
170
|
+
end
|
171
|
+
# FIXME: Can this be combined with the above block? This isn't very DRY
|
172
|
+
# One solution would be changing scenario_file to feature.
|
173
|
+
# Would that be confusing when creating a ScenarioFile from the FeatureFile?
|
174
|
+
if @opthash.subopts[:feature]
|
175
|
+
@feature_path, @feature_name = File.split(File.absolute_path(@opthash.subopts[:feature]))
|
176
|
+
end
|
177
|
+
if @opthash.subopts[:scenario]
|
178
|
+
@root_dir, @scenario_file_name = File.split(File.absolute_path(@opthash.subopts[:scenario]))
|
131
179
|
end
|
132
180
|
|
133
181
|
# Simulate energy usage as defined by ScenarioCSV\
|
134
182
|
# params\
|
135
183
|
# +scenario+:: _string_ Path to csv file that defines the scenario\
|
136
184
|
# +feature_file_path+:: _string_ Path to Feature File used to describe set of features in the district
|
137
|
-
#
|
138
|
-
# FIXME: This only works when scenario_file and feature_file are in the project root directory
|
139
|
-
# This works when called with filename (from inside project directory) and with absolute filepaths
|
140
|
-
# Also, feels a little weird that now I'm only using instance variables and not passing anything to this function. I guess it's ok?
|
141
185
|
def self.run_func
|
142
186
|
name = File.basename(@scenario_file_name, File.extname(@scenario_file_name))
|
143
187
|
run_dir = File.join(@root_dir, 'run', name.downcase)
|
@@ -147,8 +191,9 @@ module URBANopt
|
|
147
191
|
reopt_files_dir = File.join(@root_dir, 'reopt/')
|
148
192
|
num_header_rows = 1
|
149
193
|
# FIXME: This can be cleaned up in Ruby 2.5 with Dir.children(<"foldername">)
|
194
|
+
# TODO: Better way of grabbing assumptions file than the first file in the folder
|
150
195
|
reopt_files_dir_contents_list = Dir["#{reopt_files_dir}/*"]
|
151
|
-
|
196
|
+
reopt_assumptions_filename = File.basename(reopt_files_dir_contents_list[0])
|
152
197
|
|
153
198
|
if @feature_id
|
154
199
|
feature_run_dir = File.join(run_dir, @feature_id)
|
@@ -157,7 +202,11 @@ module URBANopt
|
|
157
202
|
end
|
158
203
|
|
159
204
|
feature_file = URBANopt::GeoJSON::GeoFile.from_file(featurefile)
|
160
|
-
|
205
|
+
if @opthash.subopts[:reopt] == true || @opthash.subopts[:reopt_scenario] == true || @opthash.subopts[:reopt_feature] == true
|
206
|
+
scenario_output = URBANopt::Scenario::REoptScenarioCSV.new(name, @root_dir, run_dir, feature_file, mapper_files_dir, csv_file, num_header_rows, reopt_files_dir, reopt_assumptions_filename)
|
207
|
+
else
|
208
|
+
scenario_output = URBANopt::Scenario::ScenarioCSV.new(name, @root_dir, run_dir, feature_file, mapper_files_dir, csv_file, num_header_rows)
|
209
|
+
end
|
161
210
|
scenario_output
|
162
211
|
end
|
163
212
|
|
@@ -165,25 +214,24 @@ module URBANopt
|
|
165
214
|
# params\
|
166
215
|
# +feature_file_path+:: _string_ Path to a FeatureFile
|
167
216
|
def self.create_scenario_csv_file(feature_id)
|
168
|
-
feature_file_json = JSON.parse(File.read(File.absolute_path(@
|
217
|
+
feature_file_json = JSON.parse(File.read(File.absolute_path(@opthash.subopts[:scenario_file])), symbolize_names: true)
|
169
218
|
Dir["#{@feature_path}/mappers/*.rb"].each do |mapper_file|
|
170
|
-
|
171
|
-
mapper_name = mapper_name.split('.')[0]
|
219
|
+
mapper_name = File.basename(mapper_file, File.extname(mapper_file))
|
172
220
|
scenario_file_name = if feature_id == 'SKIP'
|
173
221
|
"#{mapper_name.downcase}_scenario.csv"
|
174
222
|
else
|
175
223
|
"#{mapper_name.downcase}_scenario-#{feature_id}.csv"
|
176
224
|
end
|
177
225
|
CSV.open(File.join(@feature_path, scenario_file_name), 'wb', write_headers: true,
|
178
|
-
headers: ['Feature Id', 'Feature Name', 'Mapper Class'
|
226
|
+
headers: ['Feature Id', 'Feature Name', 'Mapper Class']) do |csv|
|
179
227
|
feature_file_json[:features].each do |feature|
|
180
228
|
if feature_id == 'SKIP'
|
181
229
|
# ensure that feature is a building
|
182
230
|
if feature[:properties][:type] == 'Building'
|
183
|
-
csv << [feature[:properties][:id], feature[:properties][:name], "URBANopt::Scenario::#{mapper_name}Mapper"
|
184
|
-
|
185
|
-
elsif feature_id == feature[:properties][:id]
|
186
|
-
csv << [feature[:properties][:id], feature[:properties][:name], "URBANopt::Scenario::#{mapper_name}Mapper"
|
231
|
+
csv << [feature[:properties][:id], feature[:properties][:name], "URBANopt::Scenario::#{mapper_name}Mapper"]
|
232
|
+
end
|
233
|
+
elsif feature_id == feature[:properties][:id]
|
234
|
+
csv << [feature[:properties][:id], feature[:properties][:name], "URBANopt::Scenario::#{mapper_name}Mapper"]
|
187
235
|
elsif
|
188
236
|
# If Feature ID specified does not exist in the Feature File raise error
|
189
237
|
unless feature_file_json[:features].any? { |hash| hash[:properties][:id].include?(feature_id.to_s) }
|
@@ -195,24 +243,38 @@ module URBANopt
|
|
195
243
|
end
|
196
244
|
end
|
197
245
|
|
246
|
+
# Write new ScenarioFile with REopt column
|
247
|
+
# params \
|
248
|
+
# +existing_scenario_file+:: _string_ - Name of existing ScenarioFile
|
249
|
+
def self.create_reopt_scenario_file(existing_scenario_file)
|
250
|
+
existing_path, existing_name = File.split(File.absolute_path(existing_scenario_file))
|
251
|
+
table = CSV.read(existing_scenario_file, headers: true, col_sep: ',')
|
252
|
+
# Add another column, row by row:
|
253
|
+
table.each do |row|
|
254
|
+
row['REopt Assumptions'] = 'multiPV_assumptions.json'
|
255
|
+
end
|
256
|
+
# write new file
|
257
|
+
CSV.open(File.join(existing_path, 'REopt_scenario.csv'), 'w') do |f|
|
258
|
+
f << table.headers
|
259
|
+
table.each { |row| f << row }
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
198
263
|
# Create project folder
|
199
264
|
# params\
|
200
265
|
# +dir_name+:: _string_ Name of new project folder
|
201
266
|
#
|
202
|
-
#
|
203
|
-
# Includes weather for UO's example location, a base workflow file, and mapper files to show a baseline and a high-efficiency option.
|
267
|
+
# Includes weather for example location, a base workflow file, and mapper files to show a baseline and a high-efficiency option.
|
204
268
|
def self.create_project_folder(dir_name, empty_folder = false, overwrite_project = false)
|
205
269
|
if overwrite_project == true
|
206
270
|
if Dir.exist?(dir_name)
|
207
271
|
FileUtils.rm_rf(dir_name)
|
208
|
-
puts "Overwriting project directory: #{dir_name}\n"
|
209
272
|
end
|
210
273
|
elsif overwrite_project == false
|
211
274
|
if Dir.exist?(dir_name)
|
212
275
|
abort("\nERROR: there is already a directory here named #{dir_name}... aborting\n---\n\n")
|
213
276
|
end
|
214
277
|
end
|
215
|
-
puts "CREATING NEW URBANopt project directory: #{dir_name}\n"
|
216
278
|
Dir.mkdir dir_name
|
217
279
|
Dir.mkdir File.join(dir_name, 'mappers')
|
218
280
|
Dir.mkdir File.join(dir_name, 'weather')
|
@@ -253,13 +315,13 @@ module URBANopt
|
|
253
315
|
|
254
316
|
# Download mapper files to user's local machine
|
255
317
|
remote_mapper_files.each do |mapper_file|
|
256
|
-
|
318
|
+
mapper_name = File.basename(mapper_file)
|
257
319
|
mapper_download = open(mapper_file, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
258
320
|
IO.copy_stream(mapper_download, File.join(mappers_dir_abs_path, mapper_name))
|
259
321
|
end
|
260
322
|
|
261
323
|
# Download gemfile to user's local machine
|
262
|
-
|
324
|
+
gem_name = File.basename(example_gem_file)
|
263
325
|
example_gem_download = open(example_gem_file, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
264
326
|
IO.copy_stream(example_gem_download, File.join(dir_name, gem_name))
|
265
327
|
|
@@ -274,153 +336,135 @@ module URBANopt
|
|
274
336
|
end
|
275
337
|
|
276
338
|
# Download config file to user's local machine
|
277
|
-
|
339
|
+
config_name = File.basename(config_file)
|
278
340
|
config_download = open(config_file, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
279
341
|
IO.copy_stream(config_download, File.join(dir_name, config_name))
|
280
342
|
|
281
343
|
# Download weather file to user's local machine
|
282
344
|
remote_weather_files.each do |weather_file|
|
283
|
-
|
345
|
+
weather_name = File.basename(weather_file)
|
284
346
|
weather_download = open(weather_file, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
285
347
|
IO.copy_stream(weather_download, File.join(weather_dir_abs_path, weather_name))
|
286
348
|
end
|
287
349
|
|
288
350
|
# Download osm files to user's local machine
|
289
351
|
osm_files.each do |osm_file|
|
290
|
-
|
352
|
+
osm_name = File.basename(osm_file)
|
291
353
|
osm_download = open(osm_file, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
292
354
|
IO.copy_stream(osm_download, File.join(osm_dir_abs_path, osm_name))
|
293
355
|
end
|
294
356
|
|
295
357
|
# Download feature file to user's local machine
|
296
|
-
|
358
|
+
feature_name = File.basename(example_feature_file)
|
297
359
|
example_feature_download = open(example_feature_file, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
298
360
|
IO.copy_stream(example_feature_download, File.join(dir_name, feature_name))
|
299
361
|
end
|
300
362
|
end
|
301
363
|
|
302
364
|
# Perform CLI actions
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
puts "
|
308
|
-
|
309
|
-
|
365
|
+
|
366
|
+
# Create new project folder
|
367
|
+
if @opthash.command == 'create' && @opthash.subopts[:project_folder] && @opthash.subopts[:empty] == false
|
368
|
+
if @opthash.subopts[:overwrite] == true
|
369
|
+
puts "\nOverwriting existing project folder: #{@opthash.subopts[:project_folder]}...\n\n"
|
370
|
+
create_project_folder(@opthash.subopts[:project_folder], empty_folder = false, overwrite_project = true)
|
371
|
+
elsif @opthash.subopts[:overwrite] == false
|
372
|
+
puts "\nCreating a new project folder...\n"
|
373
|
+
create_project_folder(@opthash.subopts[:project_folder], empty_folder = false, overwrite_project = false)
|
310
374
|
end
|
311
375
|
puts "\nAn example FeatureFile is included: 'example_project.json'. You may place your own FeatureFile alongside the example."
|
312
376
|
puts 'Weather data is provided for the example FeatureFile. Additional weather data files may be downloaded from energyplus.net/weather for free'
|
313
377
|
puts "If you use additional weather files, ensure they are added to the 'weather' directory. You will need to configure your mapper file and your osw file to use the desired weather file"
|
314
|
-
puts "
|
315
|
-
elsif @
|
316
|
-
if @
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
create_project_folder(@
|
378
|
+
puts "We recommend using absolute paths for all commands, for cleaner output\n"
|
379
|
+
elsif @opthash.command == 'create' && @opthash.subopts[:project_folder] && @opthash.subopts[:empty] == true
|
380
|
+
if @opthash.subopts[:overwrite] == true
|
381
|
+
puts "\nOverwriting existing project folder: #{@opthash.subopts[:project_folder]} with an empty folder...\n\n"
|
382
|
+
create_project_folder(@opthash.subopts[:project_folder], empty_folder = true, overwrite_project = true)
|
383
|
+
elsif @opthash.subopts[:overwrite] == false
|
384
|
+
puts "\nCreating a new empty project folder...\n"
|
385
|
+
create_project_folder(@opthash.subopts[:project_folder], empty_folder = true, overwrite_project = false)
|
322
386
|
end
|
323
|
-
puts
|
387
|
+
puts "\nAdd your FeatureFile in the Project directory you just created."
|
324
388
|
puts 'Add your weather data files in the Weather folder. They may be downloaded from energyplus.net/weather for free'
|
325
389
|
puts 'Add your OpenStudio models for Features in your Feature file, if any in the osm_building folder'
|
326
|
-
puts "
|
390
|
+
puts "We recommend using absolute paths for all commands, for cleaner output\n"
|
327
391
|
end
|
328
392
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
if @user_input[:feature_id]
|
335
|
-
puts "\nBuilding sample ScenarioFiles, assigning mapper classes to Feature ID #{@user_input[:feature_id]}..."
|
336
|
-
create_scenario_csv_file(@user_input[:feature_id])
|
393
|
+
# Create ScenarioFile from FeatureFile
|
394
|
+
if @opthash.command == 'create' && @opthash.subopts[:scenario_file]
|
395
|
+
if @opthash.subopts[:single_feature]
|
396
|
+
puts "\nBuilding sample ScenarioFiles, assigning mapper classes to Feature ID #{@opthash.subopts[:single_feature]}"
|
397
|
+
create_scenario_csv_file(@opthash.subopts[:single_feature])
|
337
398
|
puts "\nDone\n"
|
338
399
|
else
|
339
|
-
puts "\nBuilding sample ScenarioFiles, assigning mapper classes to each feature from #{@feature_name}
|
400
|
+
puts "\nBuilding sample ScenarioFiles, assigning mapper classes to each feature from #{@feature_name}"
|
340
401
|
# Skip Feature ID argument if not present
|
341
402
|
create_scenario_csv_file('SKIP')
|
342
403
|
puts "\nDone\n"
|
343
404
|
end
|
344
405
|
end
|
345
406
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
407
|
+
# Create REopt ScenarioFile from existing
|
408
|
+
if @opthash.command == 'create' && @opthash.subopts[:reopt_scenario_file]
|
409
|
+
puts "\nCreating ScenarioFile with REopt functionality, extending from #{@opthash.subopts[:reopt_scenario_file]}..."
|
410
|
+
create_reopt_scenario_file(@opthash.subopts[:reopt_scenario_file])
|
411
|
+
puts "\nDone"
|
412
|
+
end
|
413
|
+
|
414
|
+
# Run simulations
|
415
|
+
if @opthash.command == 'run' && @opthash.subopts[:scenario] && @opthash.subopts[:feature]
|
416
|
+
if @opthash.subopts[:scenario].to_s.include? '-'
|
417
|
+
@scenario_folder = @scenario_file_name.split(/\W+/)[0].capitalize.to_s
|
355
418
|
@feature_id = (@feature_name.split(/\W+/)[1]).to_s
|
356
419
|
else
|
357
420
|
@scenario_folder = @scenario_file_name.split('.')[0].capitalize.to_s
|
358
421
|
end
|
359
|
-
puts "\nSimulating features of '#{@feature_name}' as directed by '#{@
|
422
|
+
puts "\nSimulating features of '#{@feature_name}' as directed by '#{@scenario_file_name}'...\n\n"
|
360
423
|
scenario_runner = URBANopt::Scenario::ScenarioRunnerOSW.new
|
361
424
|
scenario_runner.run(run_func)
|
362
425
|
puts "\nDone\n"
|
363
426
|
end
|
364
427
|
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
if @user_input[:feature].nil?
|
370
|
-
abort("\nYou must provide '-f' flag and a valid path to a FeatureFile!\n---\n\n")
|
371
|
-
end
|
372
|
-
if @user_input[:type].nil?
|
373
|
-
abort("\nYou must provide '-t' flag and a valid Gather type!\n" \
|
374
|
-
"Valid types include: 'default', 'reopt-scenario', 'reopt-feature', or 'opendss'\n---\n\n")
|
428
|
+
# Post-process the scenario
|
429
|
+
if @opthash.command == 'process'
|
430
|
+
if @opthash.subopts[:default] == false && @opthash.subopts[:opendss] == false && @opthash.subopts[:reopt_scenario] == false && @opthash.subopts[:reopt_feature] == false
|
431
|
+
abort("\nERROR: No valid process type entered. Must enter a valid process type\n")
|
375
432
|
end
|
376
433
|
@scenario_folder = @scenario_file_name.split('.')[0].capitalize.to_s
|
377
|
-
|
378
434
|
default_post_processor = URBANopt::Scenario::ScenarioDefaultPostProcessor.new(run_func)
|
379
435
|
scenario_report = default_post_processor.run
|
380
436
|
scenario_report.save
|
381
|
-
|
382
|
-
|
383
|
-
scenario_report.feature_reports.each(&:save_feature_report)
|
384
|
-
|
385
|
-
if @user_input[:type].to_s.casecmp('default').zero?
|
437
|
+
if @opthash.subopts[:default] == true
|
438
|
+
puts 'Post-processing URBANopt results'
|
386
439
|
puts "\nDone\n"
|
387
|
-
elsif @
|
440
|
+
elsif @opthash.subopts[:opendss] == true
|
388
441
|
puts "\nPost-processing OpenDSS results\n"
|
389
|
-
opendss_folder = File.join(@root_dir, 'run', @
|
442
|
+
opendss_folder = File.join(@root_dir, 'run', @scenario_file_name.split('.')[0], 'opendss')
|
390
443
|
if File.directory?(opendss_folder)
|
391
|
-
|
444
|
+
opendss_folder_name = File.basename(opendss_folder)
|
392
445
|
opendss_post_processor = URBANopt::Scenario::OpenDSSPostProcessor.new(scenario_report, opendss_results_dir_name = opendss_folder_name)
|
393
446
|
opendss_post_processor.run
|
394
447
|
puts "\nDone\n"
|
395
448
|
else
|
396
449
|
abort("\nNo OpenDSS results available in folder '#{opendss_folder}'\n")
|
397
450
|
end
|
398
|
-
elsif @
|
451
|
+
elsif @opthash.subopts.to_s.include?('reopt')
|
399
452
|
scenario_base = default_post_processor.scenario_base
|
400
453
|
reopt_post_processor = URBANopt::REopt::REoptPostProcessor.new(scenario_report, scenario_base.scenario_reopt_assumptions_file, scenario_base.reopt_feature_assumptions, DEVELOPER_NREL_KEY)
|
401
|
-
|
402
|
-
|
403
|
-
if @user_input[:type].to_s.casecmp('reopt-scenario').zero?
|
404
|
-
puts "\nOptimizing renewable energy for the scenario\n"
|
454
|
+
if @opthash.subopts[:reopt_scenario] == true
|
455
|
+
puts "\nPost-processing entire scenario with REopt\n"
|
405
456
|
scenario_report_scenario = reopt_post_processor.run_scenario_report(scenario_report: scenario_report, save_name: 'scenario_optimization')
|
406
457
|
puts "\nDone\n"
|
407
|
-
|
408
|
-
|
409
|
-
puts "\nOptimizing renewable energy for each feature\n"
|
458
|
+
elsif @opthash.subopts[:reopt_feature] == true
|
459
|
+
puts "\nPost-processing each building individually with REopt\n"
|
410
460
|
scenario_report_features = reopt_post_processor.run_scenario_report_features(scenario_report: scenario_report, save_names_feature_reports: ['feature_optimization'] * scenario_report.feature_reports.length, save_name_scenario_report: 'feature_optimization')
|
411
461
|
puts "\nDone\n"
|
412
|
-
else
|
413
|
-
abort("\nError: did not use type 'reopt-scenario', 'reopt-feature'. Aborting...\n---\n\n")
|
414
462
|
end
|
415
|
-
else
|
416
|
-
abort("\nError: did not use type 'default', 'reopt-scenario', 'reopt-feature', or 'opendss'. Aborting...\n---\n\n")
|
417
463
|
end
|
418
464
|
end
|
419
465
|
|
420
|
-
|
421
|
-
|
422
|
-
abort("\nYou must provide '-s' flag and a valid path to a ScenarioFile!\n---\n\n")
|
423
|
-
end
|
466
|
+
# Delete simulations from a scenario
|
467
|
+
if @opthash.command == 'delete'
|
424
468
|
scenario_name = @scenario_file_name.split('.')[0]
|
425
469
|
scenario_path = File.absolute_path(@root_dir)
|
426
470
|
scenario_results_dir = File.join(scenario_path, 'run', scenario_name)
|
@@ -428,9 +472,5 @@ module URBANopt
|
|
428
472
|
FileUtils.rm_rf(scenario_results_dir)
|
429
473
|
puts "\nDone\n"
|
430
474
|
end
|
431
|
-
|
432
|
-
if @user_input[:version_request]
|
433
|
-
puts "\nURBANopt CLI version: #{@user_input[:version_request]}\n---\n\n"
|
434
|
-
end
|
435
475
|
end
|
436
476
|
end
|