openstudio-workflow 1.3.4 → 1.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +89 -77
- data/README.md +67 -93
- data/Rakefile +36 -36
- data/lib/openstudio-workflow.rb +65 -65
- data/lib/openstudio/workflow/adapters/input/local.rb +311 -324
- data/lib/openstudio/workflow/adapters/output/local.rb +158 -161
- data/lib/openstudio/workflow/adapters/output/socket.rb +106 -107
- data/lib/openstudio/workflow/adapters/output/web.rb +82 -82
- data/lib/openstudio/workflow/adapters/output_adapter.rb +163 -163
- data/lib/openstudio/workflow/job.rb +57 -57
- data/lib/openstudio/workflow/jobs/resources/monthly_report.idf +222 -222
- data/lib/openstudio/workflow/jobs/run_energyplus.rb +70 -70
- data/lib/openstudio/workflow/jobs/run_ep_measures.rb +73 -73
- data/lib/openstudio/workflow/jobs/run_initialization.rb +203 -203
- data/lib/openstudio/workflow/jobs/run_os_measures.rb +89 -89
- data/lib/openstudio/workflow/jobs/run_postprocess.rb +73 -73
- data/lib/openstudio/workflow/jobs/run_preprocess.rb +104 -104
- data/lib/openstudio/workflow/jobs/run_reporting_measures.rb +118 -118
- data/lib/openstudio/workflow/jobs/run_translation.rb +84 -84
- data/lib/openstudio/workflow/multi_delegator.rb +62 -62
- data/lib/openstudio/workflow/registry.rb +172 -172
- data/lib/openstudio/workflow/run.rb +342 -328
- data/lib/openstudio/workflow/time_logger.rb +96 -96
- data/lib/openstudio/workflow/util.rb +49 -49
- data/lib/openstudio/workflow/util/energyplus.rb +575 -605
- data/lib/openstudio/workflow/util/io.rb +68 -68
- data/lib/openstudio/workflow/util/measure.rb +658 -650
- data/lib/openstudio/workflow/util/model.rb +151 -151
- data/lib/openstudio/workflow/util/post_process.rb +235 -238
- data/lib/openstudio/workflow/util/weather_file.rb +143 -143
- data/lib/openstudio/workflow/version.rb +40 -40
- data/lib/openstudio/workflow_json.rb +475 -476
- data/lib/openstudio/workflow_runner.rb +263 -268
- metadata +24 -24
@@ -1,151 +1,151 @@
|
|
1
|
-
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) 2008-
|
3
|
-
# All rights reserved.
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are met:
|
6
|
-
#
|
7
|
-
# (1) Redistributions of source code must retain the above copyright notice,
|
8
|
-
# this list of conditions and the following disclaimer.
|
9
|
-
#
|
10
|
-
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
11
|
-
# this list of conditions and the following disclaimer in the documentation
|
12
|
-
# and/or other materials provided with the distribution.
|
13
|
-
#
|
14
|
-
# (3) Neither the name of the copyright holder nor the names of any contributors
|
15
|
-
# may be used to endorse or promote products derived from this software without
|
16
|
-
# specific prior written permission from the respective party.
|
17
|
-
#
|
18
|
-
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
19
|
-
# of modifications or other derivative works may not use the "OpenStudio"
|
20
|
-
# trademark, "OS", "os", or any other confusingly similar designation without
|
21
|
-
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
22
|
-
#
|
23
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24
|
-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25
|
-
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
-
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES
|
27
|
-
# GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
28
|
-
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
29
|
-
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
30
|
-
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
31
|
-
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
32
|
-
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
33
|
-
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
-
# *******************************************************************************
|
35
|
-
|
36
|
-
module OpenStudio
|
37
|
-
module Workflow
|
38
|
-
module Util
|
39
|
-
# Manages routine tasks involving OpenStudio::Model or OpenStudio::Workflow objects, such as loading, saving, and
|
40
|
-
# translating them.
|
41
|
-
#
|
42
|
-
module Model
|
43
|
-
# Method to create / load an OSM file
|
44
|
-
#
|
45
|
-
# @param [String] osm_path The full path to an OSM file to load
|
46
|
-
# @param [Object] logger An optional logger to use for finding the OSM model
|
47
|
-
# @return [Object] The return from this method is a loaded OSM or a failure.
|
48
|
-
#
|
49
|
-
def load_osm(osm_path, logger)
|
50
|
-
logger.info 'Loading OSM model'
|
51
|
-
|
52
|
-
# Load the model and return it
|
53
|
-
logger.info "Reading in OSM model #{osm_path}"
|
54
|
-
|
55
|
-
loaded_model = nil
|
56
|
-
begin
|
57
|
-
translator = OpenStudio::OSVersion::VersionTranslator.new
|
58
|
-
loaded_model = translator.loadModel(osm_path)
|
59
|
-
rescue
|
60
|
-
# TODO: get translator working in embedded.
|
61
|
-
# Need to embed idd files
|
62
|
-
logger.warn 'OpenStudio VersionTranslator could not be loaded'
|
63
|
-
loaded_model = OpenStudio::Model::Model.load(osm_path)
|
64
|
-
end
|
65
|
-
raise "Failed to load OSM file #{osm_path}" if loaded_model.empty?
|
66
|
-
loaded_model.get
|
67
|
-
end
|
68
|
-
|
69
|
-
# Method to create / load an IDF file
|
70
|
-
#
|
71
|
-
# @param [String] idf_path Full path to the IDF
|
72
|
-
# @param [Object] logger An optional logger to use for finding the idf model
|
73
|
-
# @return [Object] The return from this method is a loaded IDF or a failure.
|
74
|
-
#
|
75
|
-
def load_idf(idf_path, logger)
|
76
|
-
logger.info 'Loading IDF model'
|
77
|
-
|
78
|
-
# Load the IDF into a workspace object and return it
|
79
|
-
logger.info "Reading in IDF model #{idf_path}"
|
80
|
-
|
81
|
-
idf = OpenStudio::Workspace.load(idf_path)
|
82
|
-
raise "Failed to load IDF file #{idf_path}" if idf.empty?
|
83
|
-
idf.get
|
84
|
-
end
|
85
|
-
|
86
|
-
# Translates a OpenStudio model object into an OpenStudio IDF object
|
87
|
-
#
|
88
|
-
# @param [Object] model the OpenStudio::Model instance to translate into an OpenStudio::Workspace object -- see
|
89
|
-
# the OpenStudio SDK for details on the process
|
90
|
-
# @return [Object] Returns and OpenStudio::Workspace object
|
91
|
-
# @todo (rhorsey) rescue errors here
|
92
|
-
#
|
93
|
-
def translate_to_energyplus(model, logger = nil)
|
94
|
-
logger
|
95
|
-
logger.info 'Translate object to EnergyPlus IDF in preparation for EnergyPlus'
|
96
|
-
a = ::Time.now
|
97
|
-
# ensure objects exist for reporting purposes
|
98
|
-
model.getFacility
|
99
|
-
model.getBuilding
|
100
|
-
forward_translator = OpenStudio::EnergyPlus::ForwardTranslator.new
|
101
|
-
model_idf = forward_translator.translateModel(model)
|
102
|
-
b = ::Time.now
|
103
|
-
logger.info "Translate object to EnergyPlus IDF took #{b.to_f - a.to_f}"
|
104
|
-
model_idf
|
105
|
-
end
|
106
|
-
|
107
|
-
# Saves an OpenStudio model object to file
|
108
|
-
#
|
109
|
-
# @param [Object] model The OpenStudio::Model instance to save to file
|
110
|
-
# @param [String] save_directory Folder to save the model in
|
111
|
-
# @param [String] name ('in.osm') Option to define a non-standard name
|
112
|
-
# @return [String] OSM file name
|
113
|
-
#
|
114
|
-
def save_osm(model, save_directory, name = 'in.osm')
|
115
|
-
osm_filename = File.join(save_directory.to_s, name.to_s)
|
116
|
-
File.open(osm_filename, 'w') do |f|
|
117
|
-
f << model.to_s
|
118
|
-
# make sure data is written to the disk one way or the other
|
119
|
-
begin
|
120
|
-
f.fsync
|
121
|
-
rescue
|
122
|
-
f.flush
|
123
|
-
end
|
124
|
-
end
|
125
|
-
osm_filename
|
126
|
-
end
|
127
|
-
|
128
|
-
# Saves an OpenStudio IDF model object to file
|
129
|
-
#
|
130
|
-
# @param [Object] model The OpenStudio::Workspace instance to save to file
|
131
|
-
# @param [String] save_directory Folder to save the model in
|
132
|
-
# @param [String] name ('in.osm') Option to define a non-standard name
|
133
|
-
# @return [String] IDF file name
|
134
|
-
#
|
135
|
-
def save_idf(model_idf, save_directory, name = 'in.idf')
|
136
|
-
idf_filename = File.join(save_directory.to_s, name.to_s)
|
137
|
-
File.open(idf_filename, 'w') do |f|
|
138
|
-
f << model_idf.to_s
|
139
|
-
# make sure data is written to the disk one way or the other
|
140
|
-
begin
|
141
|
-
f.fsync
|
142
|
-
rescue
|
143
|
-
f.flush
|
144
|
-
end
|
145
|
-
end
|
146
|
-
idf_filename
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
|
3
|
+
# All rights reserved.
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# (1) Redistributions of source code must retain the above copyright notice,
|
8
|
+
# this list of conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
#
|
14
|
+
# (3) Neither the name of the copyright holder nor the names of any contributors
|
15
|
+
# may be used to endorse or promote products derived from this software without
|
16
|
+
# specific prior written permission from the respective party.
|
17
|
+
#
|
18
|
+
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
19
|
+
# of modifications or other derivative works may not use the "OpenStudio"
|
20
|
+
# trademark, "OS", "os", or any other confusingly similar designation without
|
21
|
+
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES
|
27
|
+
# GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
28
|
+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
29
|
+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
30
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
31
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
32
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
33
|
+
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
# *******************************************************************************
|
35
|
+
|
36
|
+
module OpenStudio
|
37
|
+
module Workflow
|
38
|
+
module Util
|
39
|
+
# Manages routine tasks involving OpenStudio::Model or OpenStudio::Workflow objects, such as loading, saving, and
|
40
|
+
# translating them.
|
41
|
+
#
|
42
|
+
module Model
|
43
|
+
# Method to create / load an OSM file
|
44
|
+
#
|
45
|
+
# @param [String] osm_path The full path to an OSM file to load
|
46
|
+
# @param [Object] logger An optional logger to use for finding the OSM model
|
47
|
+
# @return [Object] The return from this method is a loaded OSM or a failure.
|
48
|
+
#
|
49
|
+
def load_osm(osm_path, logger)
|
50
|
+
logger.info 'Loading OSM model'
|
51
|
+
|
52
|
+
# Load the model and return it
|
53
|
+
logger.info "Reading in OSM model #{osm_path}"
|
54
|
+
|
55
|
+
loaded_model = nil
|
56
|
+
begin
|
57
|
+
translator = OpenStudio::OSVersion::VersionTranslator.new
|
58
|
+
loaded_model = translator.loadModel(osm_path)
|
59
|
+
rescue StandardError
|
60
|
+
# TODO: get translator working in embedded.
|
61
|
+
# Need to embed idd files
|
62
|
+
logger.warn 'OpenStudio VersionTranslator could not be loaded'
|
63
|
+
loaded_model = OpenStudio::Model::Model.load(osm_path)
|
64
|
+
end
|
65
|
+
raise "Failed to load OSM file #{osm_path}" if loaded_model.empty?
|
66
|
+
loaded_model.get
|
67
|
+
end
|
68
|
+
|
69
|
+
# Method to create / load an IDF file
|
70
|
+
#
|
71
|
+
# @param [String] idf_path Full path to the IDF
|
72
|
+
# @param [Object] logger An optional logger to use for finding the idf model
|
73
|
+
# @return [Object] The return from this method is a loaded IDF or a failure.
|
74
|
+
#
|
75
|
+
def load_idf(idf_path, logger)
|
76
|
+
logger.info 'Loading IDF model'
|
77
|
+
|
78
|
+
# Load the IDF into a workspace object and return it
|
79
|
+
logger.info "Reading in IDF model #{idf_path}"
|
80
|
+
|
81
|
+
idf = OpenStudio::Workspace.load(idf_path)
|
82
|
+
raise "Failed to load IDF file #{idf_path}" if idf.empty?
|
83
|
+
idf.get
|
84
|
+
end
|
85
|
+
|
86
|
+
# Translates a OpenStudio model object into an OpenStudio IDF object
|
87
|
+
#
|
88
|
+
# @param [Object] model the OpenStudio::Model instance to translate into an OpenStudio::Workspace object -- see
|
89
|
+
# the OpenStudio SDK for details on the process
|
90
|
+
# @return [Object] Returns and OpenStudio::Workspace object
|
91
|
+
# @todo (rhorsey) rescue errors here
|
92
|
+
#
|
93
|
+
def translate_to_energyplus(model, logger = nil)
|
94
|
+
logger ||= ::Logger.new(STDOUT)
|
95
|
+
logger.info 'Translate object to EnergyPlus IDF in preparation for EnergyPlus'
|
96
|
+
a = ::Time.now
|
97
|
+
# ensure objects exist for reporting purposes
|
98
|
+
model.getFacility
|
99
|
+
model.getBuilding
|
100
|
+
forward_translator = OpenStudio::EnergyPlus::ForwardTranslator.new
|
101
|
+
model_idf = forward_translator.translateModel(model)
|
102
|
+
b = ::Time.now
|
103
|
+
logger.info "Translate object to EnergyPlus IDF took #{b.to_f - a.to_f}"
|
104
|
+
model_idf
|
105
|
+
end
|
106
|
+
|
107
|
+
# Saves an OpenStudio model object to file
|
108
|
+
#
|
109
|
+
# @param [Object] model The OpenStudio::Model instance to save to file
|
110
|
+
# @param [String] save_directory Folder to save the model in
|
111
|
+
# @param [String] name ('in.osm') Option to define a non-standard name
|
112
|
+
# @return [String] OSM file name
|
113
|
+
#
|
114
|
+
def save_osm(model, save_directory, name = 'in.osm')
|
115
|
+
osm_filename = File.join(save_directory.to_s, name.to_s)
|
116
|
+
File.open(osm_filename, 'w') do |f|
|
117
|
+
f << model.to_s
|
118
|
+
# make sure data is written to the disk one way or the other
|
119
|
+
begin
|
120
|
+
f.fsync
|
121
|
+
rescue StandardError
|
122
|
+
f.flush
|
123
|
+
end
|
124
|
+
end
|
125
|
+
osm_filename
|
126
|
+
end
|
127
|
+
|
128
|
+
# Saves an OpenStudio IDF model object to file
|
129
|
+
#
|
130
|
+
# @param [Object] model The OpenStudio::Workspace instance to save to file
|
131
|
+
# @param [String] save_directory Folder to save the model in
|
132
|
+
# @param [String] name ('in.osm') Option to define a non-standard name
|
133
|
+
# @return [String] IDF file name
|
134
|
+
#
|
135
|
+
def save_idf(model_idf, save_directory, name = 'in.idf')
|
136
|
+
idf_filename = File.join(save_directory.to_s, name.to_s)
|
137
|
+
File.open(idf_filename, 'w') do |f|
|
138
|
+
f << model_idf.to_s
|
139
|
+
# make sure data is written to the disk one way or the other
|
140
|
+
begin
|
141
|
+
f.fsync
|
142
|
+
rescue StandardError
|
143
|
+
f.flush
|
144
|
+
end
|
145
|
+
end
|
146
|
+
idf_filename
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -1,238 +1,235 @@
|
|
1
|
-
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) 2008-
|
3
|
-
# All rights reserved.
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are met:
|
6
|
-
#
|
7
|
-
# (1) Redistributions of source code must retain the above copyright notice,
|
8
|
-
# this list of conditions and the following disclaimer.
|
9
|
-
#
|
10
|
-
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
11
|
-
# this list of conditions and the following disclaimer in the documentation
|
12
|
-
# and/or other materials provided with the distribution.
|
13
|
-
#
|
14
|
-
# (3) Neither the name of the copyright holder nor the names of any contributors
|
15
|
-
# may be used to endorse or promote products derived from this software without
|
16
|
-
# specific prior written permission from the respective party.
|
17
|
-
#
|
18
|
-
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
19
|
-
# of modifications or other derivative works may not use the "OpenStudio"
|
20
|
-
# trademark, "OS", "os", or any other confusingly similar designation without
|
21
|
-
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
22
|
-
#
|
23
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24
|
-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25
|
-
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
-
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES
|
27
|
-
# GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
28
|
-
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
29
|
-
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
30
|
-
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
31
|
-
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
32
|
-
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
33
|
-
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
-
# *******************************************************************************
|
35
|
-
|
36
|
-
module OpenStudio
|
37
|
-
module Workflow
|
38
|
-
module Util
|
39
|
-
require 'openstudio/workflow/util/measure'
|
40
|
-
require 'csv'
|
41
|
-
|
42
|
-
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
#
|
50
|
-
#
|
51
|
-
# @
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
#
|
60
|
-
#
|
61
|
-
# @
|
62
|
-
# @
|
63
|
-
#
|
64
|
-
|
65
|
-
|
66
|
-
#
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
h =
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
analysis_json
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
objective_functions["
|
118
|
-
objective_functions["
|
119
|
-
objective_functions["
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
# @param [
|
135
|
-
#
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
#
|
159
|
-
#
|
160
|
-
# @param [String]
|
161
|
-
#
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
html
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
f.
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
measure_xml = REXML::Document.new File.read(measure_xml_path)
|
197
|
-
measure_class_name = OpenStudio.toUnderscoreCase(measure_xml.root.elements['class_name'].text)
|
198
|
-
else
|
199
|
-
measure_class_name = OpenStudio.toUnderscoreCase(measure_dir_name)
|
200
|
-
end
|
201
|
-
file_ext = File.extname(report)
|
202
|
-
append_str = File.basename(report, '.*')
|
203
|
-
new_file_name = "#{directory}/reports/#{measure_class_name}_#{append_str}#{file_ext}"
|
204
|
-
logger.info "Saving report #{report} to #{new_file_name}"
|
205
|
-
FileUtils.copy report, new_file_name
|
206
|
-
end
|
207
|
-
|
208
|
-
# Remove empty directories in run folder
|
209
|
-
Dir["#{run_dir}/*"].select { |d| File.directory? d }.select { |d| (Dir.entries(d) -
|
210
|
-
logger.info "Removing empty directory #{d}"
|
211
|
-
Dir.rmdir d
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
|
216
|
-
#
|
217
|
-
#
|
218
|
-
#
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
paths_to_rm
|
224
|
-
# paths_to_rm << Pathname.glob("
|
225
|
-
# paths_to_rm << Pathname.glob("#{run_dir}/*.
|
226
|
-
|
227
|
-
|
228
|
-
# paths_to_rm << Pathname.glob("#{run_dir}/*.
|
229
|
-
paths_to_rm << Pathname.glob("#{run_dir}/*.
|
230
|
-
paths_to_rm
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
end
|
237
|
-
end
|
238
|
-
end
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
|
3
|
+
# All rights reserved.
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# (1) Redistributions of source code must retain the above copyright notice,
|
8
|
+
# this list of conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
#
|
14
|
+
# (3) Neither the name of the copyright holder nor the names of any contributors
|
15
|
+
# may be used to endorse or promote products derived from this software without
|
16
|
+
# specific prior written permission from the respective party.
|
17
|
+
#
|
18
|
+
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
19
|
+
# of modifications or other derivative works may not use the "OpenStudio"
|
20
|
+
# trademark, "OS", "os", or any other confusingly similar designation without
|
21
|
+
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES
|
27
|
+
# GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
28
|
+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
29
|
+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
30
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
31
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
32
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
33
|
+
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
# *******************************************************************************
|
35
|
+
|
36
|
+
module OpenStudio
|
37
|
+
module Workflow
|
38
|
+
module Util
|
39
|
+
require 'openstudio/workflow/util/measure'
|
40
|
+
require 'csv'
|
41
|
+
|
42
|
+
# This module serves as a wrapper around various post-processing tasks used to manage outputs
|
43
|
+
# @todo (rhorsey) ummmm. So some of this is pretty ugly. Since @dmacumber had ideas about this maybe he can figure
|
44
|
+
# out what to do about it all
|
45
|
+
# @todo (nlong) the output adapter restructure will frack up the extraction method royally
|
46
|
+
#
|
47
|
+
module PostProcess
|
48
|
+
# This method loads a sql file into OpenStudio and returns it
|
49
|
+
#
|
50
|
+
# @param [String] sql_file Absolute path to the sql file to be loaded
|
51
|
+
# @return [Object, nil] The OpenStudio::SqlFile object, or nil if it could not be found
|
52
|
+
#
|
53
|
+
def load_sql_file(sql_file)
|
54
|
+
return nil unless File.exist? sql_file
|
55
|
+
OpenStudio::SqlFile.new(@sql_filename)
|
56
|
+
end
|
57
|
+
|
58
|
+
# This method parses all sorts of stuff which something needs
|
59
|
+
#
|
60
|
+
# @param [String] run_dir The directory that the simulation was run in
|
61
|
+
# @return [Hash, Hash] results and objective_function (which may be empty) are returned
|
62
|
+
# @todo (rhorsey) fix the description
|
63
|
+
#
|
64
|
+
def run_extract_inputs_and_outputs(run_dir, logger)
|
65
|
+
# For xml, the measure attributes are in the measure_attributes_xml.json file
|
66
|
+
# TODO: somehow pass the metadata around on which JSONs to suck into the database
|
67
|
+
results = {}
|
68
|
+
# Inputs are in the measure_attributes.json file
|
69
|
+
if File.exist? "#{run_dir}/measure_attributes.json"
|
70
|
+
h = JSON.parse(File.read("#{run_dir}/measure_attributes.json"), symbolize_names: true)
|
71
|
+
h = rename_hash_keys(h, logger)
|
72
|
+
results.merge! h
|
73
|
+
end
|
74
|
+
|
75
|
+
logger.info 'Saving the result hash to file'
|
76
|
+
File.open("#{run_dir}/results.json", 'w') do |f|
|
77
|
+
f << JSON.pretty_generate(results)
|
78
|
+
# make sure data is written to the disk one way or the other
|
79
|
+
begin
|
80
|
+
f.fsync
|
81
|
+
rescue StandardError
|
82
|
+
f.flush
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
objective_functions = {}
|
87
|
+
if @registry[:analysis]
|
88
|
+
logger.info 'Iterating over Analysis JSON Output Variables'
|
89
|
+
# Save the objective functions to the object for sending back to the simulation executive
|
90
|
+
analysis_json = @registry[:analysis]
|
91
|
+
if analysis_json[:analysis] && analysis_json[:analysis][:output_variables]
|
92
|
+
analysis_json[:analysis][:output_variables].each do |variable|
|
93
|
+
# determine which ones are the objective functions (code smell: todo: use enumerator)
|
94
|
+
if variable[:objective_function]
|
95
|
+
logger.info "Looking for objective function #{variable[:name]}"
|
96
|
+
# TODO: move this to cleaner logic. Use ostruct?
|
97
|
+
k, v = variable[:name].split('.')
|
98
|
+
|
99
|
+
# look for the objective function key and make sure that it is not nil. False is an okay obj function.
|
100
|
+
if results.key?(k.to_sym) && !results[k.to_sym][v.to_sym].nil?
|
101
|
+
objective_functions["objective_function_#{variable[:objective_function_index] + 1}"] = results[k.to_sym][v.to_sym]
|
102
|
+
if variable[:objective_function_target]
|
103
|
+
logger.info "Found objective function target for #{variable[:name]}"
|
104
|
+
objective_functions["objective_function_target_#{variable[:objective_function_index] + 1}"] = variable[:objective_function_target].to_f
|
105
|
+
end
|
106
|
+
if variable[:scaling_factor]
|
107
|
+
logger.info "Found scaling factor for #{variable[:name]}"
|
108
|
+
objective_functions["scaling_factor_#{variable[:objective_function_index] + 1}"] = variable[:scaling_factor].to_f
|
109
|
+
end
|
110
|
+
if variable[:objective_function_group]
|
111
|
+
logger.info "Found objective function group for #{variable[:name]}"
|
112
|
+
objective_functions["objective_function_group_#{variable[:objective_function_index] + 1}"] = variable[:objective_function_group].to_f
|
113
|
+
end
|
114
|
+
else
|
115
|
+
logger.warn "No results for objective function #{variable[:name]}"
|
116
|
+
objective_functions["objective_function_#{variable[:objective_function_index] + 1}"] = Float::MAX
|
117
|
+
objective_functions["objective_function_target_#{variable[:objective_function_index] + 1}"] = nil
|
118
|
+
objective_functions["scaling_factor_#{variable[:objective_function_index] + 1}"] = nil
|
119
|
+
objective_functions["objective_function_group_#{variable[:objective_function_index] + 1}"] = nil
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
return results, objective_functions
|
127
|
+
end
|
128
|
+
|
129
|
+
# Remove any invalid characters in the measure attribute keys. Periods and Pipes are the most problematic
|
130
|
+
# because mongo does not allow hash keys with periods, and the pipes are used in the map/reduce method that
|
131
|
+
# was written to speed up the data write in openstudio-server. Also remove any trailing underscores and spaces
|
132
|
+
#
|
133
|
+
# @param [Hash] hash Any hash with potentially problematic characters
|
134
|
+
# @param [Logger] logger Logger to write to
|
135
|
+
#
|
136
|
+
def rename_hash_keys(hash, logger)
|
137
|
+
# @todo should we log the name changes?
|
138
|
+
regex = /[|!@#\$%^&\*\(\)\{\}\\\[\];:'",<.>\/?\+=]+/
|
139
|
+
|
140
|
+
rename_keys = lambda do |h|
|
141
|
+
if Hash === h
|
142
|
+
h.each_key do |key|
|
143
|
+
if key.to_s =~ regex
|
144
|
+
logger.warn "Renaming result key '#{key}' to remove invalid characters"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
Hash[h.map { |k, v| [k.to_s.gsub(regex, '_').squeeze('_').gsub(/[_\s]+$/, '').chomp.to_sym, rename_keys[v]] }]
|
148
|
+
else
|
149
|
+
h
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
rename_keys[hash]
|
154
|
+
end
|
155
|
+
|
156
|
+
# Save reports to a common directory
|
157
|
+
#
|
158
|
+
# @param [String] run_dir
|
159
|
+
# @param [String] directory
|
160
|
+
# @param [String] logger
|
161
|
+
#
|
162
|
+
def gather_reports(run_dir, directory, workflow_json, logger)
|
163
|
+
logger.info run_dir
|
164
|
+
logger.info directory
|
165
|
+
|
166
|
+
FileUtils.mkdir_p "#{directory}/reports"
|
167
|
+
|
168
|
+
# try to find the energyplus result file
|
169
|
+
eplus_html = "#{run_dir}/eplustbl.htm"
|
170
|
+
if File.exist? eplus_html
|
171
|
+
# do some encoding on the html if possible
|
172
|
+
html = File.read(eplus_html)
|
173
|
+
html = html.force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
|
174
|
+
logger.info "Saving EnergyPlus HTML report to #{directory}/reports/eplustbl.html"
|
175
|
+
File.open("#{directory}/reports/eplustbl.html", 'w') do |f|
|
176
|
+
f << html
|
177
|
+
# make sure data is written to the disk one way or the other
|
178
|
+
begin
|
179
|
+
f.fsync
|
180
|
+
rescue StandardError
|
181
|
+
f.flush
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Also, find any "report*.*" files
|
187
|
+
Dir["#{run_dir}/*/report*.*"].each do |report|
|
188
|
+
# HRH: This is a temporary work-around to support PAT 2.1 pretty names AND the CLI while we roll a WorkflowJSON solution
|
189
|
+
measure_dir_name = File.dirname(report).split(File::SEPARATOR).last.gsub(/[0-9][0-9][0-9]_/, '')
|
190
|
+
measure_xml_path = File.absolute_path(File.join(File.dirname(report), '../../..', 'measures',
|
191
|
+
measure_dir_name, 'measure.xml'))
|
192
|
+
logger.info "measure_xml_path: #{measure_xml_path}"
|
193
|
+
if File.exist? measure_xml_path
|
194
|
+
# REXML is slow, so we lazy load only as needed
|
195
|
+
require 'rexml/document'
|
196
|
+
measure_xml = REXML::Document.new File.read(measure_xml_path)
|
197
|
+
measure_class_name = OpenStudio.toUnderscoreCase(measure_xml.root.elements['class_name'].text)
|
198
|
+
else
|
199
|
+
measure_class_name = OpenStudio.toUnderscoreCase(measure_dir_name)
|
200
|
+
end
|
201
|
+
file_ext = File.extname(report)
|
202
|
+
append_str = File.basename(report, '.*')
|
203
|
+
new_file_name = "#{directory}/reports/#{measure_class_name}_#{append_str}#{file_ext}"
|
204
|
+
logger.info "Saving report #{report} to #{new_file_name}"
|
205
|
+
FileUtils.copy report, new_file_name
|
206
|
+
end
|
207
|
+
|
208
|
+
# Remove empty directories in run folder
|
209
|
+
Dir["#{run_dir}/*"].select { |d| File.directory? d }.select { |d| (Dir.entries(d) - ['.', '..']).empty? }.each do |d|
|
210
|
+
logger.info "Removing empty directory #{d}"
|
211
|
+
Dir.rmdir d
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# A general post-processing step which could be made significantly more modular
|
216
|
+
#
|
217
|
+
# @param [String] run_dir
|
218
|
+
#
|
219
|
+
def cleanup(run_dir, directory, logger)
|
220
|
+
paths_to_rm = []
|
221
|
+
# paths_to_rm << Pathname.glob("#{run_dir}/*.osm")
|
222
|
+
# paths_to_rm << Pathname.glob("#{run_dir}/*.idf") # keep the idfs
|
223
|
+
# paths_to_rm << Pathname.glob("*.audit")
|
224
|
+
# paths_to_rm << Pathname.glob("*.bnd")
|
225
|
+
# paths_to_rm << Pathname.glob("#{run_dir}/*.eso")
|
226
|
+
paths_to_rm << Pathname.glob("#{run_dir}/*.mtr")
|
227
|
+
paths_to_rm << Pathname.glob("#{run_dir}/*.epw")
|
228
|
+
# paths_to_rm << Pathname.glob("#{run_dir}/*.mtd")
|
229
|
+
# paths_to_rm << Pathname.glob("#{run_dir}/*.rdd")
|
230
|
+
paths_to_rm.each { |p| FileUtils.rm_rf(p) }
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|