urbanopt-scenario 0.1.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 (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +25 -0
  3. data/.rdoc_options +36 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +10 -0
  6. data/.travis.yml +23 -0
  7. data/CHANGELOG.md +5 -0
  8. data/Gemfile +42 -0
  9. data/Jenkinsfile +10 -0
  10. data/LICENSE.md +27 -0
  11. data/RDOC_MAIN.md +39 -0
  12. data/README.md +39 -0
  13. data/Rakefile +51 -0
  14. data/deploy_docs.sh +5 -0
  15. data/doc_templates/LICENSE.md +27 -0
  16. data/doc_templates/README.md.erb +42 -0
  17. data/doc_templates/copyright_erb.txt +31 -0
  18. data/doc_templates/copyright_js.txt +4 -0
  19. data/doc_templates/copyright_ruby.txt +29 -0
  20. data/docs/.gitignore +3 -0
  21. data/docs/.vuepress/components/InnerJsonSchema.vue +84 -0
  22. data/docs/.vuepress/components/JsonSchema.vue +12 -0
  23. data/docs/.vuepress/components/ScenarioSchema.vue +12 -0
  24. data/docs/.vuepress/components/StaticLink.vue +8 -0
  25. data/docs/.vuepress/config.js +15 -0
  26. data/docs/.vuepress/highlight.js +8 -0
  27. data/docs/.vuepress/public/custom_rdoc_styles.css +74 -0
  28. data/docs/.vuepress/utils.js +17 -0
  29. data/docs/README.md +39 -0
  30. data/docs/package-lock.json +11791 -0
  31. data/docs/package.json +22 -0
  32. data/docs/schemas/scenario-schema.md +3 -0
  33. data/lib/measures/.rubocop.yml +5 -0
  34. data/lib/measures/default_feature_reports/LICENSE.md +27 -0
  35. data/lib/measures/default_feature_reports/README.md +56 -0
  36. data/lib/measures/default_feature_reports/README.md.erb +42 -0
  37. data/lib/measures/default_feature_reports/measure.rb +731 -0
  38. data/lib/measures/default_feature_reports/measure.xml +139 -0
  39. data/lib/measures/default_feature_reports/tests/USA_CO_Golden-NREL.724666_TMY3.epw +8768 -0
  40. data/lib/measures/default_feature_reports/tests/default_feature_reports_test.rb +238 -0
  41. data/lib/measures/default_feature_reports/tests/example_model.osm +4378 -0
  42. data/lib/urbanopt-scenario.rb +31 -0
  43. data/lib/urbanopt/scenario.rb +45 -0
  44. data/lib/urbanopt/scenario/default_reports.rb +40 -0
  45. data/lib/urbanopt/scenario/default_reports/construction_cost.rb +169 -0
  46. data/lib/urbanopt/scenario/default_reports/date.rb +97 -0
  47. data/lib/urbanopt/scenario/default_reports/end_use.rb +159 -0
  48. data/lib/urbanopt/scenario/default_reports/end_uses.rb +140 -0
  49. data/lib/urbanopt/scenario/default_reports/feature_report.rb +207 -0
  50. data/lib/urbanopt/scenario/default_reports/location.rb +99 -0
  51. data/lib/urbanopt/scenario/default_reports/logger.rb +44 -0
  52. data/lib/urbanopt/scenario/default_reports/program.rb +261 -0
  53. data/lib/urbanopt/scenario/default_reports/reporting_period.rb +298 -0
  54. data/lib/urbanopt/scenario/default_reports/scenario_report.rb +276 -0
  55. data/lib/urbanopt/scenario/default_reports/schema/README.md +33 -0
  56. data/lib/urbanopt/scenario/default_reports/schema/scenario_csv_columns.txt +13 -0
  57. data/lib/urbanopt/scenario/default_reports/schema/scenario_schema.json +742 -0
  58. data/lib/urbanopt/scenario/default_reports/timeseries_csv.rb +231 -0
  59. data/lib/urbanopt/scenario/default_reports/validator.rb +97 -0
  60. data/lib/urbanopt/scenario/extension.rb +63 -0
  61. data/lib/urbanopt/scenario/logger.rb +42 -0
  62. data/lib/urbanopt/scenario/scenario_base.rb +79 -0
  63. data/lib/urbanopt/scenario/scenario_csv.rb +122 -0
  64. data/lib/urbanopt/scenario/scenario_datapoint_base.rb +162 -0
  65. data/lib/urbanopt/scenario/scenario_post_processor_base.rb +69 -0
  66. data/lib/urbanopt/scenario/scenario_post_processor_default.rb +97 -0
  67. data/lib/urbanopt/scenario/scenario_runner_base.rb +63 -0
  68. data/lib/urbanopt/scenario/scenario_runner_osw.rb +158 -0
  69. data/lib/urbanopt/scenario/simulation_dir_base.rb +90 -0
  70. data/lib/urbanopt/scenario/simulation_dir_osw.rb +261 -0
  71. data/lib/urbanopt/scenario/simulation_mapper_base.rb +47 -0
  72. data/lib/urbanopt/scenario/version.rb +35 -0
  73. data/urbanopt-scenario-gem.gemspec +36 -0
  74. metadata +227 -0
@@ -0,0 +1,63 @@
1
+ # *********************************************************************************
2
+ # URBANopt, Copyright (c) 2019, Alliance for Sustainable Energy, LLC, and other
3
+ # contributors. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without modification,
6
+ # are permitted provided that the following conditions are met:
7
+ #
8
+ # Redistributions of source code must retain the above copyright notice, this list
9
+ # of conditions and the following disclaimer.
10
+ #
11
+ # Redistributions in binary form must reproduce the above copyright notice, this
12
+ # list of conditions and the following disclaimer in the documentation and/or other
13
+ # materials provided with the distribution.
14
+ #
15
+ # Neither the name of the copyright holder nor the names of its contributors may be
16
+ # used to endorse or promote products derived from this software without specific
17
+ # prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
+ # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24
+ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
+ # OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ # *********************************************************************************
30
+
31
+ module URBANopt
32
+ module Scenario
33
+ class ScenarioRunnerBase
34
+ ##
35
+ # ScenarioRunnerBase is the agnostic interface for a class which can create and run SimulationFiles.
36
+ ##
37
+ def initialize; end
38
+
39
+ ##
40
+ # Create all SimulationDirs for Scenario.
41
+ ##
42
+ # [parameters:]
43
+ # +scenario+ - _ScenarioBase_ - Scenario to create simulation input files for scenario.
44
+ # +force_clear+ - _Bool_ - Clear Scenario before creating simulation input files
45
+ # [return:] _Array_ Returns an array of all SimulationDirs, even those created previously, for Scenario.
46
+ def create_simulation_files(scenario, force_clear = false)
47
+ raise 'create_input_files is not implemented for ScenarioRunnerBase, override in your class'
48
+ end
49
+
50
+ ##
51
+ # Create and run all SimulationFiles for Scenario.
52
+ ##
53
+ # [parameters:]
54
+ # +scenario+ - _ScenarioBase_ - Scenario to create and run simulation input files for.
55
+ # +force_clear+ - _Bool_ - Clear Scenario before creating Simulation input files.
56
+ #
57
+ # [return:] _Array_ Returns an array of all SimulationDirs, even those created previously, for Scenario.
58
+ def run(scenario, force_clear = false)
59
+ raise 'run is not implemented for ScenarioRunnerBase, override in your class'
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,158 @@
1
+ # *********************************************************************************
2
+ # URBANopt, Copyright (c) 2019, Alliance for Sustainable Energy, LLC, and other
3
+ # contributors. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without modification,
6
+ # are permitted provided that the following conditions are met:
7
+ #
8
+ # Redistributions of source code must retain the above copyright notice, this list
9
+ # of conditions and the following disclaimer.
10
+ #
11
+ # Redistributions in binary form must reproduce the above copyright notice, this
12
+ # list of conditions and the following disclaimer in the documentation and/or other
13
+ # materials provided with the distribution.
14
+ #
15
+ # Neither the name of the copyright holder nor the names of its contributors may be
16
+ # used to endorse or promote products derived from this software without specific
17
+ # prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
+ # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24
+ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
+ # OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ # *********************************************************************************
30
+
31
+ require 'urbanopt/scenario/scenario_runner_base'
32
+ require 'json'
33
+
34
+ require 'fileutils'
35
+ # require 'hash_parser'
36
+
37
+ module URBANopt
38
+ module Scenario
39
+ class ScenarioRunnerOSW < ScenarioRunnerBase
40
+ ##
41
+ # ScenarioRunnerOSW is a class to create and run SimulationFileOSWs
42
+ ##
43
+ def initialize; end
44
+
45
+ ##
46
+ # Create all OSWs for Scenario.
47
+ ##
48
+ # [parameters:]
49
+ # +scenario+ - _ScenarioBase_ - Scenario to create simulation input files for.
50
+ # +force_clear+ - _Bool_ - Clear Scenario before creating simulation input files.
51
+ # [return:] _Array_ Returns array of all SimulationDirs, even those created previously, for Scenario.
52
+ def create_simulation_files(scenario, force_clear = false)
53
+ if force_clear
54
+ scenario.clear
55
+ end
56
+
57
+ FileUtils.mkdir_p(scenario.run_dir) if !File.exist?(scenario.run_dir)
58
+
59
+ simulation_dirs = scenario.simulation_dirs
60
+
61
+ simulation_dirs.each do |simulation_dir|
62
+ if simulation_dir.out_of_date?
63
+ puts "simulation_dir #{simulation_dir.run_dir} is out of date, regenerating input files"
64
+ simulation_dir.create_input_files
65
+ end
66
+ end
67
+ return simulation_dirs
68
+ end
69
+
70
+ ##
71
+ # Create and run all SimulationFileOSW for Scenario.
72
+ # A staged runner is implented to run buildings, then transformers then district systems.
73
+ # - instantiate openstudio runner to run .osw files.
74
+ # - create simulation files for this scenario.
75
+ # - get feature_type value from in.osw files
76
+ # - cretae 3 groups to store .osw files (+building_osws+ , +transformer_osws+ , +district_system_osws+)
77
+ # - add each osw file to its corresponding group id +simulation_dir+ is out_of_date
78
+ # - Run osw file groups in order and store simulation failure in a array.
79
+ ##
80
+ # [parameters:]
81
+ # +scenario+ - _ScenarioBase_ - Scenario to create and run SimulationFiles for.
82
+ # +force_clear+ - _Bool_ - Clear Scenario before creating SimulationFiles.
83
+ # [return:] _Array_ Returns array of all SimulationFiles, even those created previously, for Scenario.
84
+ def run(scenario, force_clear = false)
85
+ # instantiate openstudio runner - use the defaults for now. If need to change then create
86
+ # the runner.conf file (i.e. run `rake openstudio:runner:init`)
87
+ runner = OpenStudio::Extension::Runner.new(scenario.root_dir)
88
+
89
+ # create simulation files
90
+ simulation_dirs = create_simulation_files(scenario, force_clear)
91
+
92
+ # osws = []
93
+ # simulation_dirs.each do |simulation_dir|
94
+ # if !simulation_dir.is_a?(SimulationDirOSW)
95
+ # raise "ScenarioRunnerOSW does not know how to run #{simulation_dir.class}"
96
+ # end
97
+ # if simulation_dir.out_of_date?
98
+ # osws << simulation_dir.in_osw_path
99
+ # end
100
+ # end
101
+
102
+ # cretae 3 groups to store .osw files (+building_osws+ , +transformer_osws+ , +district_system_osws+)
103
+ building_osws = []
104
+ transformer_osws = []
105
+ district_system_osws = []
106
+
107
+ simulation_dirs.each do |simulation_dir|
108
+ in_osw = File.read(simulation_dir.in_osw_path)
109
+ in_osw_hash = JSON.parse(in_osw, symbolize_names: true)
110
+
111
+ if !simulation_dir.is_a?(SimulationDirOSW)
112
+ raise "ScenarioRunnerOSW does not know how to run #{simulation_dir.class}"
113
+ end
114
+
115
+ # get feature_type value from in.osw files
116
+ feature_type = nil
117
+ in_osw_hash[:steps].each { |x| feature_type = x[:arguments][:feature_type] if x[:arguments][:feature_type] }
118
+
119
+ # add each osw file to its corresponding group id +simulation_dir+ is out_of_date
120
+ if simulation_dir.out_of_date?
121
+
122
+ if feature_type == 'Building'
123
+ building_osws << simulation_dir.in_osw_path
124
+ elsif feature_type == 'District System'
125
+ district_system_osws << simulation_dir.in_osw_path
126
+ elsif feature_type == 'Transformer'
127
+ transformer_osws << simulation_dir.in_osw_path
128
+ else
129
+ raise "ScenarioRunnerOSW does not know how to run a #{feature_type} feature"
130
+ end
131
+
132
+ end
133
+ end
134
+
135
+ # Run osw groups in order and store simulation failure in a array.
136
+ # Return simulation_dirs after running all simulations.
137
+
138
+ # failures
139
+ failures = []
140
+ # run building_osws
141
+ # building_failures = runner.run_osws(building_osws, num_parallel = Extension::NUM_PARALLEL, max_to_run = Extension::MAX_DATAPOINTS)
142
+ building_failures = runner.run_osws(building_osws)
143
+ failures << building_failures
144
+ # run district_system_osws
145
+ # district_system_failures = runner.run_osws(district_system_osws, num_parallel = Extension::NUM_PARALLEL, max_to_run = Extension::MAX_DATAPOINTS)
146
+ district_system_failures = runner.run_osws(district_system_osws)
147
+ failures << district_system_failures
148
+ # run transformer_osws
149
+ # transformer_failures = runner.run_osws(transformer_osws, num_parallel = Extension::NUM_PARALLEL, max_to_run = Extension::MAX_DATAPOINTS)
150
+ transformer_failures = runner.run_osws(transformer_osws)
151
+ failures << transformer_failures
152
+
153
+ # puts "failures = #{failures}"
154
+ return simulation_dirs
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,90 @@
1
+ # *********************************************************************************
2
+ # URBANopt, Copyright (c) 2019, Alliance for Sustainable Energy, LLC, and other
3
+ # contributors. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without modification,
6
+ # are permitted provided that the following conditions are met:
7
+ #
8
+ # Redistributions of source code must retain the above copyright notice, this list
9
+ # of conditions and the following disclaimer.
10
+ #
11
+ # Redistributions in binary form must reproduce the above copyright notice, this
12
+ # list of conditions and the following disclaimer in the documentation and/or other
13
+ # materials provided with the distribution.
14
+ #
15
+ # Neither the name of the copyright holder nor the names of its contributors may be
16
+ # used to endorse or promote products derived from this software without specific
17
+ # prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
+ # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24
+ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
+ # OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ # *********************************************************************************
30
+
31
+ module URBANopt
32
+ module Scenario
33
+ class SimulationDirBase
34
+ ##
35
+ # SimulationDirBase is the agnostic representation of a directory of simulation input files.
36
+ ##
37
+ # [parameters:]
38
+ # +scenario+ - _ScenarioBase_ - Scenario containing this SimulationDirBase.
39
+ # +features+ - _Array_ - Array of Features that this SimulationDirBase represents.
40
+ # +feature_names+ - _Array_ - Array of scenario specific names for these Features.
41
+ def initialize(scenario, features, feature_names)
42
+ @scenario = scenario
43
+ @features = features
44
+ @feature_names = feature_names
45
+ end
46
+
47
+ attr_reader :scenario #:nodoc:
48
+
49
+ attr_reader :features #:nodoc:
50
+
51
+ attr_reader :feature_names #:nodoc:
52
+
53
+ ##
54
+ # Return the directory that this simulation will run in
55
+ ##
56
+ def run_dir
57
+ raise 'run_dir is not implemented for SimulationFileBase, override in your class'
58
+ end
59
+
60
+ ##
61
+ # Return true if the simulation is out of date (input files newer than results), false otherwise.
62
+ # Non-existant simulation input files are out of date.
63
+ ##
64
+ def out_of_date?
65
+ raise 'out_of_date? is not implemented for SimulationFileBase, override in your class'
66
+ end
67
+
68
+ ##
69
+ # Returns simulation status one of {'Not Started', 'Started', 'Complete', 'Failed'}
70
+ ##
71
+ def simulation_status
72
+ raise 'simulation_status is not implemented for SimulationFileBase, override in your class'
73
+ end
74
+
75
+ ##
76
+ # Clear the directory that this simulation runs in
77
+ ##
78
+ def clear
79
+ raise 'clear is not implemented for SimulationFileBase, override in your class'
80
+ end
81
+
82
+ ##
83
+ # Create run directory and generate simulation inputs, all previous contents of directory are removed
84
+ ##
85
+ def create_input_files
86
+ raise 'create_input_files is not implemented for SimulationFileBase, override in your class'
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,261 @@
1
+ # *********************************************************************************
2
+ # URBANopt, Copyright (c) 2019, Alliance for Sustainable Energy, LLC, and other
3
+ # contributors. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without modification,
6
+ # are permitted provided that the following conditions are met:
7
+ #
8
+ # Redistributions of source code must retain the above copyright notice, this list
9
+ # of conditions and the following disclaimer.
10
+ #
11
+ # Redistributions in binary form must reproduce the above copyright notice, this
12
+ # list of conditions and the following disclaimer in the documentation and/or other
13
+ # materials provided with the distribution.
14
+ #
15
+ # Neither the name of the copyright holder nor the names of its contributors may be
16
+ # used to endorse or promote products derived from this software without specific
17
+ # prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
+ # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24
+ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
+ # OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ # *********************************************************************************
30
+
31
+ require 'urbanopt/scenario/simulation_dir_base'
32
+
33
+ module URBANopt
34
+ module Scenario
35
+ class SimulationDirOSW < SimulationDirBase
36
+ ##
37
+ # SimulationDirOSW creates a OSW file to simulate features, a SimulationMapperBase is invoked to translate features to OSW.
38
+ ##
39
+ # [parameters:]
40
+ # +scenario+ - _ScenarioBase_ - Scenario containing this SimulationFileBase.
41
+ # +features+ - _Array_ - Array of Features this SimulationFile represents.
42
+ # +feature_names+ - _Array_ - Array of scenario specific names for these Features.
43
+ # +mapper_class+ - _String_ - Name of class derived frmo SimulationMapperBase used to translate feature to simulation OSW.
44
+ def initialize(scenario, features, feature_names, mapper_class)
45
+ super(scenario, features, feature_names)
46
+
47
+ if features.size != 1
48
+ raise 'SimulationDirOSW currently cannot simulate more than one feature'
49
+ end
50
+
51
+ @feature = features[0]
52
+ @feature_id = @feature.id
53
+
54
+ if feature_names.size == 1
55
+ @feature_name = feature_names[0]
56
+ else
57
+ @feature_name = @feature.name
58
+ end
59
+
60
+ @mapper_class = mapper_class
61
+ end
62
+
63
+ attr_reader :mapper_class
64
+
65
+ ##
66
+ # Return the directory that this simulation will run in.
67
+ ##
68
+ def run_dir
69
+ raise 'Feature ID not set' if @feature_id.nil?
70
+ raise 'Scenario run dir not set' if scenario.run_dir.nil?
71
+ return File.join(scenario.run_dir, @feature_id + '/')
72
+ end
73
+
74
+ ##
75
+ # Return the input OSW path
76
+ ##
77
+ def in_osw_path
78
+ return File.join(run_dir, 'in.osw')
79
+ end
80
+
81
+ ##
82
+ # Return the input OSW
83
+ ##
84
+ def in_osw
85
+ result = nil
86
+ if File.exist?(in_osw_path)
87
+ File.open(in_osw_path, 'r') do |f|
88
+ result = JSON.parse(f.read, symbolize_names: true)
89
+ end
90
+ end
91
+ return result
92
+ end
93
+
94
+ ##
95
+ # Return the started.job path
96
+ ##
97
+ def started_job_path
98
+ return File.join(run_dir, 'started.job')
99
+ end
100
+
101
+ ##
102
+ # Return the failed.job path
103
+ ##
104
+ def failed_job_path
105
+ return File.join(run_dir, 'failed.job')
106
+ end
107
+
108
+ ##
109
+ # Return the finished.job path
110
+ ##
111
+ def finished_job_path
112
+ return File.join(run_dir, 'finished.job')
113
+ end
114
+
115
+ ##
116
+ # Return the output OSW path
117
+ ##
118
+ def out_osw_path
119
+ return File.join(run_dir, 'out.osw')
120
+ end
121
+
122
+ ##
123
+ # Return the output OSW
124
+ ##
125
+ def out_osw
126
+ result = nil
127
+ if File.exist?(out_osw_path)
128
+ File.open(out_osw_path, 'r') do |f|
129
+ result = JSON.parse(f.read, symbolize_names: true)
130
+ end
131
+ end
132
+ return result
133
+ end
134
+
135
+ # rubocop: disable Metrics/AbcSize #:nodoc:
136
+
137
+ ##
138
+ # Return true if the simulation is out of date (input files newer than results), false otherwise.
139
+ # Non-existant simulation input files are out of date.
140
+ ##
141
+ def out_of_date?
142
+ if !File.exist?(run_dir)
143
+ puts "run_dir '#{run_dir}' does not exist, simulation dir '#{run_dir}' out of date"
144
+ return true
145
+ end
146
+
147
+ if !File.exist?(finished_job_path)
148
+ puts "finished_job_path '#{finished_job_path}' does not exist, simulation dir '#{run_dir}' out of date"
149
+ return true
150
+ end
151
+
152
+ if !File.exist?(out_osw_path)
153
+ puts "out_osw_path '#{out_osw_path}' does not exist, simulation dir '#{run_dir}' out of date"
154
+ return true
155
+ end
156
+ out_osw_time = File.mtime(out_osw_path)
157
+
158
+ # array of files that this simulation dir depends on
159
+ dependencies = []
160
+ out_of_date_files = []
161
+
162
+ # depends on the in.osw
163
+ dependencies << in_osw_path
164
+
165
+ # depends on the feature file
166
+ dependencies << scenario.feature_file.path
167
+
168
+ # depends on the csv file
169
+ dependencies << scenario.csv_file
170
+
171
+ # depends on the mapper classes
172
+ Dir.glob(File.join(scenario.mapper_files_dir, '*')).each do |f|
173
+ dependencies << f
174
+ end
175
+
176
+ # depends on the root gemfile
177
+ dependencies << File.join(scenario.root_dir, 'Gemfile')
178
+ dependencies << File.join(scenario.root_dir, 'Gemfile.lock')
179
+
180
+ # todo, read in the in.osw and depend on all the measures
181
+
182
+ # check if out of date
183
+ dependencies.each do |f|
184
+ if File.exist?(f)
185
+ if File.mtime(f) > out_osw_time
186
+ out_of_date_files << f
187
+ end
188
+ else
189
+ puts "Dependency file '#{f}' does not exist"
190
+ end
191
+ end
192
+
193
+ if !out_of_date_files.empty?
194
+ puts "Files [#{out_of_date_files.join(',')}] are newer than '#{out_osw_path}', simulation dir '#{run_dir}' out of date"
195
+ return true
196
+ end
197
+
198
+ return false
199
+ end
200
+ # rubocop: enable Metrics/AbcSize #:nodoc:
201
+
202
+ # rubocop: disable Style/GuardClause #:nodoc:
203
+
204
+ ##
205
+ # Return simulation status one of {'Not Started', 'Started', 'Complete', 'Failed'}
206
+ ##
207
+ def simulation_status
208
+ if File.exist?(failed_job_path)
209
+ return 'Failed'
210
+ elsif File.exist?(started_job_path)
211
+ if File.exist?(finished_job_path)
212
+ return 'Complete'
213
+ else
214
+ return 'Failed'
215
+ end
216
+ end
217
+
218
+ return 'Not Started'
219
+ end
220
+ # rubocop: enable Style/GuardClause #:nodoc:
221
+
222
+ ##
223
+ # Clear the directory that this simulation runs in
224
+ ##
225
+ def clear
226
+ dir = run_dir
227
+ FileUtils.mkdir_p(dir) if !File.exist?(dir)
228
+ Dir.glob(File.join(dir, '/*')).each do |f|
229
+ FileUtils.rm_rf(f)
230
+ end
231
+ end
232
+
233
+ # rubocop: disable Security/Eval #:nodoc:
234
+ # rubocop: disable Style/EvalWithLocation #:nodoc:
235
+
236
+ ##
237
+ # Create run directory and generate simulation OSW, all previous contents of directory are removed
238
+ # The simulation OSW is created by evaluating the mapper_class's create_osw method
239
+ ##
240
+ def create_input_files
241
+ clear
242
+
243
+ dir = run_dir
244
+ osw = eval("#{@mapper_class}.new.create_osw(scenario, features, feature_names)")
245
+ osw_path = File.join(dir, 'in.osw')
246
+ File.open(osw_path, 'w') do |f|
247
+ f << JSON.pretty_generate(osw)
248
+ # make sure data is written to the disk one way or the other
249
+ begin
250
+ f.fsync
251
+ rescue StandardError
252
+ f.flush
253
+ end
254
+ end
255
+ return osw_path
256
+ end
257
+ # rubocop: enable Security/Eval #:nodoc:
258
+ # rubocop: enable Style/EvalWithLocation #:nodoc:
259
+ end
260
+ end
261
+ end