urbanopt-cli 0.2.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -31,7 +31,7 @@
31
31
  # *********************************************************************************
32
32
 
33
33
  require 'uo_cli/version'
34
- require 'optparse'
34
+ require 'optimist'
35
35
  require 'urbanopt/geojson'
36
36
  require 'urbanopt/scenario'
37
37
  require 'urbanopt/reopt'
@@ -43,91 +43,139 @@ require_relative '../developer_nrel_key'
43
43
 
44
44
  module URBANopt
45
45
  module CLI
46
- # Set up user interface
47
- @user_input = {}
48
- the_parser = OptionParser.new do |opts|
49
- opts.banner = "Usage: uo [-peomrgdsfitv]\n" \
50
- "\n" \
51
- "URBANopt CLI\n" \
52
- "First create a project folder with -p, then run additional commands as desired\n" \
53
- "Additional config options can be set with the 'runner.conf' file inside your new project folder"
54
- opts.separator ''
55
-
56
- opts.on('-p', '--project_folder <DIR>', String, "Create project directory named <DIR> in your current folder\n" \
57
- ' You must be inside the project directory you just created for all following commands to work') do |folder|
58
- @user_input[:project_folder] = folder
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
- opts.on('-e', '--empty_project_folder', String, "Use with -p argument to create an empty project folder\n" \
62
- " Example: uo -e -p <DIR>\n" \
63
- " Then add your own Feature file in the project directory you created,\n" \
64
- " add Weather files in the weather folder and add OpenStudio models of Features \n" \
65
- " in the Feature File, if any in the osm_building folder \n" \
66
- ' You must be inside the project directory you just created for all following commands to work') do
67
- @user_input[:empty_project_folder] = 'Create empty project folder' # This text does not get displayed to the user
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
- opts.on('-o', '--overwrite_project_folder', String, "Use with -p argument to overwrite existing project folder and replace with new project folder.\n" \
71
- " Or, use with -e and -p argument to overwrite existing project folder and replace with new empty project folder.\n" \
72
- " Usage: uo -o -p <DIR>\n" \
73
- " or, uo -o -e -p <DIR>\n" \
74
- ' Where, <DIR> is the existing project folder') do
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
- opts.on('-m', '--make_scenario', String, "Create ScenarioCSV files for each MapperFile using the Feature file path. Must specify -f argument\n" \
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
- opts.on('-r', '--run', String, "Run simulations. Must specify -s & -f arguments\n" \
86
- ' Example: uo -r -s baseline_scenario.csv -f example_project.json') do
87
- @user_input[:run_scenario] = 'Run simulations' # This text does not get displayed to the user
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
- opts.on('-g', '--gather', String, "group individual feature results to scenario-level results. Must specify -t, -s, & -f arguments\n" \
91
- ' Example: uo -g -t default -s baseline_scenario.csv -f example_project.json') do
92
- @user_input[:gather] = 'Aggregate all features to a whole Scenario' # This text does not get displayed to the user
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
- opts.on('-d', '--delete_scenario', String, "Delete results from scenario. Must specify -s argument\n" \
96
- ' Example: uo -d -s baseline_scenario.csv') do
97
- @user_input[:delete_scenario] = 'Delete scenario results that were created from <SFP>' # This text does not get displayed to the user
98
- end
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
- opts.on('-s', '--scenario_file <SFP>', String, 'Specify <SFP> (ScenarioCSV file path). Used as input for other commands') do |scenario|
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
- opts.on('-f', '--feature_file <FFP>', String, 'Specify <FFP> (Feature file path). Used as input for other commands') do |feature|
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
- opts.on('-i', '--feature_id <FID>', Integer, 'Specify <FID> (Feature ID). Used as input for other commands') do |feature_id|
111
- @user_input[:feature_id] = feature_id
112
- end
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
- opts.on('-t', '--type <TYPE>', String, "Specify <TYPE> of post-processor to run:\n" \
115
- " default\n" \
116
- " reopt-scenario\n" \
117
- " reopt-feature\n" \
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
- opts.on('-v', '--version', 'Show CLI version and exit') do
123
- @user_input[:version_request] = VERSION
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
- begin
128
- the_parser.parse!
129
- rescue OptionParser::InvalidOption => e
130
- puts e
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\
@@ -142,10 +190,6 @@ module URBANopt
142
190
  mapper_files_dir = File.join(@root_dir, 'mappers')
143
191
  reopt_files_dir = File.join(@root_dir, 'reopt/')
144
192
  num_header_rows = 1
145
- # FIXME: This can be cleaned up in Ruby 2.5 with Dir.children(<"foldername">)
146
- # TODO: Better way of grabbing assumptions file than the first file in the folder
147
- reopt_files_dir_contents_list = Dir["#{reopt_files_dir}/*"]
148
- reopt_assumptions_filename = File.basename(reopt_files_dir_contents_list[0])
149
193
 
150
194
  if @feature_id
151
195
  feature_run_dir = File.join(run_dir, @feature_id)
@@ -154,7 +198,14 @@ module URBANopt
154
198
  end
155
199
 
156
200
  feature_file = URBANopt::GeoJSON::GeoFile.from_file(featurefile)
157
- 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)
201
+ if @opthash.subopts[:reopt] == true || @opthash.subopts[:reopt_scenario] == true || @opthash.subopts[:reopt_feature] == true
202
+ # TODO: Better way of grabbing assumptions file than the first file in the folder
203
+ reopt_files_dir_contents_list = Dir.children(reopt_files_dir.to_s)
204
+ reopt_assumptions_filename = File.basename(reopt_files_dir_contents_list[0])
205
+ 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)
206
+ else
207
+ scenario_output = URBANopt::Scenario::ScenarioCSV.new(name, @root_dir, run_dir, feature_file, mapper_files_dir, csv_file, num_header_rows)
208
+ end
158
209
  scenario_output
159
210
  end
160
211
 
@@ -162,7 +213,7 @@ module URBANopt
162
213
  # params\
163
214
  # +feature_file_path+:: _string_ Path to a FeatureFile
164
215
  def self.create_scenario_csv_file(feature_id)
165
- feature_file_json = JSON.parse(File.read(File.absolute_path(@user_input[:feature])), symbolize_names: true)
216
+ feature_file_json = JSON.parse(File.read(File.absolute_path(@opthash.subopts[:scenario_file])), symbolize_names: true)
166
217
  Dir["#{@feature_path}/mappers/*.rb"].each do |mapper_file|
167
218
  mapper_name = File.basename(mapper_file, File.extname(mapper_file))
168
219
  scenario_file_name = if feature_id == 'SKIP'
@@ -171,15 +222,15 @@ module URBANopt
171
222
  "#{mapper_name.downcase}_scenario-#{feature_id}.csv"
172
223
  end
173
224
  CSV.open(File.join(@feature_path, scenario_file_name), 'wb', write_headers: true,
174
- headers: ['Feature Id', 'Feature Name', 'Mapper Class', 'REopt Assumptions']) do |csv|
225
+ headers: ['Feature Id', 'Feature Name', 'Mapper Class']) do |csv|
175
226
  feature_file_json[:features].each do |feature|
176
227
  if feature_id == 'SKIP'
177
228
  # ensure that feature is a building
178
229
  if feature[:properties][:type] == 'Building'
179
- csv << [feature[:properties][:id], feature[:properties][:name], "URBANopt::Scenario::#{mapper_name}Mapper", 'base_assumptions.json']
180
- end
181
- elsif feature_id == feature[:properties][:id].to_i
182
- csv << [feature[:properties][:id], feature[:properties][:name], "URBANopt::Scenario::#{mapper_name}Mapper", 'base_assumptions.json']
230
+ csv << [feature[:properties][:id], feature[:properties][:name], "URBANopt::Scenario::#{mapper_name}Mapper"]
231
+ end
232
+ elsif feature_id == feature[:properties][:id]
233
+ csv << [feature[:properties][:id], feature[:properties][:name], "URBANopt::Scenario::#{mapper_name}Mapper"]
183
234
  elsif
184
235
  # If Feature ID specified does not exist in the Feature File raise error
185
236
  unless feature_file_json[:features].any? { |hash| hash[:properties][:id].include?(feature_id.to_s) }
@@ -191,24 +242,38 @@ module URBANopt
191
242
  end
192
243
  end
193
244
 
245
+ # Write new ScenarioFile with REopt column
246
+ # params \
247
+ # +existing_scenario_file+:: _string_ - Name of existing ScenarioFile
248
+ def self.create_reopt_scenario_file(existing_scenario_file)
249
+ existing_path, existing_name = File.split(File.absolute_path(existing_scenario_file))
250
+ table = CSV.read(existing_scenario_file, headers: true, col_sep: ',')
251
+ # Add another column, row by row:
252
+ table.each do |row|
253
+ row['REopt Assumptions'] = 'multiPV_assumptions.json'
254
+ end
255
+ # write new file
256
+ CSV.open(File.join(existing_path, 'REopt_scenario.csv'), 'w') do |f|
257
+ f << table.headers
258
+ table.each { |row| f << row }
259
+ end
260
+ end
261
+
194
262
  # Create project folder
195
263
  # params\
196
264
  # +dir_name+:: _string_ Name of new project folder
197
265
  #
198
- # Folder gets created in the current working directory
199
- # Includes weather for UO's example location, a base workflow file, and mapper files to show a baseline and a high-efficiency option.
266
+ # Includes weather for example location, a base workflow file, and mapper files to show a baseline and a high-efficiency option.
200
267
  def self.create_project_folder(dir_name, empty_folder = false, overwrite_project = false)
201
268
  if overwrite_project == true
202
269
  if Dir.exist?(dir_name)
203
270
  FileUtils.rm_rf(dir_name)
204
- puts "Overwriting project directory: #{dir_name}\n"
205
271
  end
206
272
  elsif overwrite_project == false
207
273
  if Dir.exist?(dir_name)
208
274
  abort("\nERROR: there is already a directory here named #{dir_name}... aborting\n---\n\n")
209
275
  end
210
276
  end
211
- puts "CREATING NEW URBANopt project directory: #{dir_name}\n"
212
277
  Dir.mkdir dir_name
213
278
  Dir.mkdir File.join(dir_name, 'mappers')
214
279
  Dir.mkdir File.join(dir_name, 'weather')
@@ -296,93 +361,84 @@ module URBANopt
296
361
  end
297
362
 
298
363
  # Perform CLI actions
299
- if @user_input[:project_folder] && @user_input[:empty_project_folder].nil?
300
- if @user_input[:overwrite_project_folder]
301
- create_project_folder(@user_input[:project_folder], empty_folder = false, overwrite_project = true)
302
- puts "\nOverwriting exiting project folder #{@user_input[:project_folder]}."
303
- puts "Creating a new project folder.\n"
304
- elsif @user_input[:overwrite_project_folder].nil?
305
- create_project_folder(@user_input[:project_folder], empty_folder = false, overwrite_project = false)
364
+
365
+ # Create new project folder
366
+ if @opthash.command == 'create' && @opthash.subopts[:project_folder] && @opthash.subopts[:empty] == false
367
+ if @opthash.subopts[:overwrite] == true
368
+ puts "\nOverwriting existing project folder: #{@opthash.subopts[:project_folder]}...\n\n"
369
+ create_project_folder(@opthash.subopts[:project_folder], empty_folder = false, overwrite_project = true)
370
+ elsif @opthash.subopts[:overwrite] == false
371
+ puts "\nCreating a new project folder...\n"
372
+ create_project_folder(@opthash.subopts[:project_folder], empty_folder = false, overwrite_project = false)
306
373
  end
307
374
  puts "\nAn example FeatureFile is included: 'example_project.json'. You may place your own FeatureFile alongside the example."
308
375
  puts 'Weather data is provided for the example FeatureFile. Additional weather data files may be downloaded from energyplus.net/weather for free'
309
376
  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"
310
- puts "Next, move inside your new folder ('cd <FolderYouJustCreated>') and create ScenarioFiles using this CLI call: 'uo -m -f <FFP>'\n"
311
- elsif @user_input[:project_folder] && @user_input[:empty_project_folder]
312
- if @user_input[:overwrite_project_folder]
313
- create_project_folder(@user_input[:project_folder], empty_folder = true, overwrite_project = true)
314
- puts "\nOverwriting exiting project folder #{@user_input[:project_folder]}."
315
- puts "Creating a new project folder.\n"
316
- elsif @user_input[:overwrite_project].nil?
317
- create_project_folder(@user_input[:project_folder], empty_folder = true, overwrite_project = false)
377
+ puts "We recommend using absolute paths for all commands, for cleaner output\n"
378
+ elsif @opthash.command == 'create' && @opthash.subopts[:project_folder] && @opthash.subopts[:empty] == true
379
+ if @opthash.subopts[:overwrite] == true
380
+ puts "\nOverwriting existing project folder: #{@opthash.subopts[:project_folder]} with an empty folder...\n\n"
381
+ create_project_folder(@opthash.subopts[:project_folder], empty_folder = true, overwrite_project = true)
382
+ elsif @opthash.subopts[:overwrite] == false
383
+ puts "\nCreating a new empty project folder...\n"
384
+ create_project_folder(@opthash.subopts[:project_folder], empty_folder = true, overwrite_project = false)
318
385
  end
319
- puts 'Add your FeatureFile in the Project directory you just created.'
386
+ puts "\nAdd your FeatureFile in the Project directory you just created."
320
387
  puts 'Add your weather data files in the Weather folder. They may be downloaded from energyplus.net/weather for free'
321
388
  puts 'Add your OpenStudio models for Features in your Feature file, if any in the osm_building folder'
322
- puts "Next, move inside your new folder ('cd <FolderYouJustCreated>') and create ScenarioFiles using this CLI call: 'uo -m -f <FFP>'\n"
389
+ puts "We recommend using absolute paths for all commands, for cleaner output\n"
323
390
  end
324
391
 
325
- if @user_input[:make_scenario_from]
326
- if @user_input[:feature].nil?
327
- abort("\nYou must provide the '-f' flag and a valid path to a FeatureFile!\n---\n\n")
328
- end
329
-
330
- if @user_input[:feature_id]
331
- puts "\nBuilding sample ScenarioFiles, assigning mapper classes to Feature ID #{@user_input[:feature_id]}..."
332
- create_scenario_csv_file(@user_input[:feature_id])
392
+ # Create ScenarioFile from FeatureFile
393
+ if @opthash.command == 'create' && @opthash.subopts[:scenario_file]
394
+ if @opthash.subopts[:single_feature]
395
+ puts "\nBuilding sample ScenarioFiles, assigning mapper classes to Feature ID #{@opthash.subopts[:single_feature]}"
396
+ create_scenario_csv_file(@opthash.subopts[:single_feature])
333
397
  puts "\nDone\n"
334
398
  else
335
- puts "\nBuilding sample ScenarioFiles, assigning mapper classes to each feature from #{@feature_name}..."
399
+ puts "\nBuilding sample ScenarioFiles, assigning mapper classes to each feature from #{@feature_name}"
336
400
  # Skip Feature ID argument if not present
337
401
  create_scenario_csv_file('SKIP')
338
402
  puts "\nDone\n"
339
403
  end
340
404
  end
341
405
 
342
- if @user_input[:run_scenario]
343
- if @user_input[:scenario].nil?
344
- abort("\nYou must provide '-s' flag and a valid path to a ScenarioFile!\n---\n\n")
345
- end
346
- if @user_input[:feature].nil?
347
- abort("\nYou must provide '-f' flag and a valid path to a FeatureFile!\n---\n\n")
348
- end
349
- if @user_input[:scenario].to_s.include? '-'
406
+ # Create REopt ScenarioFile from existing
407
+ if @opthash.command == 'create' && @opthash.subopts[:reopt_scenario_file]
408
+ puts "\nCreating ScenarioFile with REopt functionality, extending from #{@opthash.subopts[:reopt_scenario_file]}..."
409
+ create_reopt_scenario_file(@opthash.subopts[:reopt_scenario_file])
410
+ puts "\nDone"
411
+ end
412
+
413
+ # Run simulations
414
+ if @opthash.command == 'run' && @opthash.subopts[:scenario] && @opthash.subopts[:feature]
415
+ if @opthash.subopts[:scenario].to_s.include? '-'
350
416
  @scenario_folder = @scenario_file_name.split(/\W+/)[0].capitalize.to_s
351
417
  @feature_id = (@feature_name.split(/\W+/)[1]).to_s
352
418
  else
353
419
  @scenario_folder = @scenario_file_name.split('.')[0].capitalize.to_s
354
420
  end
355
- puts "\nSimulating features of '#{@feature_name}' as directed by '#{@user_input[:scenario]}'...\n\n"
421
+ puts "\nSimulating features of '#{@feature_name}' as directed by '#{@scenario_file_name}'...\n\n"
356
422
  scenario_runner = URBANopt::Scenario::ScenarioRunnerOSW.new
357
423
  scenario_runner.run(run_func)
358
424
  puts "\nDone\n"
359
425
  end
360
426
 
361
- if @user_input[:gather]
362
- if @user_input[:scenario].nil?
363
- abort("\nYou must provide '-s' flag and a valid path to a ScenarioFile!\n---\n\n")
364
- end
365
- if @user_input[:feature].nil?
366
- abort("\nYou must provide '-f' flag and a valid path to a FeatureFile!\n---\n\n")
367
- end
368
- if @user_input[:type].nil?
369
- abort("\nYou must provide '-t' flag and a valid Gather type!\n" \
370
- "Valid types include: 'default', 'reopt-scenario', 'reopt-feature', or 'opendss'\n---\n\n")
427
+ # Post-process the scenario
428
+ if @opthash.command == 'process'
429
+ if @opthash.subopts[:default] == false && @opthash.subopts[:opendss] == false && @opthash.subopts[:reopt_scenario] == false && @opthash.subopts[:reopt_feature] == false
430
+ abort("\nERROR: No valid process type entered. Must enter a valid process type\n")
371
431
  end
372
432
  @scenario_folder = @scenario_file_name.split('.')[0].capitalize.to_s
373
-
374
433
  default_post_processor = URBANopt::Scenario::ScenarioDefaultPostProcessor.new(run_func)
375
434
  scenario_report = default_post_processor.run
376
435
  scenario_report.save
377
- # FIXME: Remove this feature_reports block once urbanopt/urbanopt-scenario-gem#104 works as expected.
378
- # save feature reports
379
- scenario_report.feature_reports.each(&:save_feature_report)
380
-
381
- if @user_input[:type].to_s.casecmp('default').zero?
436
+ if @opthash.subopts[:default] == true
437
+ puts 'Post-processing URBANopt results'
382
438
  puts "\nDone\n"
383
- elsif @user_input[:type].to_s.casecmp('opendss').zero?
439
+ elsif @opthash.subopts[:opendss] == true
384
440
  puts "\nPost-processing OpenDSS results\n"
385
- opendss_folder = File.join(@root_dir, 'run', @scenario_name.split('.')[0], 'opendss')
441
+ opendss_folder = File.join(@root_dir, 'run', @scenario_file_name.split('.')[0], 'opendss')
386
442
  if File.directory?(opendss_folder)
387
443
  opendss_folder_name = File.basename(opendss_folder)
388
444
  opendss_post_processor = URBANopt::Scenario::OpenDSSPostProcessor.new(scenario_report, opendss_results_dir_name = opendss_folder_name)
@@ -391,32 +447,23 @@ module URBANopt
391
447
  else
392
448
  abort("\nNo OpenDSS results available in folder '#{opendss_folder}'\n")
393
449
  end
394
- elsif @user_input[:type].to_s.downcase.include?('reopt')
450
+ elsif @opthash.subopts.to_s.include?('reopt')
395
451
  scenario_base = default_post_processor.scenario_base
396
452
  reopt_post_processor = URBANopt::REopt::REoptPostProcessor.new(scenario_report, scenario_base.scenario_reopt_assumptions_file, scenario_base.reopt_feature_assumptions, DEVELOPER_NREL_KEY)
397
-
398
- # Optimize REopt outputs for the whole Scenario
399
- if @user_input[:type].to_s.casecmp('reopt-scenario').zero?
400
- puts "\nOptimizing renewable energy for the scenario\n"
453
+ if @opthash.subopts[:reopt_scenario] == true
454
+ puts "\nPost-processing entire scenario with REopt\n"
401
455
  scenario_report_scenario = reopt_post_processor.run_scenario_report(scenario_report: scenario_report, save_name: 'scenario_optimization')
402
456
  puts "\nDone\n"
403
- # Optimize REopt outputs for each feature individually
404
- elsif @user_input[:type].to_s.casecmp('reopt-feature').zero?
405
- puts "\nOptimizing renewable energy for each feature\n"
457
+ elsif @opthash.subopts[:reopt_feature] == true
458
+ puts "\nPost-processing each building individually with REopt\n"
406
459
  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')
407
460
  puts "\nDone\n"
408
- else
409
- abort("\nError: did not use type 'reopt-scenario', 'reopt-feature'. Aborting...\n---\n\n")
410
461
  end
411
- else
412
- abort("\nError: did not use type 'default', 'reopt-scenario', 'reopt-feature', or 'opendss'. Aborting...\n---\n\n")
413
462
  end
414
463
  end
415
464
 
416
- if @user_input[:delete_scenario]
417
- if @user_input[:scenario].nil?
418
- abort("\nYou must provide '-s' flag and a valid path to a ScenarioFile!\n---\n\n")
419
- end
465
+ # Delete simulations from a scenario
466
+ if @opthash.command == 'delete'
420
467
  scenario_name = @scenario_file_name.split('.')[0]
421
468
  scenario_path = File.absolute_path(@root_dir)
422
469
  scenario_results_dir = File.join(scenario_path, 'run', scenario_name)
@@ -424,9 +471,5 @@ module URBANopt
424
471
  FileUtils.rm_rf(scenario_results_dir)
425
472
  puts "\nDone\n"
426
473
  end
427
-
428
- if @user_input[:version_request]
429
- puts "\nURBANopt CLI version: #{@user_input[:version_request]}\n---\n\n"
430
- end
431
474
  end
432
475
  end