urbanopt-scenario 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.github/pull_request_template.md +2 -2
  3. data/.gitignore +2 -0
  4. data/CHANGELOG.md +32 -0
  5. data/CONTRIBUTING.md +1 -1
  6. data/Gemfile +33 -17
  7. data/Jenkinsfile +1 -1
  8. data/LICENSE.md +1 -1
  9. data/RDOC_MAIN.md +1 -1
  10. data/README.md +1 -1
  11. data/Rakefile +1 -1
  12. data/docs/README.md +1 -1
  13. data/docs/package-lock.json +2499 -2322
  14. data/docs/package.json +13 -9
  15. data/lib/urbanopt-scenario.rb +1 -1
  16. data/lib/urbanopt/scenario.rb +2 -1
  17. data/lib/urbanopt/scenario/default_reports.rb +3 -8
  18. data/lib/urbanopt/scenario/extension.rb +1 -1
  19. data/lib/urbanopt/scenario/logger.rb +1 -1
  20. data/lib/urbanopt/scenario/scenario_base.rb +1 -1
  21. data/lib/urbanopt/scenario/scenario_csv.rb +22 -9
  22. data/lib/urbanopt/scenario/scenario_datapoint_base.rb +8 -1
  23. data/lib/urbanopt/scenario/scenario_post_processor_base.rb +1 -1
  24. data/lib/urbanopt/scenario/scenario_post_processor_default.rb +81 -8
  25. data/lib/urbanopt/scenario/scenario_post_processor_opendss.rb +6 -7
  26. data/lib/urbanopt/scenario/scenario_runner_base.rb +2 -2
  27. data/lib/urbanopt/scenario/scenario_runner_osw.rb +23 -9
  28. data/lib/urbanopt/scenario/scenario_visualization.rb +236 -0
  29. data/lib/urbanopt/scenario/simulation_dir_base.rb +1 -1
  30. data/lib/urbanopt/scenario/simulation_dir_osw.rb +2 -5
  31. data/lib/urbanopt/scenario/simulation_mapper_base.rb +1 -1
  32. data/lib/urbanopt/scenario/version.rb +2 -2
  33. data/package-lock.json +3 -0
  34. data/urbanopt-scenario-gem.gemspec +10 -6
  35. metadata +73 -46
  36. data/doc_templates/LICENSE.md +0 -27
  37. data/doc_templates/README.md.erb +0 -42
  38. data/doc_templates/copyright_erb.txt +0 -31
  39. data/doc_templates/copyright_js.txt +0 -4
  40. data/doc_templates/copyright_ruby.txt +0 -29
  41. data/lib/measures/.rubocop.yml +0 -5
  42. data/lib/measures/default_feature_reports/LICENSE.md +0 -27
  43. data/lib/measures/default_feature_reports/README.md +0 -26
  44. data/lib/measures/default_feature_reports/README.md.erb +0 -42
  45. data/lib/measures/default_feature_reports/measure.rb +0 -1013
  46. data/lib/measures/default_feature_reports/measure.xml +0 -160
  47. data/lib/urbanopt/scenario/default_reports/construction_cost.rb +0 -169
  48. data/lib/urbanopt/scenario/default_reports/date.rb +0 -97
  49. data/lib/urbanopt/scenario/default_reports/distributed_generation.rb +0 -379
  50. data/lib/urbanopt/scenario/default_reports/end_use.rb +0 -159
  51. data/lib/urbanopt/scenario/default_reports/end_uses.rb +0 -140
  52. data/lib/urbanopt/scenario/default_reports/feature_report.rb +0 -267
  53. data/lib/urbanopt/scenario/default_reports/generator.rb +0 -92
  54. data/lib/urbanopt/scenario/default_reports/location.rb +0 -99
  55. data/lib/urbanopt/scenario/default_reports/logger.rb +0 -44
  56. data/lib/urbanopt/scenario/default_reports/power_distribution.rb +0 -102
  57. data/lib/urbanopt/scenario/default_reports/program.rb +0 -265
  58. data/lib/urbanopt/scenario/default_reports/reporting_period.rb +0 -304
  59. data/lib/urbanopt/scenario/default_reports/scenario_report.rb +0 -317
  60. data/lib/urbanopt/scenario/default_reports/schema/README.md +0 -33
  61. data/lib/urbanopt/scenario/default_reports/schema/scenario_csv_columns.txt +0 -34
  62. data/lib/urbanopt/scenario/default_reports/schema/scenario_schema.json +0 -857
  63. data/lib/urbanopt/scenario/default_reports/solar_pv.rb +0 -93
  64. data/lib/urbanopt/scenario/default_reports/storage.rb +0 -105
  65. data/lib/urbanopt/scenario/default_reports/timeseries_csv.rb +0 -299
  66. data/lib/urbanopt/scenario/default_reports/validator.rb +0 -97
  67. data/lib/urbanopt/scenario/default_reports/wind.rb +0 -92
@@ -10,17 +10,21 @@
10
10
  },
11
11
  "author": "NREL",
12
12
  "dependencies": {
13
- "highlight.js": "^9.15.6",
14
- "json-schema-ref-parser": "^6.1.0",
13
+ "highlight.js": "^10.2.0",
14
+ "json-schema-ref-parser": "^9.0.6",
15
15
  "json-schema-view-js": "git+https://git@github.com/bgschiller/json-schema-view-js.git",
16
- "vuepress": "^1.2.0",
17
- "webpack-dev-middleware": "^3.6.0"
16
+ "vuepress": "^1.5.4",
17
+ "webpack-dev-middleware": "^3.7.2"
18
18
  },
19
19
  "devDependencies": {
20
- "braces": ">=2.3.1",
21
- "gh-pages": "^2.0.1",
22
- "js-yaml": ">=3.13.1",
23
- "serialize-javascript": ">=2.1.1",
24
- "set-value": ">=2.0.1"
20
+ "braces": "^3.0.2",
21
+ "dot-prop": "^5.3.0",
22
+ "gh-pages": "^3.1.0",
23
+ "js-yaml": "^3.14.0",
24
+ "minimist": ">=1.2.3",
25
+ "node-forge": ">=0.10.0",
26
+ "serialize-javascript": "^5.0.1",
27
+ "set-value": "^3.0.2",
28
+ "yargs-parser": ">=18.1.1"
25
29
  }
26
30
  }
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -42,5 +42,6 @@ require 'urbanopt/scenario/scenario_runner_osw'
42
42
  require 'urbanopt/scenario/simulation_dir_base'
43
43
  require 'urbanopt/scenario/simulation_dir_osw'
44
44
  require 'urbanopt/scenario/simulation_mapper_base'
45
+ require 'urbanopt/scenario/scenario_visualization'
45
46
 
46
47
  require 'urbanopt/scenario/default_reports'
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -31,10 +31,5 @@
31
31
  ##
32
32
  # Retrieve all default_reports classes.
33
33
  ##
34
- require 'urbanopt/scenario/default_reports/construction_cost'
35
- require 'urbanopt/scenario/default_reports/feature_report'
36
- require 'urbanopt/scenario/default_reports/logger'
37
- require 'urbanopt/scenario/default_reports/program'
38
- require 'urbanopt/scenario/default_reports/reporting_period'
39
- require 'urbanopt/scenario/default_reports/scenario_report'
40
- require 'urbanopt/scenario/default_reports/timeseries_csv'
34
+
35
+ require 'urbanopt/reporting/default_reports'
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -52,7 +52,6 @@ module URBANopt
52
52
 
53
53
  def initialize(name, root_dir, run_dir, feature_file, mapper_files_dir, csv_file, num_header_rows)
54
54
  super(name, root_dir, run_dir, feature_file)
55
-
56
55
  @mapper_files_dir = mapper_files_dir
57
56
  @csv_file = csv_file
58
57
  @num_header_rows = num_header_rows
@@ -73,13 +72,27 @@ module URBANopt
73
72
 
74
73
  # Require all simulation mappers in mapper_files_dir
75
74
  def load_mapper_files
76
- Dir.glob(File.join(@mapper_files_dir, '/*.rb')).each do |f|
77
- begin
78
- require(f)
79
- rescue LoadError => e
80
- @@logger.error(e.message)
81
- raise
82
- end
75
+ dirs = Dir.glob(File.join(@mapper_files_dir, '/*.rb'))
76
+ # order is not guaranteed...attempt to add Baseline first, then High Efficiency
77
+ ordered_dirs = []
78
+ bindex = dirs.find_index { |i| i.include? 'Baseline.rb' }
79
+ if bindex
80
+ ordered_dirs << dirs[bindex]
81
+ dirs.delete_at(bindex)
82
+ end
83
+ hindex = dirs.find_index { |i| i.include? 'HighEfficiency.rb' }
84
+ if hindex
85
+ ordered_dirs << dirs[hindex] if hindex
86
+ dirs.delete_at(hindex)
87
+ end
88
+ # then the rest
89
+ ordered_dirs += dirs
90
+
91
+ ordered_dirs.each do |f|
92
+ require(f)
93
+ rescue LoadError => e
94
+ @@logger.error(e.message)
95
+ raise
83
96
  end
84
97
  end
85
98
 
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -59,6 +59,13 @@ module URBANopt
59
59
  @feature.feature_type
60
60
  end
61
61
 
62
+ ##
63
+ # Gets the type of a feature
64
+ ##
65
+ def feature_location
66
+ @feature.feature_location
67
+ end
68
+
62
69
  ##
63
70
  # Return the directory that this datapoint will run in.
64
71
  ##
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -29,12 +29,12 @@
29
29
  # *********************************************************************************
30
30
 
31
31
  require 'urbanopt/scenario/scenario_post_processor_base'
32
- require 'urbanopt/scenario/default_reports'
33
- require 'urbanopt/scenario/default_reports/logger'
32
+ require 'urbanopt/reporting/default_reports'
34
33
 
35
34
  require 'csv'
36
35
  require 'json'
37
36
  require 'fileutils'
37
+ require 'sqlite3'
38
38
 
39
39
  module URBANopt
40
40
  module Scenario
@@ -47,10 +47,11 @@ module URBANopt
47
47
  def initialize(scenario_base)
48
48
  super(scenario_base)
49
49
 
50
- initialization_hash = { directory_name: scenario_base.run_dir, name: scenario_base.name, id: scenario_base.name }
51
- @scenario_result = URBANopt::Scenario::DefaultReports::ScenarioReport.new(initialization_hash)
50
+ @initialization_hash = { directory_name: scenario_base.run_dir, name: scenario_base.name, id: scenario_base.name }
51
+ @scenario_result = URBANopt::Reporting::DefaultReports::ScenarioReport.new(@initialization_hash)
52
+ @default_save_name = 'default_scenario_report'
52
53
 
53
- @@logger ||= URBANopt::Scenario::DefaultReports.logger
54
+ @@logger ||= URBANopt::Reporting::DefaultReports.logger
54
55
  end
55
56
 
56
57
  ##
@@ -70,7 +71,7 @@ module URBANopt
70
71
  # [parameters:]
71
72
  # +simulation_dir+ - _SimulationDirOSW_ - An object on SimulationDirOSW class.
72
73
  def add_simulation_dir(simulation_dir)
73
- feature_reports = URBANopt::Scenario::DefaultReports::FeatureReport.from_simulation_dir(simulation_dir)
74
+ feature_reports = URBANopt::Reporting::DefaultReports::FeatureReport.from_simulation_dir(simulation_dir)
74
75
 
75
76
  feature_reports.each do |feature_report|
76
77
  if feature_report.to_hash[:simulation_status] == 'Complete'
@@ -83,12 +84,84 @@ module URBANopt
83
84
  return feature_reports
84
85
  end
85
86
 
87
+ # Create database file with scenario-level results
88
+ # Sum values for each timestep across all features. Save to new table in a new database
89
+ def create_scenario_db_file(file_name = @default_save_name)
90
+ new_db_file = File.join(@initialization_hash[:directory_name], "#{file_name}.db")
91
+ scenario_db = SQLite3::Database.open new_db_file
92
+ scenario_db.execute "CREATE TABLE IF NOT EXISTS ReportData(
93
+ TimeIndex INTEGER,
94
+ ReportDataDictionaryIndex INTEGER,
95
+ Value INTEGER
96
+ )"
97
+
98
+ values_arr = []
99
+ feature_list = Pathname.new(@initialization_hash[:directory_name]).children.select(&:directory?) # Folders in the run/scenario directory
100
+ feature_1_name = File.basename(feature_list[0]) # Get name of first feature, so we can read eplusout.sql from there
101
+ uo_output_sql_file = File.join(@initialization_hash[:directory_name], feature_1_name, 'eplusout.sql')
102
+ feature_list.each do |feature| # Loop through each feature in the scenario
103
+ feature_db = SQLite3::Database.open uo_output_sql_file
104
+ # Doing "db.results_as_hash = true" is prettier, but in this case significantly slower.
105
+
106
+ # RDDI == 10 is the timestep value for facility electricity
107
+ elec_query = feature_db.query "SELECT TimeIndex, Value
108
+ FROM ReportData
109
+ WHERE (TimeIndex % 2) != 0
110
+ AND ReportDataDictionaryIndex=10 order by TimeIndex"
111
+
112
+ elec_query.each do |row| # Add up all the values for electricity usage across all Features at this timestep
113
+ # row[0] == TimeIndex, row[1] == Value
114
+ arr_match = values_arr.find { |v| v[:time_index] == row[0] }
115
+ if arr_match.nil?
116
+ # add new row to value_arr
117
+ values_arr << { time_index: row[0], elec_val: Float(row[1]), gas_val: 0 }
118
+ else
119
+ # running sum
120
+ arr_match[:elec_val] += Float(row[1])
121
+ end
122
+ end # End elec_query
123
+ elec_query.close
124
+
125
+ # RDDI == 255 is the timestep value for facility gas
126
+ gas_query = feature_db.query "SELECT TimeIndex, Value
127
+ FROM ReportData
128
+ WHERE (TimeIndex % 2) != 0
129
+ AND ReportDataDictionaryIndex=255 order by TimeIndex"
130
+
131
+ gas_query.each do |row|
132
+ # row[0] == TimeIndex, row[1] == Value
133
+ arr_match = values_arr.find { |v| v[:time_index] == row[0] }
134
+ if arr_match.nil?
135
+ # add new row to value_arr
136
+ values_arr << { time_index: row[0], gas_val: Float(row[1]), elec_val: 0 }
137
+ else
138
+ # running sum
139
+ arr_match[:gas_val] += Float(row[1])
140
+ end
141
+ end # End gas_query
142
+ gas_query.close
143
+ feature_db.close
144
+ end # End feature_list loop
145
+
146
+ elec_sql = []
147
+ gas_sql = []
148
+ values_arr.each do |i|
149
+ elec_sql << "(#{i[:time_index]}, 10, #{i[:elec_val]})"
150
+ gas_sql << "(#{i[:time_index]}, 255, #{i[:gas_val]})"
151
+ end
152
+
153
+ # Put summed Values into the database
154
+ scenario_db.execute("INSERT INTO ReportData (TimeIndex, ReportDataDictionaryIndex, Value) VALUES #{elec_sql.join(', ')}")
155
+ scenario_db.execute("INSERT INTO ReportData (TimeIndex, ReportDataDictionaryIndex, Value) VALUES #{gas_sql.join(', ')}")
156
+ scenario_db.close
157
+ end
158
+
86
159
  ##
87
160
  # Save scenario result
88
161
  ##
89
162
  # [parameters:]
90
163
  # +file_name+ - _String_ - Assign a name to the saved scenario results file
91
- def save(file_name = 'default_scenario_report')
164
+ def save(file_name = @default_save_name)
92
165
  @scenario_result.save
93
166
 
94
167
  return @scenario_result
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -29,8 +29,7 @@
29
29
  # *********************************************************************************
30
30
 
31
31
  # require 'urbanopt/scenario/scenario_post_processor_base'
32
- require 'urbanopt/scenario/default_reports'
33
- require 'urbanopt/scenario/default_reports/logger'
32
+ require 'urbanopt/reporting/default_reports'
34
33
 
35
34
  require 'csv'
36
35
  require 'json'
@@ -64,7 +63,7 @@ module URBANopt
64
63
  @feature_reports_data = {}
65
64
 
66
65
  # initialize logger
67
- @@logger ||= URBANopt::Scenario::DefaultReports.logger
66
+ @@logger ||= URBANopt::Reporting::DefaultReports.logger
68
67
  end
69
68
 
70
69
  # load opendss data
@@ -166,9 +165,9 @@ module URBANopt
166
165
  File.write(File.join(transformer_dir, 'feature_reports', 'default_feature_report_opendss' + '.csv'), transformer_csv)
167
166
 
168
167
  # create transformer report
169
- transformer_report = URBANopt::Scenario::DefaultReports::FeatureReport.new(id: k, name: k, directory_name: transformer_dir, feature_type: 'Transformer',
170
- timesteps_per_hour: @scenario_report.timesteps_per_hour,
171
- simulation_status: 'complete')
168
+ transformer_report = URBANopt::Reporting::DefaultReports::FeatureReport.new(id: k, name: k, directory_name: transformer_dir, feature_type: 'Transformer',
169
+ timesteps_per_hour: @scenario_report.timesteps_per_hour,
170
+ simulation_status: 'complete')
172
171
 
173
172
  # assign results to transfomrer report
174
173
  transformer_report.power_distribution.over_voltage_hours = over_voltage_hrs
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -55,7 +55,7 @@ module URBANopt
55
55
  # +force_clear+ - _Bool_ - Clear Scenario before creating Simulation input files.
56
56
  #
57
57
  # [return:] _Array_ Returns an array of all SimulationDirs, even those created previously, for Scenario.
58
- def run(scenario, force_clear = false)
58
+ def run(scenario, force_clear = false, options = {})
59
59
  raise 'run is not implemented for ScenarioRunnerBase, override in your class'
60
60
  end
61
61
  end
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -55,6 +55,7 @@ module URBANopt
55
55
  end
56
56
 
57
57
  FileUtils.mkdir_p(scenario.run_dir) if !File.exist?(scenario.run_dir)
58
+ FileUtils.rm_rf(File.join(scenario.run_dir, 'run_status.json')) if File.exist?(File.join(scenario.run_dir, 'run_status.json'))
58
59
 
59
60
  simulation_dirs = scenario.simulation_dirs
60
61
 
@@ -81,10 +82,11 @@ module URBANopt
81
82
  # +scenario+ - _ScenarioBase_ - Scenario to create and run SimulationFiles for.
82
83
  # +force_clear+ - _Bool_ - Clear Scenario before creating SimulationFiles.
83
84
  # [return:] _Array_ Returns array of all SimulationFiles, even those created previously, for Scenario.
84
- def run(scenario, force_clear = false)
85
+ def run(scenario, force_clear = false, options = {})
85
86
  # instantiate openstudio runner - use the defaults for now. If need to change then create
86
87
  # the runner.conf file (i.e. run `rake openstudio:runner:init`)
87
- runner = OpenStudio::Extension::Runner.new(scenario.root_dir)
88
+ # allow passing gemfile_path and bundle_install_path in options
89
+ runner = OpenStudio::Extension::Runner.new(scenario.root_dir, [], options)
88
90
 
89
91
  # create simulation files
90
92
  simulation_dirs = create_simulation_files(scenario, force_clear)
@@ -156,18 +158,30 @@ module URBANopt
156
158
  # puts "DATAPOINT FAILURES: #{failures}"
157
159
  # end
158
160
 
159
- # look for other failed datapoints
161
+ # write results to file and to command line
162
+ get_results(scenario, simulation_dirs)
163
+
164
+ return simulation_dirs
165
+ end
166
+
167
+ def get_results(scenario, simulation_dirs)
168
+ # look for other failed datapoints (command line display)
169
+ # also compile datapoint status for latest_run.json file
170
+ status_arr = []
160
171
  failed_sims = []
161
- simulation_dirs.each do |simulation_dir|
162
- if File.exist?(File.join(simulation_dir.run_dir, 'failed.job'))
163
- failed_sims << simulation_dir.run_dir.split('/')[-1]
172
+ simulation_dirs.each do |sim_dir|
173
+ if File.exist?(sim_dir.failed_job_path)
174
+ failed_sims << sim_dir.run_dir.split('/')[-1]
164
175
  end
176
+ status_arr << { "id": sim_dir.feature_id, "status": sim_dir.simulation_status, "mapper_class": sim_dir.mapper_class }
165
177
  end
178
+
179
+ # write to file
180
+ File.open(File.join(scenario.run_dir, 'run_status.json'), 'w') { |f| f.write JSON.pretty_generate("timestamp": Time.now.strftime('%Y-%m-%dT%k:%M:%S.%L'), "results": status_arr) }
181
+
166
182
  if !failed_sims.empty?
167
183
  puts "FAILED SIMULATION IDs: #{failed_sims.join(',')}"
168
184
  end
169
-
170
- return simulation_dirs
171
185
  end
172
186
  end
173
187
  end
@@ -0,0 +1,236 @@
1
+ # *********************************************************************************
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
+ # contributors. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without modification,
6
+ # are permitted provided that the following conditions are met:
7
+ #
8
+ # Redistributions of source code must retain the above copyright notice, this list
9
+ # of conditions and the following disclaimer.
10
+ #
11
+ # Redistributions in binary form must reproduce the above copyright notice, this
12
+ # list of conditions and the following disclaimer in the documentation and/or other
13
+ # materials provided with the distribution.
14
+ #
15
+ # Neither the name of the copyright holder nor the names of its contributors may be
16
+ # used to endorse or promote products derived from this software without specific
17
+ # prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
+ # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24
+ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
+ # OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ # *********************************************************************************
30
+
31
+ require 'csv'
32
+ require 'date'
33
+ require 'json'
34
+ require 'fileutils'
35
+
36
+ module URBANopt
37
+ module Scenario
38
+ class ResultVisualization
39
+ def self.create_visualization(run_dir, feature = true)
40
+ @all_results = []
41
+ run_dir.each do |folder|
42
+ name = folder.split('/')[-1]
43
+
44
+ # create visualization for scenarios
45
+ if feature == false
46
+ csv_dir = File.join(folder, 'default_scenario_report.csv')
47
+ # create visualization for features
48
+ elsif feature == true
49
+ csv_dir = File.join(folder, 'feature_reports/default_feature_report.csv')
50
+ end
51
+
52
+ if File.exist?(csv_dir)
53
+ size = CSV.open(csv_dir).readlines.size
54
+
55
+ monthly_values = {}
56
+ monthly_totals = {}
57
+ annual_values = {}
58
+
59
+ headers_unitless = []
60
+ i = 0
61
+ CSV.foreach(csv_dir).map do |row|
62
+ if i == 0
63
+ # store header values from csv
64
+ headers = row
65
+ headers.each do |header|
66
+ header_unitless = header.to_s.split('(')[0]
67
+ headers_unitless << header_unitless
68
+ monthly_values[header_unitless] = []
69
+ end
70
+ # store values from csv for each row
71
+ elsif i <= size
72
+ headers_unitless.each_index do |j|
73
+ monthly_values[headers_unitless[j]] << row[j]
74
+ end
75
+ end
76
+ i += 1
77
+ end
78
+
79
+ if monthly_values['Datetime'][0].split(/\W+/)[0].to_f > 31
80
+ format = '%Y/%m/%d %H:%M'
81
+ year = monthly_values['Datetime'][0].split(/\W+/)[0]
82
+ else
83
+ format = '%m/%d/%Y %H:%M'
84
+ year = monthly_values['Datetime'][0].split(/\W+/)[2]
85
+ end
86
+
87
+ # create dates for each month
88
+ jan_date = DateTime.new(year.to_i, 1, 1, 1, 0)
89
+ feb_date = DateTime.new(year.to_i, 2, 1, 0, 0)
90
+ mar_date = DateTime.new(year.to_i, 3, 1, 0, 0)
91
+ apr_date = DateTime.new(year.to_i, 4, 1, 0, 0)
92
+ may_date = DateTime.new(year.to_i, 5, 1, 0, 0)
93
+ jun_date = DateTime.new(year.to_i, 6, 1, 0, 0)
94
+ jul_date = DateTime.new(year.to_i, 7, 1, 0, 0)
95
+ aug_date = DateTime.new(year.to_i, 8, 1, 0, 0)
96
+ sep_date = DateTime.new(year.to_i, 9, 1, 0, 0)
97
+ oct_date = DateTime.new(year.to_i, 10, 1, 0, 0)
98
+ nov_date = DateTime.new(year.to_i, 11, 1, 0, 0)
99
+ dec_date = DateTime.new(year.to_i, 12, 1, 0, 0)
100
+ jan_next_year = DateTime.new(year.to_i + 1, 1, 1, 0, 0)
101
+
102
+ monthly_values['Datetime'].each do |i|
103
+ date_obj = DateTime.strptime(i.to_s, format)
104
+ index = monthly_values['Datetime'].index(i)
105
+
106
+ # store index of each date from the csv
107
+ if feb_date == date_obj
108
+ @feb_index = index
109
+ elsif mar_date == date_obj
110
+ @mar_index = index
111
+ elsif apr_date == date_obj
112
+ @apr_index = index
113
+ elsif may_date == date_obj
114
+ @may_index = index
115
+ elsif jun_date == date_obj
116
+ @jun_index = index
117
+ elsif jul_date == date_obj
118
+ @jul_index = index
119
+ elsif aug_date == date_obj
120
+ @aug_index = index
121
+ elsif sep_date == date_obj
122
+ @sep_index = index
123
+ elsif oct_date == date_obj
124
+ @oct_index = index
125
+ elsif nov_date == date_obj
126
+ @nov_index = index
127
+ elsif dec_date == date_obj
128
+ @dec_index = index
129
+ elsif jan_next_year == date_obj
130
+ @jan_next_year_index = index
131
+ end
132
+ end
133
+
134
+ headers_unitless.each_index do |j|
135
+ i = 0
136
+ k = 0
137
+
138
+ monthly_sum_jan = monthly_sum_feb = monthly_sum_mar = monthly_sum_apr = monthly_sum_may = monthly_sum_jun = monthly_sum_jul = monthly_sum_aug = monthly_sum_sep = monthly_sum_oct = monthly_sum_nov = monthly_sum_dec = annual_sum = 0
139
+
140
+ # loop through values for each header
141
+ all_values = monthly_values[headers_unitless[j]]
142
+
143
+ unless @jan_next_year_index.nil? || @feb_index.nil? || @mar_index.nil? || @apr_index.nil? || @may_index.nil? || @jun_index.nil? || @jul_index.nil? || @aug_index.nil? || @sep_index.nil? || @oct_index.nil? || @nov_index.nil? || @dec_index.nil?
144
+
145
+ # for each header store monthly sums of values
146
+ all_values.each do |v|
147
+ if i < @feb_index
148
+ monthly_sum_jan += v.to_f
149
+ i += 1
150
+ elsif @feb_index <= i && i < @mar_index
151
+ monthly_sum_feb += v.to_f
152
+ i += 1
153
+ elsif @mar_index <= i && i < @apr_index
154
+ monthly_sum_mar += v.to_f
155
+ i += 1
156
+ elsif @apr_index <= i && i < @may_index
157
+ monthly_sum_apr += v.to_f
158
+ i += 1
159
+ elsif @may_index <= i && i < @jun_index
160
+ monthly_sum_may += v.to_f
161
+ i += 1
162
+ elsif @jun_index <= i && i < @jul_index
163
+ monthly_sum_jun += v.to_f
164
+ i += 1
165
+ elsif @jul_index <= i && i < @aug_index
166
+ monthly_sum_jul += v.to_f
167
+ i += 1
168
+ elsif @aug_index <= i && i < @sep_index
169
+ monthly_sum_aug += v.to_f
170
+ i += 1
171
+ elsif @sep_index <= i && i < @oct_index
172
+ monthly_sum_sep += v.to_f
173
+ i += 1
174
+ elsif @oct_index <= i && i < @nov_index
175
+ monthly_sum_oct += v.to_f
176
+ i += 1
177
+ elsif @nov_index <= i && i < @dec_index
178
+ monthly_sum_nov += v.to_f
179
+ i += 1
180
+ elsif @dec_index <= i && i < @jan_next_year_index
181
+ monthly_sum_dec += v.to_f
182
+ i += 1
183
+ end
184
+ # sum up all values for annual aggregate
185
+ if k <= size
186
+ annual_sum += v.to_f
187
+ k += 1
188
+ end
189
+ end
190
+ end
191
+
192
+ # store headers as key and monthly sums as values for each header
193
+ monthly_totals[headers_unitless[j]] = [monthly_sum_jan, monthly_sum_feb, monthly_sum_mar, monthly_sum_apr, monthly_sum_may, monthly_sum_jun, monthly_sum_jul, monthly_sum_aug, monthly_sum_sep, monthly_sum_oct, monthly_sum_nov, monthly_sum_dec]
194
+
195
+ annual_values[headers_unitless[j]] = annual_sum
196
+ end
197
+
198
+ @results = {}
199
+ @results['name'] = name
200
+ @results['monthly_values'] = {}
201
+ @results['annual_values'] = {}
202
+
203
+ if @jan_next_year_index.nil? || @feb_index.nil? || @mar_index.nil? || @apr_index.nil? || @may_index.nil? || @jun_index.nil? || @jul_index.nil? || @aug_index.nil? || @sep_index.nil? || @oct_index.nil? || @nov_index.nil? || @dec_index.nil?
204
+ @results['complete_simulation'] = false
205
+ puts "#{name} did not contain an annual simulation…visualizations will not render for it."
206
+ else
207
+ @results['complete_simulation'] = true
208
+ end
209
+
210
+ monthly_totals&.each do |key, value|
211
+ unless key == 'Datetime'
212
+ @results['monthly_values'][key] = value
213
+ end
214
+ end
215
+
216
+ annual_values&.each do |key, value|
217
+ unless key == 'Datetime'
218
+ @results['annual_values'][key] = value
219
+ end
220
+ end
221
+
222
+ end
223
+
224
+ unless @results.nil?
225
+ @all_results << @results
226
+ end
227
+ end
228
+ # create json with required data stored in a variable
229
+ results_path = File.join(run_dir[0], '../scenarioData.js')
230
+ File.open(results_path, 'w') do |file|
231
+ file << "var scenarioData = #{JSON.pretty_generate(@all_results)};"
232
+ end
233
+ end
234
+ end # ResultVisualization
235
+ end # Scenario
236
+ end # URBANopt