urbanopt-cli 0.2.0.pre6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/uo_cli.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/ ruby
2
2
 
3
- #*********************************************************************************
3
+ # *********************************************************************************
4
4
  # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
5
5
  # contributors. All rights reserved.
6
6
  #
@@ -28,359 +28,409 @@
28
28
  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29
29
  # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30
30
  # OF THE POSSIBILITY OF SUCH DAMAGE.
31
- #*********************************************************************************
32
-
33
- require "uo_cli/version"
34
- require "optparse"
35
- require "urbanopt/geojson"
36
- require "urbanopt/scenario"
37
- require "csv"
38
- require "json"
39
- require "openssl"
40
-
31
+ # *********************************************************************************
32
+
33
+ require 'uo_cli/version'
34
+ require 'optparse'
35
+ require 'urbanopt/geojson'
36
+ require 'urbanopt/scenario'
37
+ require 'urbanopt/reopt'
38
+ require 'urbanopt/reopt_scenario'
39
+ require 'csv'
40
+ require 'json'
41
+ require 'openssl'
42
+ require_relative '../developer_nrel_key'
41
43
 
42
44
  module URBANopt
43
45
  module CLI
44
-
45
46
  # Set up user interface
46
47
  @user_input = {}
47
48
  the_parser = OptionParser.new do |opts|
48
- opts.banner = "Usage: uo [-peomradsfiv]\n" +
49
- "\n" +
50
- "URBANopt CLI\n" +
51
- "First create a project folder with -p, then run additional commands as desired\n" +
52
- "Additional config options can be set with the 'runner.conf' file inside your new project folder"
53
- opts.separator ""
54
-
55
- opts.on("-p", "--project_folder <DIR>",String, "Create project directory named <DIR> in your current folder\n" +
56
- " You must be inside the project directory you just created for all following commands to work") do |folder|
57
- @user_input[:project_folder] = folder
58
- end
59
-
60
- opts.on("-e", "--empty_project_folder", String, "Use with -p argument to create an empty project folder\n" +
61
- " Example: uo -e -p <DIR>\n" +
62
- " Then add your own Feature file in the project directory you created,\n" +
63
- " add Weather files in the weather folder and add OpenStudio models of Features \n" +
64
- " in the Feature File, if any in the osm_building folder \n" +
65
- " You must be inside the project directory you just created for all following commands to work") do
66
- @user_input[:empty_project_folder] = "Create empty project folder" # This text does not get displayed to the user
67
- end
68
-
69
- opts.on("-o", "--overwrite_project_folder", String, "Use with -p argument to overwrite existing project folder and replace with new project folder.\n" +
70
- " Or, use with -e and -p argument to overwrite existing project folder and replace with new empty project folder.\n" +
71
- " Usage: uo -o -p <DIR>\n" +
72
- " or, uo -o -e -p <DIR>\n" +
73
- " Where, <DIR> is the existing project folder") do
74
- @user_input[:overwrite_project_folder] = "Overwriting existing project folder" # This text does not get displayed to the user
75
- end
76
-
77
- opts.on("-m", "--make_scenario", String, "Create ScenarioCSV files for each MapperFile using the Feature file path. Must specify -f argument\n" +
78
- " Example: uo -m -f example_project.json\n" +
79
- " Or, Create Scenario CSV for each MapperFile for a single Feature from Feature File. Must specify -f and -i argument\n" +
80
- " Example: uo -m -f example_project.json -i 1") do
81
- @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
82
- end
83
-
84
- opts.on("-r", "--run", String, "Run simulations. Must specify -s & -f arguments\n" +
85
- " Example: uo -r -s baseline_scenario.csv -f example_project.json") do
86
- @user_input[:run_scenario] = "Run simulations" # This text does not get displayed to the user
87
- end
88
-
89
- opts.on("-a", "--aggregate", String, "Aggregate individual feature results to scenario-level results. Must specify -s & -f arguments\n" +
90
- " Example: uo -a -s baseline_scenario.csv -f example_project.json") do
91
- @user_input[:aggregate] = "Aggregate all features to a whole Scenario" # This text does not get displayed to the user
92
- end
93
-
94
- opts.on("-d", "--delete_scenario", String, "Delete results from scenario. Must specify -s argument\n" +
95
- " Example: uo -d -s baseline_scenario.csv") do
96
- @user_input[:delete_scenario] = "Delete scenario results that were created from <SFP>" # This text does not get displayed to the user
97
- end
98
-
99
- opts.on("-s", "--scenario_file <SFP>", String, "Specify <SFP> (ScenarioCSV file path). Used as input for other commands") do |scenario|
100
- @user_input[:scenario] = scenario
101
- end
102
-
103
- opts.on("-f", "--feature_file <FFP>", String, "Specify <FFP> (Feature file path). Used as input for other commands") do |feature|
104
- @user_input[:feature] = feature
105
- end
106
-
107
- opts.on("-i", "--feature_id <FID>", Integer, "Specify <FID> (Feature ID). Used as input for other commands") do |feature_id|
108
- @user_input[:feature_id] = feature_id
109
- end
110
-
111
- opts.on("-v", "--version", "Show CLI version and exit") do
112
- @user_input[:version_request] = VERSION
113
- end
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
59
+ end
60
+
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
68
+ end
69
+
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
77
+
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
84
+
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
89
+
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
93
+ end
94
+
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
99
+
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
104
+
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
109
+
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
113
+
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
120
+ end
121
+
122
+ opts.on('-v', '--version', 'Show CLI version and exit') do
123
+ @user_input[:version_request] = VERSION
124
+ end
114
125
  end
115
126
 
116
127
  begin
117
- the_parser.parse!
128
+ the_parser.parse!
118
129
  rescue OptionParser::InvalidOption => e
119
130
  puts e
120
131
  end
121
132
 
122
- # Simulate energy usage for each Feature or for single feature as defined by ScenarioCSV\
133
+ # Simulate energy usage as defined by ScenarioCSV\
123
134
  # params\
124
135
  # +scenario+:: _string_ Path to csv file that defines the scenario\
125
136
  # +feature_file_path+:: _string_ Path to Feature File used to describe set of features in the district
126
- #
137
+ #
127
138
  # FIXME: This only works when scenario_file and feature_file are in the project root directory
128
139
  # This works when called with filename (from inside project directory) and with absolute filepaths
129
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?
130
- def self.run_func
131
- root_dir = File.dirname(File.absolute_path(@user_input[:scenario]))
132
- scenario_basename = File.basename(File.absolute_path(@user_input[:scenario]))
133
- name = File.basename(scenario_basename, File.extname(scenario_basename))
134
- run_dir = File.join(root_dir, 'run', name.downcase)
135
-
136
- if @feature_id
137
- feature_run_dir = File.join(run_dir,@feature_id)
138
- # If run folder for feature exists, remove it
139
- if File.exist?(feature_run_dir)
140
- FileUtils.rm_rf(feature_run_dir)
141
- end
142
- end
143
-
144
- csv_file = File.join(root_dir, scenario_basename)
145
- featurefile = File.join(root_dir, @feature_name)
146
- mapper_files_dir = File.join(root_dir, "mappers")
147
- num_header_rows = 1
148
-
149
- feature_file = URBANopt::GeoJSON::GeoFile.from_file(featurefile)
150
- scenario_output = URBANopt::Scenario::ScenarioCSV.new(name, root_dir, run_dir, feature_file, mapper_files_dir, csv_file, num_header_rows)
151
- return scenario_output
141
+ def self.run_func
142
+ name = File.basename(@scenario_file_name, File.extname(@scenario_file_name))
143
+ run_dir = File.join(@root_dir, 'run', name.downcase)
144
+ csv_file = File.join(@root_dir, @scenario_file_name)
145
+ featurefile = File.join(@root_dir, @feature_name)
146
+ mapper_files_dir = File.join(@root_dir, 'mappers')
147
+ reopt_files_dir = File.join(@root_dir, 'reopt/')
148
+ num_header_rows = 1
149
+ # FIXME: This can be cleaned up in Ruby 2.5 with Dir.children(<"foldername">)
150
+ reopt_files_dir_contents_list = Dir["#{reopt_files_dir}/*"]
151
+ reopt_folder_path, reopt_assumptions_filename = File.split(reopt_files_dir_contents_list[0])
152
+
153
+ if @feature_id
154
+ feature_run_dir = File.join(run_dir, @feature_id)
155
+ # If run folder for feature exists, remove it
156
+ FileUtils.rm_rf(feature_run_dir) if File.exist?(feature_run_dir)
157
+ end
158
+
159
+ feature_file = URBANopt::GeoJSON::GeoFile.from_file(featurefile)
160
+ 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)
161
+ scenario_output
152
162
  end
153
163
 
154
164
  # Create a scenario csv file from a FeatureFile
155
165
  # params\
156
166
  # +feature_file_path+:: _string_ Path to a FeatureFile
157
- def self.create_scenario_csv_file(feature_file_path, feature_id)
158
- feature_file_json = JSON.parse(File.read(feature_file_path), :symbolize_names => true)
159
- Dir["#{@feature_path}/mappers/*.rb"].each do |mapper_file|
160
- mapper_path, mapper_name = File.split(mapper_file)
161
- mapper_name = mapper_name.split('.')[0]
162
- unless feature_id == 'SKIP'
163
- scenario_file_name = "#{mapper_name.downcase}_scenario-#{feature_id}.csv"
164
- else
165
- scenario_file_name = "#{mapper_name.downcase}_scenario.csv"
166
- end
167
- CSV.open(File.join(@feature_path, scenario_file_name), "wb", :write_headers => true,
168
- :headers => ["Feature Id","Feature Name","Mapper Class"]) do |csv|
169
- feature_file_json[:features].each do |feature|
170
- if feature_id == 'SKIP'
171
- # ensure that feature is a building
172
- if feature[:properties][:type] == "Building"
173
- csv << [feature[:properties][:id], feature[:properties][:name], "URBANopt::Scenario::#{mapper_name}Mapper"]
174
- end
175
- elsif feature_id == feature[:properties][:id].to_i
176
- csv << [feature[:properties][:id], feature[:properties][:name], "URBANopt::Scenario::#{mapper_name}Mapper"]
177
- elsif
178
- # If Feature ID specified does not exist in the Feature File raise error
179
- unless feature_file_json[:features].any? {|hash| hash[:properties][:id].include?(feature_id.to_s)}
180
- abort("\nYou must provide Feature ID from FeatureFile!\n---\n\n")
181
- end
182
- end
167
+ def self.create_scenario_csv_file(feature_id)
168
+ feature_file_json = JSON.parse(File.read(File.absolute_path(@user_input[:feature])), symbolize_names: true)
169
+ Dir["#{@feature_path}/mappers/*.rb"].each do |mapper_file|
170
+ mapper_path, mapper_name = File.split(mapper_file)
171
+ mapper_name = mapper_name.split('.')[0]
172
+ scenario_file_name = if feature_id == 'SKIP'
173
+ "#{mapper_name.downcase}_scenario.csv"
174
+ else
175
+ "#{mapper_name.downcase}_scenario-#{feature_id}.csv"
176
+ end
177
+ CSV.open(File.join(@feature_path, scenario_file_name), 'wb', write_headers: true,
178
+ headers: ['Feature Id', 'Feature Name', 'Mapper Class', 'REopt Assumptions']) do |csv|
179
+ feature_file_json[:features].each do |feature|
180
+ if feature_id == 'SKIP'
181
+ # ensure that feature is a building
182
+ if feature[:properties][:type] == 'Building'
183
+ csv << [feature[:properties][:id], feature[:properties][:name], "URBANopt::Scenario::#{mapper_name}Mapper", 'base_assumptions.json']
183
184
  end
185
+ elsif feature_id == feature[:properties][:id].to_i
186
+ csv << [feature[:properties][:id], feature[:properties][:name], "URBANopt::Scenario::#{mapper_name}Mapper", 'base_assumptions.json']
187
+ elsif
188
+ # If Feature ID specified does not exist in the Feature File raise error
189
+ unless feature_file_json[:features].any? { |hash| hash[:properties][:id].include?(feature_id.to_s) }
190
+ abort("\nYou must provide Feature ID from FeatureFile!\n---\n\n")
191
+ end
184
192
  end
193
+ end
185
194
  end
195
+ end
186
196
  end
187
197
 
188
-
189
198
  # Create project folder
190
199
  # params\
191
200
  # +dir_name+:: _string_ Name of new project folder
192
- #
201
+ #
193
202
  # Folder gets created in the current working directory
194
203
  # Includes weather for UO's example location, a base workflow file, and mapper files to show a baseline and a high-efficiency option.
195
204
  def self.create_project_folder(dir_name, empty_folder = false, overwrite_project = false)
196
- if overwrite_project == true
197
- if Dir.exist?(dir_name)
198
- FileUtils.rm_rf(dir_name)
199
- puts "Overwriting project directory: #{dir_name}"
200
- end
201
- elsif overwrite_project == false
202
- if Dir.exist?(dir_name)
203
- abort("ERROR: there is already a directory here named #{dir_name}... aborting")
204
- end
205
+ if overwrite_project == true
206
+ if Dir.exist?(dir_name)
207
+ FileUtils.rm_rf(dir_name)
208
+ puts "Overwriting project directory: #{dir_name}\n"
209
+ end
210
+ elsif overwrite_project == false
211
+ if Dir.exist?(dir_name)
212
+ abort("\nERROR: there is already a directory here named #{dir_name}... aborting\n---\n\n")
213
+ end
214
+ end
215
+ puts "CREATING NEW URBANopt project directory: #{dir_name}\n"
216
+ Dir.mkdir dir_name
217
+ Dir.mkdir File.join(dir_name, 'mappers')
218
+ Dir.mkdir File.join(dir_name, 'weather')
219
+ Dir.mkdir File.join(dir_name, 'reopt')
220
+ Dir.mkdir File.join(dir_name, 'osm_building')
221
+ mappers_dir_abs_path = File.absolute_path(File.join(dir_name, 'mappers/'))
222
+ weather_dir_abs_path = File.absolute_path(File.join(dir_name, 'weather/'))
223
+ reopt_dir_abs_path = File.absolute_path(File.join(dir_name, 'reopt/'))
224
+ osm_dir_abs_path = File.absolute_path(File.join(dir_name, 'osm_building/'))
225
+
226
+ config_file = 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/runner.conf'
227
+ example_feature_file = 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/example_project.json'
228
+ example_gem_file = 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/Gemfile'
229
+ remote_weather_files = [
230
+ 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/weather/USA_NY_Buffalo-Greater.Buffalo.Intl.AP.725280_TMY3.epw',
231
+ 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/weather/USA_NY_Buffalo-Greater.Buffalo.Intl.AP.725280_TMY3.ddy',
232
+ 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/weather/USA_NY_Buffalo-Greater.Buffalo.Intl.AP.725280_TMY3.stat'
233
+ ]
234
+ osm_files = [
235
+ 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/osm_building/7.osm',
236
+ 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/osm_building/8.osm',
237
+ 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/osm_building/9.osm'
238
+ ]
239
+
240
+ reopt_files = [
241
+ 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/reopt/base_assumptions.json',
242
+ 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/reopt/multiPV_assumptions.json'
243
+ ]
244
+
245
+ # FIXME: When residential hpxml flow is implemented
246
+ # (https://github.com/urbanopt/urbanopt-example-geojson-project/pull/24 gets merged)
247
+ # these files will change
248
+ remote_mapper_files = [
249
+ 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/mappers/base_workflow.osw',
250
+ 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/mappers/Baseline.rb',
251
+ 'https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/mappers/HighEfficiency.rb'
252
+ ]
253
+
254
+ # Download mapper files to user's local machine
255
+ remote_mapper_files.each do |mapper_file|
256
+ mapper_path, mapper_name = File.split(mapper_file)
257
+ mapper_download = open(mapper_file, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
258
+ IO.copy_stream(mapper_download, File.join(mappers_dir_abs_path, mapper_name))
259
+ end
260
+
261
+ # Download gemfile to user's local machine
262
+ gem_path, gem_name = File.split(example_gem_file)
263
+ example_gem_download = open(example_gem_file, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
264
+ IO.copy_stream(example_gem_download, File.join(dir_name, gem_name))
265
+
266
+ # if argument for creating an empty folder is not added
267
+ if empty_folder == false
268
+
269
+ # Download reopt files to user's local machine
270
+ reopt_files.each do |reopt_remote_file|
271
+ reopt_file = File.basename(reopt_remote_file)
272
+ reopt_file_download = open(reopt_remote_file, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
273
+ IO.copy_stream(reopt_file_download, File.join(reopt_dir_abs_path, reopt_file))
205
274
  end
206
- puts "CREATING NEW URBANopt project directory: #{dir_name}"
207
- Dir.mkdir dir_name
208
- Dir.mkdir File.join(dir_name, 'mappers')
209
- Dir.mkdir File.join(dir_name, 'weather')
210
- Dir.mkdir File.join(dir_name, 'osm_building')
211
- mappers_dir_abs_path = File.absolute_path(File.join(dir_name, 'mappers/'))
212
- weather_dir_abs_path = File.absolute_path(File.join(dir_name, 'weather/'))
213
- osm_dir_abs_path = File.absolute_path(File.join(dir_name, 'osm_building/'))
214
-
215
- # FIXME: When residential hpxml flow is implemented
216
- # (https://github.com/urbanopt/urbanopt-example-geojson-project/pull/24 gets merged)
217
- # these files will change
218
-
219
-
220
- remote_mapper_files = [
221
- "https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/mappers/base_workflow.osw",
222
- "https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/mappers/Baseline.rb",
223
- "https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/mappers/HighEfficiency.rb",
224
- ]
225
-
226
- example_gem_file = "https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/Gemfile"
227
-
228
- # Download mapper files to user's local machine
229
- remote_mapper_files.each do |mapper_file|
230
- mapper_path, mapper_name = File.split(mapper_file)
231
- mapper_download = open(mapper_file, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE})
232
- IO.copy_stream(mapper_download, File.join(mappers_dir_abs_path, mapper_name))
233
- end
234
275
 
235
- # Download gemfile to user's local machine
236
- gem_path, gem_name = File.split(example_gem_file)
237
- example_gem_download = open(example_gem_file, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE})
238
- IO.copy_stream(example_gem_download, File.join(dir_name, gem_name))
239
-
240
- #if argument for creating an empty folder is not added
241
- if empty_folder == false
242
-
243
- example_feature_file = "https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/example_project.json"
244
-
245
- remote_weather_files = [
246
- "https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/weather/USA_NY_Buffalo-Greater.Buffalo.Intl.AP.725280_TMY3.epw",
247
- "https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/weather/USA_NY_Buffalo-Greater.Buffalo.Intl.AP.725280_TMY3.ddy",
248
- "https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/weather/USA_NY_Buffalo-Greater.Buffalo.Intl.AP.725280_TMY3.stat",
249
- ]
250
-
251
- osm_files = [
252
- "https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/osm_building/7.osm",
253
- "https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/osm_building/8.osm",
254
- "https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/osm_building/9.osm"
255
- ]
256
-
257
- config_file = "https://raw.githubusercontent.com/urbanopt/urbanopt-cli/master/example_files/runner.conf"
258
- config_path, config_name = File.split(config_file)
259
- config_download = open(config_file, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE})
260
- IO.copy_stream(config_download, File.join(dir_name, config_name))
261
-
262
-
263
- # Download weather file to user's local machine
264
- remote_weather_files.each do |weather_file|
265
- weather_path, weather_name = File.split(weather_file)
266
- weather_download = open(weather_file, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE})
267
- IO.copy_stream(weather_download, File.join(weather_dir_abs_path, weather_name))
268
- end
276
+ # Download config file to user's local machine
277
+ config_path, config_name = File.split(config_file)
278
+ config_download = open(config_file, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
279
+ IO.copy_stream(config_download, File.join(dir_name, config_name))
269
280
 
270
- osm_files.each do |osm_file|
271
- osm_path, osm_name = File.split(osm_file)
272
- osm_download = open(osm_file, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE})
273
- IO.copy_stream(osm_download, File.join(osm_dir_abs_path, osm_name))
274
- end
281
+ # Download weather file to user's local machine
282
+ remote_weather_files.each do |weather_file|
283
+ weather_path, weather_name = File.split(weather_file)
284
+ weather_download = open(weather_file, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
285
+ IO.copy_stream(weather_download, File.join(weather_dir_abs_path, weather_name))
286
+ end
275
287
 
276
- feature_path, feature_name = File.split(example_feature_file)
277
- example_feature_download = open(example_feature_file, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE})
278
- IO.copy_stream(example_feature_download, File.join(dir_name, feature_name))
288
+ # Download osm files to user's local machine
289
+ osm_files.each do |osm_file|
290
+ osm_path, osm_name = File.split(osm_file)
291
+ osm_download = open(osm_file, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
292
+ IO.copy_stream(osm_download, File.join(osm_dir_abs_path, osm_name))
293
+ end
279
294
 
280
- end
295
+ # Download feature file to user's local machine
296
+ feature_path, feature_name = File.split(example_feature_file)
297
+ example_feature_download = open(example_feature_file, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
298
+ IO.copy_stream(example_feature_download, File.join(dir_name, feature_name))
299
+ end
281
300
  end
282
301
 
283
-
284
302
  # Perform CLI actions
285
303
  if @user_input[:project_folder] && @user_input[:empty_project_folder].nil?
286
- if @user_input[:overwrite_project_folder]
287
- create_project_folder(@user_input[:project_folder], empty_folder = false, overwrite_project = true)
288
- puts "\nOverwriting exiting project folder #{@user_input[:project_folder]}."
289
- puts "Creating a new project folder."
290
- elsif @user_input[:overwrite_project_folder].nil?
291
- create_project_folder(@user_input[:project_folder], empty_folder = false, overwrite_project = false)
292
- end
293
- puts "\nAn example FeatureFile is included: 'example_project.json'. You may place your own FeatureFile alongside the example."
294
- puts "Weather data is provided for the example FeatureFile. Additional weather data files may be downloaded from energyplus.net/weather for free"
295
- 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"
296
- puts "Next, move inside your new folder ('cd <FolderYouJustCreated>') and create ScenarioFiles using this CLI call: 'uo -m -f <FFP>'"
304
+ if @user_input[:overwrite_project_folder]
305
+ create_project_folder(@user_input[:project_folder], empty_folder = false, overwrite_project = true)
306
+ puts "\nOverwriting exiting project folder #{@user_input[:project_folder]}."
307
+ puts "Creating a new project folder.\n"
308
+ elsif @user_input[:overwrite_project_folder].nil?
309
+ create_project_folder(@user_input[:project_folder], empty_folder = false, overwrite_project = false)
310
+ end
311
+ puts "\nAn example FeatureFile is included: 'example_project.json'. You may place your own FeatureFile alongside the example."
312
+ puts 'Weather data is provided for the example FeatureFile. Additional weather data files may be downloaded from energyplus.net/weather for free'
313
+ 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 "Next, move inside your new folder ('cd <FolderYouJustCreated>') and create ScenarioFiles using this CLI call: 'uo -m -f <FFP>'\n"
297
315
  elsif @user_input[:project_folder] && @user_input[:empty_project_folder]
298
- if @user_input[:overwrite_project_folder]
299
- create_project_folder(@user_input[:project_folder], empty_folder = true, overwrite_project = true)
300
- puts "\nOverwriting exiting project folder #{@user_input[:project_folder]}."
301
- puts "Creating a new project folder."
302
- elsif @user_input[:overwrite_project].nil?
303
- create_project_folder(@user_input[:project_folder], empty_folder = true, overwrite_project = false)
304
- end
305
- puts "Add your FeatureFile in the Project directory you just created."
306
- puts "Add your weather data files in the Weather folder. They may be downloaded from energyplus.net/weather for free"
307
- puts "Add your OpenStudio models for Features in your Feature file, if any in the osm_building folder"
308
- puts "Next, move inside your new folder ('cd <FolderYouJustCreated>') and create ScenarioFiles using this CLI call: 'uo -m -f <FFP>'"
316
+ if @user_input[:overwrite_project_folder]
317
+ create_project_folder(@user_input[:project_folder], empty_folder = true, overwrite_project = true)
318
+ puts "\nOverwriting exiting project folder #{@user_input[:project_folder]}."
319
+ puts "Creating a new project folder.\n"
320
+ elsif @user_input[:overwrite_project].nil?
321
+ create_project_folder(@user_input[:project_folder], empty_folder = true, overwrite_project = false)
322
+ end
323
+ puts 'Add your FeatureFile in the Project directory you just created.'
324
+ puts 'Add your weather data files in the Weather folder. They may be downloaded from energyplus.net/weather for free'
325
+ puts 'Add your OpenStudio models for Features in your Feature file, if any in the osm_building folder'
326
+ puts "Next, move inside your new folder ('cd <FolderYouJustCreated>') and create ScenarioFiles using this CLI call: 'uo -m -f <FFP>'\n"
309
327
  end
310
328
 
311
329
  if @user_input[:make_scenario_from]
312
- if @user_input[:feature].nil?
313
- abort("\nYou must provide the '-f' flag and a valid path to a FeatureFile!\n---\n\n")
314
- end
315
-
316
- @feature_path, @feature_name = File.split(@user_input[:feature])
317
- if @user_input[:feature_id]
318
- puts "\nBuilding sample ScenarioFiles, assigning mapper classes to Feature ID #{@user_input[:feature_id]}..."
319
- create_scenario_csv_file(@user_input[:feature], @user_input[:feature_id])
320
- puts "Done"
321
- else
322
- puts "\nBuilding sample ScenarioFiles, assigning mapper classes to each feature from #{@feature_name}..."
323
- # Skip Feature ID argument if not present
324
- create_scenario_csv_file(@user_input[:feature], 'SKIP')
325
- puts "Done"
326
- end
330
+ if @user_input[:feature].nil?
331
+ abort("\nYou must provide the '-f' flag and a valid path to a FeatureFile!\n---\n\n")
332
+ end
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])
337
+ puts "\nDone\n"
338
+ else
339
+ puts "\nBuilding sample ScenarioFiles, assigning mapper classes to each feature from #{@feature_name}..."
340
+ # Skip Feature ID argument if not present
341
+ create_scenario_csv_file('SKIP')
342
+ puts "\nDone\n"
343
+ end
327
344
  end
328
345
 
329
-
330
-
331
346
  if @user_input[:run_scenario]
332
- if @user_input[:scenario].nil?
333
- abort("\nYou must provide '-s' flag and a valid path to a ScenarioFile!\n---\n\n")
334
- end
335
- if @user_input[:feature].nil?
336
- abort("\nYou must provide '-f' flag and a valid path to a FeatureFile!\n---\n\n")
337
- end
338
- if @user_input[:scenario].include? "-"
339
- @scenario_folder = "#{@user_input[:scenario].split(/\W+/)[0].capitalize}"
340
- @feature_id = "#{@user_input[:scenario].split(/\W+/)[1]}"
341
- else
342
- @scenario_folder = "#{@user_input[:scenario].split('.')[0].capitalize}"
343
- end
344
- @feature_path, @feature_name = File.split(@user_input[:feature])
345
- puts "\nSimulating features of '#{@feature_name}' as directed by '#{@user_input[:scenario]}'...\n\n"
346
- scenario_runner = URBANopt::Scenario::ScenarioRunnerOSW.new
347
- scenario_runner.run(run_func())
348
- puts "Done"
347
+ if @user_input[:scenario].nil?
348
+ abort("\nYou must provide '-s' flag and a valid path to a ScenarioFile!\n---\n\n")
349
+ end
350
+ if @user_input[:feature].nil?
351
+ abort("\nYou must provide '-f' flag and a valid path to a FeatureFile!\n---\n\n")
352
+ end
353
+ if @user_input[:scenario].to_s.include? '-'
354
+ @scenario_folder = scenario_file_name.split(/\W+/)[0].capitalize.to_s
355
+ @feature_id = (@feature_name.split(/\W+/)[1]).to_s
356
+ else
357
+ @scenario_folder = @scenario_file_name.split('.')[0].capitalize.to_s
358
+ end
359
+ puts "\nSimulating features of '#{@feature_name}' as directed by '#{@user_input[:scenario]}'...\n\n"
360
+ scenario_runner = URBANopt::Scenario::ScenarioRunnerOSW.new
361
+ scenario_runner.run(run_func)
362
+ puts "\nDone\n"
349
363
  end
350
364
 
351
- if @user_input[:aggregate]
352
- if @user_input[:scenario].nil?
353
- abort("\nYou must provide '-s' flag and a valid path to a ScenarioFile!\n---\n\n")
365
+ if @user_input[:gather]
366
+ if @user_input[:scenario].nil?
367
+ abort("\nYou must provide '-s' flag and a valid path to a ScenarioFile!\n---\n\n")
368
+ end
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")
375
+ end
376
+ @scenario_folder = @scenario_file_name.split('.')[0].capitalize.to_s
377
+
378
+ default_post_processor = URBANopt::Scenario::ScenarioDefaultPostProcessor.new(run_func)
379
+ scenario_report = default_post_processor.run
380
+ scenario_report.save
381
+ # FIXME: Remove this feature_reports block once urbanopt/urbanopt-scenario-gem#104 works as expected.
382
+ # save feature reports
383
+ scenario_report.feature_reports.each(&:save_feature_report)
384
+
385
+ if @user_input[:type].to_s.casecmp('default').zero?
386
+ puts "\nDone\n"
387
+ elsif @user_input[:type].to_s.casecmp('opendss').zero?
388
+ puts "\nPost-processing OpenDSS results\n"
389
+ opendss_folder = File.join(@root_dir, 'run', @scenario_name.split('.')[0], 'opendss')
390
+ if File.directory?(opendss_folder)
391
+ opendss_folder_path, opendss_folder_name = File.split(opendss_folder)
392
+ opendss_post_processor = URBANopt::Scenario::OpenDSSPostProcessor.new(scenario_report, opendss_results_dir_name = opendss_folder_name)
393
+ opendss_post_processor.run
394
+ puts "\nDone\n"
395
+ else
396
+ abort("\nNo OpenDSS results available in folder '#{opendss_folder}'\n")
354
397
  end
355
- if @user_input[:feature].nil?
356
- abort("\nYou must provide '-f' flag and a valid path to a FeatureFile!\n---\n\n")
398
+ elsif @user_input[:type].to_s.downcase.include?('reopt')
399
+ scenario_base = default_post_processor.scenario_base
400
+ 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
+ # Optimize REopt outputs for the whole Scenario
403
+ if @user_input[:type].to_s.casecmp('reopt-scenario').zero?
404
+ puts "\nOptimizing renewable energy for the scenario\n"
405
+ scenario_report_scenario = reopt_post_processor.run_scenario_report(scenario_report: scenario_report, save_name: 'scenario_optimization')
406
+ puts "\nDone\n"
407
+ # Optimize REopt outputs for each feature individually
408
+ elsif @user_input[:type].to_s.casecmp('reopt-feature').zero?
409
+ puts "\nOptimizing renewable energy for each feature\n"
410
+ 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
+ puts "\nDone\n"
412
+ else
413
+ abort("\nError: did not use type 'reopt-scenario', 'reopt-feature'. Aborting...\n---\n\n")
357
414
  end
358
- @scenario_folder = "#{@user_input[:scenario].split('.')[0].capitalize}"
359
- @scenario_path, @scenario_name = File.split(@user_input[:scenario])
360
- @feature_path, @feature_name = File.split(@user_input[:feature])
361
- puts "\nAggregating results across all features of #{@feature_name} according to '#{@scenario_name}'...\n"
362
- scenario_result = URBANopt::Scenario::ScenarioDefaultPostProcessor.new(run_func()).run
363
- scenario_result.save
364
- puts "Done"
415
+ else
416
+ abort("\nError: did not use type 'default', 'reopt-scenario', 'reopt-feature', or 'opendss'. Aborting...\n---\n\n")
417
+ end
365
418
  end
366
419
 
367
420
  if @user_input[:delete_scenario]
368
- if @user_input[:scenario].nil?
369
- abort("\nYou must provide '-s' flag and a valid path to a ScenarioFile!\n---\n\n")
370
- end
371
- @scenario_path, @scenario_name = File.split(@user_input[:scenario])
372
- scenario_name = @scenario_name.split('.')[0]
373
- scenario_path = File.absolute_path(@scenario_path)
374
- scenario_results_dir = File.join(scenario_path, 'run', scenario_name)
375
- puts "\nDeleting previous results from '#{@scenario_name}'..."
376
- FileUtils.rm_rf(scenario_results_dir)
377
- puts "Done"
421
+ if @user_input[:scenario].nil?
422
+ abort("\nYou must provide '-s' flag and a valid path to a ScenarioFile!\n---\n\n")
423
+ end
424
+ scenario_name = @scenario_file_name.split('.')[0]
425
+ scenario_path = File.absolute_path(@root_dir)
426
+ scenario_results_dir = File.join(scenario_path, 'run', scenario_name)
427
+ puts "\nDeleting previous results from '#{@scenario_file_name}'...\n"
428
+ FileUtils.rm_rf(scenario_results_dir)
429
+ puts "\nDone\n"
378
430
  end
379
431
 
380
432
  if @user_input[:version_request]
381
- puts "URBANopt CLI version: #{@user_input[:version_request]}"
433
+ puts "\nURBANopt CLI version: #{@user_input[:version_request]}\n---\n\n"
382
434
  end
383
-
384
- end # End module CLI
385
-
386
- end # End module Urbanopt
435
+ end
436
+ end