openstudio-workflow 0.0.1 → 0.0.2

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 (24) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/README.md +39 -2
  4. data/Rakefile +12 -1
  5. data/lib/openstudio-workflow.rb +31 -4
  6. data/lib/openstudio/workflow/adapter.rb +8 -9
  7. data/lib/openstudio/workflow/adapters/local.rb +35 -22
  8. data/lib/openstudio/workflow/adapters/mongo.rb +82 -92
  9. data/lib/openstudio/workflow/jobs/lib/apply_measures.rb +229 -0
  10. data/lib/openstudio/workflow/jobs/run_energyplus/run_energyplus.rb +7 -10
  11. data/lib/openstudio/workflow/jobs/run_openstudio/run_openstudio.rb +37 -159
  12. data/lib/openstudio/workflow/jobs/run_postprocess/run_postprocess.rb +53 -492
  13. data/lib/openstudio/workflow/jobs/run_preflight/run_preflight.rb +1 -5
  14. data/lib/openstudio/workflow/jobs/{run_postprocess → run_reporting_measures}/packaged_measures/README.md +0 -0
  15. data/lib/openstudio/workflow/jobs/{run_postprocess → run_reporting_measures}/packaged_measures/StandardReports/measure.rb +81 -87
  16. data/lib/openstudio/workflow/jobs/{run_postprocess → run_reporting_measures}/packaged_measures/StandardReports/measure.xml +1 -1
  17. data/lib/openstudio/workflow/jobs/{run_postprocess/packaged_measures/StandardReports/resources/report.html.in → run_reporting_measures/packaged_measures/StandardReports/resources/report.html.erb} +0 -0
  18. data/lib/openstudio/workflow/jobs/run_reporting_measures/run_reporting_measures.rb +548 -0
  19. data/lib/openstudio/workflow/jobs/run_runmanager/run_runmanager.rb +226 -0
  20. data/lib/openstudio/workflow/jobs/run_xml/run_xml.rb +39 -41
  21. data/lib/openstudio/workflow/multi_delegator.rb +6 -6
  22. data/lib/openstudio/workflow/run.rb +95 -39
  23. data/lib/openstudio/workflow/version.rb +1 -1
  24. metadata +9 -6
@@ -17,10 +17,8 @@
17
17
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
  ######################################################################
19
19
 
20
-
21
20
  # Run Prelight job to prepare the directory for simulations.
22
21
  class RunPreflight
23
-
24
22
  def initialize(directory, logger, adapter, options = {})
25
23
  defaults = {}
26
24
  @options = defaults.merge(options)
@@ -28,13 +26,11 @@ class RunPreflight
28
26
  @adapter = adapter
29
27
  @results = {}
30
28
  @logger = logger
31
-
32
29
  end
33
30
 
34
31
  def perform
35
32
  @logger.info "Calling #{__method__} in the #{self.class} class"
36
33
 
37
-
38
34
  @adapter.communicate_started @directory, @options
39
35
 
40
36
  # Add the moment this does nothing.
@@ -42,4 +38,4 @@ class RunPreflight
42
38
  # return the results back to the caller--always
43
39
  @results
44
40
  end
45
- end
41
+ end
@@ -1,91 +1,90 @@
1
1
  require 'erb'
2
+ require 'fileutils'
2
3
 
3
- #start the measure
4
+ # start the measure
4
5
  class StandardReports < OpenStudio::Ruleset::ReportingUserScript
5
-
6
- #define the name that a user will see, this method may be deprecated as
7
- #the display name in PAT comes from the name field in measure.xml
6
+ # define the name that a user will see, this method may be deprecated as
7
+ # the display name in PAT comes from the name field in measure.xml
8
8
  def name
9
- return "Standard Reports"
9
+ 'Standard Reports'
10
10
  end
11
11
 
12
- #define the arguments that the user will input
13
- def arguments()
12
+ # define the arguments that the user will input
13
+ def arguments
14
14
  args = OpenStudio::Ruleset::OSArgumentVector.new
15
15
 
16
- return args
17
- end #end the arguments method
16
+ args
17
+ end # end the arguments method
18
18
 
19
- #sql_query method
19
+ # sql_query method
20
20
  def sql_query(sql, report_name, query)
21
21
  val = 10e9
22
22
  result = sql.execAndReturnFirstDouble("SELECT Value FROM TabularDataWithStrings WHERE ReportName='#{report_name}' AND #{query}")
23
- if not result.empty?
23
+ unless result.empty?
24
24
  val = result.get
25
25
  end
26
- return val
26
+ val
27
27
  end
28
28
 
29
- #define what happens when the measure is run
29
+ # define what happens when the measure is run
30
30
  def run(runner, user_arguments)
31
31
  super(runner, user_arguments)
32
32
 
33
- #use the built-in error checking
34
- if not runner.validateUserArguments(arguments(), user_arguments)
33
+ # use the built-in error checking
34
+ unless runner.validateUserArguments(arguments, user_arguments)
35
35
  return false
36
36
  end
37
-
38
- os_version = OpenStudio::VersionString.new(OpenStudio::openStudioVersion())
39
- min_version_feature1 = OpenStudio::VersionString.new("1.2.3")
40
37
 
41
- # get the last model and sql file
38
+ os_version = OpenStudio::VersionString.new(OpenStudio.openStudioVersion)
39
+ min_version_feature1 = OpenStudio::VersionString.new('1.2.3')
42
40
 
41
+ # get the last model and sql file
43
42
  model = runner.lastOpenStudioModel
44
43
  if model.empty?
45
- runner.registerError("Cannot find last model.")
44
+ runner.registerError('Cannot find last model.')
46
45
  return false
47
46
  end
48
47
  model = model.get
49
48
 
50
49
  sqlFile = runner.lastEnergyPlusSqlFile
51
50
  if sqlFile.empty?
52
- runner.registerError("Cannot find last sql file.")
51
+ runner.registerError('Cannot find last sql file.')
53
52
  return false
54
53
  end
55
54
  sqlFile = sqlFile.get
56
55
  model.setSqlFile(sqlFile)
57
56
 
58
57
  # put data into variables, these are available in the local scope binding
59
- #building_name = model.getBuilding.name.get
58
+ # building_name = model.getBuilding.name.get
60
59
 
61
- web_asset_path = OpenStudio::getSharedResourcesPath() / OpenStudio::Path.new("web_assets")
60
+ web_asset_path = OpenStudio.getSharedResourcesPath / OpenStudio::Path.new('web_assets')
62
61
 
63
62
  energy = "var consumption = {\n"
64
- fuel_type = ""
65
- units = ""
63
+ fuel_type = ''
64
+ units = ''
66
65
 
67
66
  site_energy_use = 0.0
68
- OpenStudio::EndUseFuelType::getValues.each do |fuel_type|
67
+ OpenStudio::EndUseFuelType.getValues.each do |fuel_type|
69
68
  energy << "\t\""
70
69
  fuel_type = OpenStudio::EndUseFuelType.new(fuel_type).valueDescription
71
70
  energy << OpenStudio::EndUseFuelType.new(fuel_type).valueDescription # append this to remove whitespace between words ".delete(' ')"
72
71
  energy << " Consumption\":{\n\t\t\"units\":"
73
- if fuel_type == "Electricity"
72
+ if fuel_type == 'Electricity'
74
73
  units = "\"kWh\""
75
- unit_str = "kWh"
74
+ unit_str = 'kWh'
76
75
  else
77
76
  units = "\"Million Btu\""
78
- unit_str = "MBtu"
77
+ unit_str = 'MBtu'
79
78
  end
80
79
  fuel_type_aggregation = 0.0
81
80
  energy << units
82
81
  energy << ",\n\t\t\"data\":{\n\t\t\t\""
83
- OpenStudio::EndUseCategoryType::getValues.each do |category_type|
82
+ OpenStudio::EndUseCategoryType.getValues.each do |category_type|
84
83
  fuel_and_category_aggregation = 0.0
85
84
  category_str = OpenStudio::EndUseCategoryType.new(category_type).valueDescription
86
85
  energy << category_str # append this to remove whitespace between words ".delete(' ')"
87
86
  energy << "\":["
88
- OpenStudio::MonthOfYear::getValues.each do |month|
87
+ OpenStudio::MonthOfYear.getValues.each do |month|
89
88
  if month >= 1 and month <= 12
90
89
  if not sqlFile.energyConsumptionByMonth(OpenStudio::EndUseFuelType.new(fuel_type),
91
90
  OpenStudio::EndUseCategoryType.new(category_type),
@@ -94,36 +93,36 @@ class StandardReports < OpenStudio::Ruleset::ReportingUserScript
94
93
  OpenStudio::EndUseCategoryType.new(category_type),
95
94
  OpenStudio::MonthOfYear.new(month)).get
96
95
  fuel_and_category_aggregation += valInJ
97
- valInUnits = OpenStudio::convert(valInJ,"J",unit_str).get()
98
- temp = sprintf "%.3f", valInUnits
96
+ valInUnits = OpenStudio.convert(valInJ, 'J', unit_str).get
97
+ temp = sprintf '%.3f', valInUnits
99
98
  energy << temp.to_s
100
- energy << ","
99
+ energy << ','
101
100
  if os_version >= min_version_feature1
102
101
  month_str = OpenStudio::MonthOfYear.new(month).valueDescription
103
- prefix_str = OpenStudio::toUnderscoreCase("#{fuel_type}_#{category_str}_#{month_str}")
104
- runner.registerValue("#{prefix_str}_si",valInJ,"J")
105
- runner.registerValue("#{prefix_str}_ip",valInUnits,unit_str)
102
+ prefix_str = OpenStudio.toUnderscoreCase("#{fuel_type}_#{category_str}_#{month_str}")
103
+ runner.registerValue("#{prefix_str}_si", valInJ, 'J')
104
+ runner.registerValue("#{prefix_str}_ip", valInUnits, unit_str)
106
105
  end
107
106
  else
108
- energy << "0,"
107
+ energy << '0,'
109
108
  end
110
109
  end
111
110
  end
112
111
  energy = energy[0..-2]
113
112
  energy << "],\n\t\t\t\""
114
- if (os_version >= min_version_feature1)
115
- prefix_str = OpenStudio::toUnderscoreCase("#{fuel_type}_#{category_str}")
116
- runner.registerValue("#{prefix_str}_si",fuel_and_category_aggregation,"J")
117
- runner.registerValue("#{prefix_str}_ip",OpenStudio::convert(fuel_and_category_aggregation,"J",unit_str).get,unit_str)
113
+ if (os_version >= min_version_feature1)
114
+ prefix_str = OpenStudio.toUnderscoreCase("#{fuel_type}_#{category_str}")
115
+ runner.registerValue("#{prefix_str}_si", fuel_and_category_aggregation, 'J')
116
+ runner.registerValue("#{prefix_str}_ip", OpenStudio.convert(fuel_and_category_aggregation, 'J', unit_str).get, unit_str)
118
117
  end
119
118
  fuel_type_aggregation += fuel_and_category_aggregation
120
119
  end
121
120
  energy = energy[0..-7]
122
121
  energy << "\n\t\t}\n\t},\n"
123
122
  if (os_version >= min_version_feature1)
124
- runner.registerValue(OpenStudio::toUnderscoreCase("#{fuel_type}_si"),fuel_type_aggregation,"J")
125
- runner.registerValue(OpenStudio::toUnderscoreCase("#{fuel_type}_ip"),
126
- OpenStudio::convert(fuel_type_aggregation,"J",unit_str).get,
123
+ runner.registerValue(OpenStudio.toUnderscoreCase("#{fuel_type}_si"), fuel_type_aggregation, 'J')
124
+ runner.registerValue(OpenStudio.toUnderscoreCase("#{fuel_type}_ip"),
125
+ OpenStudio.convert(fuel_type_aggregation, 'J', unit_str).get,
127
126
  unit_str)
128
127
  end
129
128
  site_energy_use += fuel_type_aggregation
@@ -131,64 +130,61 @@ class StandardReports < OpenStudio::Ruleset::ReportingUserScript
131
130
  energy = energy[0..-3]
132
131
  energy << "\n};\n"
133
132
  if (os_version >= min_version_feature1)
134
- runner.registerValue("site_energy_use_si",OpenStudio::convert(site_energy_use,"J","GJ").get,"GJ")
135
- runner.registerValue("site_energy_use_ip",OpenStudio::convert(site_energy_use,"J","MBtu").get,"MBtu")
136
-
137
- # queries that don't have API methods yet
133
+ runner.registerValue('site_energy_use_si', OpenStudio.convert(site_energy_use, 'J', 'GJ').get, 'GJ')
134
+ runner.registerValue('site_energy_use_ip', OpenStudio.convert(site_energy_use, 'J', 'MBtu').get, 'MBtu')
135
+
136
+ # queries that don't have API methods yet
138
137
  total_building_area = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Building Area' AND RowName='Total Building Area' AND ColumnName='Area'")
139
- runner.registerValue("total_building_area",total_building_area,"m2")
140
-
138
+ runner.registerValue('total_building_area', total_building_area, 'm2')
139
+
141
140
  net_conditioned_building_area = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Building Area' AND RowName='Net Conditioned Building Area' AND ColumnName='Area'")
142
- runner.registerValue("net_conditioned_building_area",net_conditioned_building_area,"m2")
143
-
141
+ runner.registerValue('net_conditioned_building_area', net_conditioned_building_area, 'm2')
142
+
144
143
  unconditioned_building_area = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Building Area' AND RowName='Unconditioned Building Area' AND ColumnName='Area'")
145
- runner.registerValue("unconditioned_building_area",unconditioned_building_area,"m2")
146
-
144
+ runner.registerValue('unconditioned_building_area', unconditioned_building_area, 'm2')
145
+
147
146
  total_site_energy_eui = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Site and Source Energy' AND RowName='Total Site Energy' AND ColumnName='Energy Per Conditioned Building Area'")
148
- runner.registerValue("total_site_energy_eui",total_site_energy_eui,"MJ/m2")
147
+ runner.registerValue('total_site_energy_eui', total_site_energy_eui, 'MJ/m2')
149
148
 
150
149
  total_source_energy_eui = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Site and Source Energy' AND RowName='Total Source Energy' AND ColumnName='Energy Per Conditioned Building Area'")
151
- runner.registerValue("total_source_energy_eui",total_source_energy_eui,"MJ/m2")
152
-
150
+ runner.registerValue('total_source_energy_eui', total_source_energy_eui, 'MJ/m2')
151
+
153
152
  time_setpoint_not_met_during_occupied_heating = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Comfort and Setpoint Not Met Summary' AND RowName='Time Setpoint Not Met During Occupied Heating' AND ColumnName='Facility'")
154
- runner.registerValue("time_setpoint_not_met_during_occupied_heating",time_setpoint_not_met_during_occupied_heating,"hr")
153
+ runner.registerValue('time_setpoint_not_met_during_occupied_heating', time_setpoint_not_met_during_occupied_heating, 'hr')
155
154
 
156
155
  time_setpoint_not_met_during_occupied_cooling = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Comfort and Setpoint Not Met Summary' AND RowName='Time Setpoint Not Met During Occupied Cooling' AND ColumnName='Facility'")
157
- runner.registerValue("time_setpoint_not_met_during_occupied_cooling",time_setpoint_not_met_during_occupied_cooling,"hr")
158
-
156
+ runner.registerValue('time_setpoint_not_met_during_occupied_cooling', time_setpoint_not_met_during_occupied_cooling, 'hr')
157
+
159
158
  time_setpoint_not_met_during_occupied_hours = time_setpoint_not_met_during_occupied_heating + time_setpoint_not_met_during_occupied_cooling
160
- runner.registerValue("time_setpoint_not_met_during_occupied_hours",time_setpoint_not_met_during_occupied_hours,"hr")
161
-
159
+ runner.registerValue('time_setpoint_not_met_during_occupied_hours', time_setpoint_not_met_during_occupied_hours, 'hr')
160
+
162
161
  total_life_cycle_cost = sql_query(sqlFile, 'Life-Cycle Cost Report', "TableName='Present Value by Category' AND RowName='Grand Total' AND ColumnName='Present Value'")
163
- runner.registerValue("total_life_cycle_cost",total_life_cycle_cost,"$")
164
-
162
+ runner.registerValue('total_life_cycle_cost', total_life_cycle_cost, '$')
163
+
165
164
  end
166
165
 
167
166
  # echo out our values
168
- #runner.registerInfo("This building is named #{building_name}.")
167
+ # runner.registerInfo("This building is named #{building_name}.")
169
168
 
170
169
  # read in template
171
- html_in_path = "#{File.dirname(__FILE__)}/resources/report.html.in"
170
+ html_in_path = "#{File.dirname(__FILE__)}/resources/report.html.erb"
172
171
  if File.exist?(html_in_path)
173
- html_in_path = html_in_path
172
+ html_in_path = html_in_path
174
173
  else
175
- html_in_path = "#{File.dirname(__FILE__)}/report.html.in"
176
- end
177
- html_in = ""
178
- File.open(html_in_path, 'r') do |file|
179
- html_in = file.read
174
+ html_in_path = "#{File.dirname(__FILE__)}/report.html.erb"
180
175
  end
181
176
 
182
177
  # configure template with variable values
183
- renderer = ERB.new(html_in)
178
+ renderer = ERB.new(File.read(html_in_path))
184
179
  html_out = renderer.result(binding)
185
180
 
186
181
  # write html file
187
- html_out_path = 'report.html'
182
+ html_out_path = './report.html'
183
+
188
184
  File.open(html_out_path, 'w') do |file|
189
185
  file << html_out
190
-
191
- # make sure data is written to the disk one way or the other
186
+
187
+ # make sure data is written to the disk one way or the other
192
188
  begin
193
189
  file.fsync
194
190
  rescue
@@ -196,17 +192,15 @@ class StandardReports < OpenStudio::Ruleset::ReportingUserScript
196
192
  end
197
193
  end
198
194
 
199
- #closing the sql file
195
+ # closing the sql file
200
196
  sqlFile.close
201
197
 
202
- #reporting final condition
203
- runner.registerFinalCondition("Standard Report generated successfully.")
204
-
205
- return true
206
-
207
- end #end the run method
198
+ # reporting final condition
199
+ runner.registerFinalCondition('Standard Report generated successfully.')
208
200
 
209
- end #end the measure
201
+ true
202
+ end # end the run method
203
+ end # end the measure
210
204
 
211
- #this allows the measure to be use by the application
212
- StandardReports.new.registerWithApplication
205
+ # this allows the measure to be use by the application
206
+ StandardReports.new.registerWithApplication
@@ -28,7 +28,7 @@
28
28
  <checksum>0D4162D2</checksum>
29
29
  </file>
30
30
  <file>
31
- <filename>report.html.in</filename>
31
+ <filename>report.html.erb</filename>
32
32
  <filetype>in</filetype>
33
33
  <usage_type>resource</usage_type>
34
34
  <checksum>093FE760</checksum>
@@ -0,0 +1,548 @@
1
+ ######################################################################
2
+ # Copyright (c) 2008-2014, Alliance for Sustainable Energy.
3
+ # All rights reserved.
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ ######################################################################
19
+
20
+ # Run precanned post processing to extract object functions
21
+ # TODO: I hear that measures can step on each other if not run in their own directory
22
+
23
+ require 'csv'
24
+ require 'ostruct'
25
+
26
+ class RunReportingMeasures
27
+ # Mixin the MeasureApplication module to apply measures
28
+ include OpenStudio::Workflow::ApplyMeasures
29
+
30
+ def initialize(directory, logger, adapter, options = {})
31
+ defaults = {}
32
+ @options = defaults.merge(options)
33
+ @directory = directory
34
+ @run_directory = "#{@directory}/run"
35
+ @adapter = adapter
36
+ @logger = logger
37
+ @results = {}
38
+ @output_attributes = {}
39
+
40
+ # TODO: we shouldn't have to keep loading this file if we need it. It should be availabe for any job.
41
+ # TODO: passing in the options everytime is ridiculuous
42
+ @analysis_json = @adapter.get_problem(@directory, @options)
43
+
44
+ @logger.info "#{self.class} passed the following options #{@options}"
45
+
46
+ @model = load_model @options[:run_openstudio][:osm]
47
+
48
+ # TODO: should read the name of the sql output file via the :run_openstudio options hash
49
+ # I want to reiterate that this is cheezy!
50
+ @sql_filename = "#{@run_directory}/eplusout.sql"
51
+ fail "EnergyPlus SQL file did not exist #{@sql_filename}" unless File.exist? @sql_filename
52
+
53
+ @objective_functions = {}
54
+ end
55
+
56
+ def perform
57
+ @logger.info "Calling #{__method__} in the #{self.class} class"
58
+ @logger.info 'RunPostProcess Retrieving datapoint and problem'
59
+
60
+ begin
61
+ @datapoint_json = @adapter.get_datapoint(@directory, @options)
62
+ @analysis_json = @adapter.get_problem(@directory, @options)
63
+
64
+ if @options[:use_monthly_reports]
65
+ run_monthly_postprocess
66
+ else
67
+ run_standard_postprocess
68
+ end
69
+
70
+ translate_csv_to_json
71
+
72
+ run_packaged_measures
73
+
74
+ if @analysis_json && @analysis_json[:analysis]
75
+ apply_measures(:reporting_measure)
76
+ end
77
+
78
+ @logger.info 'Saving reporting measures output attributes JSON'
79
+ File.open("#{@run_directory}/reporting_measure_attributes.json", 'w') do
80
+ |f| f << JSON.pretty_generate(@output_attributes)
81
+ end
82
+
83
+ run_extract_inputs_and_outputs
84
+
85
+ @logger.info "Objective Function JSON is #{@objective_functions}"
86
+ obj_fun_file = "#{@directory}/objectives.json"
87
+ FileUtils.rm_f(obj_fun_file) if File.exist?(obj_fun_file)
88
+ File.open(obj_fun_file, 'w') { |f| f << JSON.pretty_generate(@objective_functions) }
89
+
90
+ rescue => e
91
+ log_message = "Runner error #{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
92
+ raise log_message
93
+ end
94
+
95
+ @results
96
+ end
97
+
98
+ def run_extract_inputs_and_outputs
99
+ # For xml, the measure attributes are in the measure_attributes_xml.json file
100
+ # TODO: somehow pass the metadata around on which JSONs to suck into the database
101
+ if File.exist? "#{@run_directory}/measure_attributes_xml.json"
102
+ temp_json = JSON.parse(File.read("#{@run_directory}/measure_attributes_xml.json"), symbolize_names: true)
103
+ @results.merge! temp_json
104
+ end
105
+
106
+ # Inputs are in the measure_attributes.json file
107
+ if File.exist? "#{@run_directory}/measure_attributes.json"
108
+ temp_json = JSON.parse(File.read("#{@run_directory}/measure_attributes.json"), symbolize_names: true)
109
+ @results.merge! temp_json
110
+ end
111
+
112
+ # Inputs are in the reporting_measure_attributes.jsonfile
113
+ if File.exist? "#{@run_directory}/reporting_measure_attributes.json"
114
+ temp_json = JSON.parse(File.read("#{@run_directory}/reporting_measure_attributes.json"), symbolize_names: true)
115
+ @results.merge! temp_json
116
+ end
117
+
118
+ # Initialize the objective function variable
119
+ @objective_functions = {}
120
+ if File.exist? "#{@run_directory}/standard_report_legacy.json"
121
+ @results[:standard_report_legacy] = JSON.parse(File.read("#{@run_directory}/standard_report_legacy.json"), symbolize_names: true)
122
+
123
+ @logger.info 'Iterating over Analysis JSON Output Variables'
124
+ # Save the objective functions to the object for sending back to the simulation executive
125
+
126
+ @analysis_json[:analysis][:output_variables].each do |variable|
127
+ # determine which ones are the objective functions (code smell: todo: use enumerator)
128
+ if variable[:objective_function]
129
+ @logger.info "Looking for objective function #{variable[:name]}"
130
+ # TODO: move this to cleaner logic. Use ostruct?
131
+ if variable[:name].include? '.'
132
+ k, v = variable[:name].split('.')
133
+ if @results.key?(k.to_sym) && @results[k.to_sym][v.to_sym]
134
+ @objective_functions["objective_function_#{variable[:objective_function_index] + 1}"] = @results[k.to_sym][v.to_sym]
135
+ if variable[:objective_function_target]
136
+ @logger.info "Found objective function target for #{variable[:name]}"
137
+ @objective_functions["objective_function_target_#{variable[:objective_function_index] + 1}"] = variable[:objective_function_target].to_f
138
+ end
139
+ if variable[:scaling_factor]
140
+ @logger.info "Found scaling factor for #{variable[:name]}"
141
+ @objective_functions["scaling_factor_#{variable[:objective_function_index] + 1}"] = variable[:scaling_factor].to_f
142
+ end
143
+ if variable[:objective_function_group]
144
+ @logger.info "Found objective function group for #{variable[:name]}"
145
+ @objective_functions["objective_function_group_#{variable[:objective_function_index] + 1}"] = variable[:objective_function_group].to_f
146
+ end
147
+ else
148
+ @logger.warn "No results for objective function #{variable[:name]}"
149
+ @objective_functions["objective_function_#{variable[:objective_function_index] + 1}"] = Float::MAX
150
+ @objective_functions["objective_function_target_#{variable[:objective_function_index] + 1}"] = nil
151
+ @objective_functions["scaling_factor_#{variable[:objective_function_index] + 1}"] = nil
152
+ @objective_functions["objective_function_group_#{variable[:objective_function_index] + 1}"] = nil
153
+ end
154
+ else
155
+ # variable name is not nested with the '.' -- this is for legacy purposes and should be deleted on 9/30/2014
156
+ if @results[variable[:name]]
157
+ @objective_functions["objective_function_#{variable[:objective_function_index] + 1}"] = @results[k.to_sym][v.to_sym]
158
+ if variable[:objective_function_target]
159
+ @logger.info "Found objective function target for #{variable[:name]}"
160
+ @objective_functions["objective_function_target_#{variable[:objective_function_index] + 1}"] = variable[:objective_function_target].to_f
161
+ end
162
+ if variable[:scaling_factor]
163
+ @logger.info "Found scaling factor for #{variable[:name]}"
164
+ @objective_functions["scaling_factor_#{variable[:objective_function_index] + 1}"] = variable[:scaling_factor].to_f
165
+ end
166
+ if variable[:objective_function_group]
167
+ @logger.info "Found objective function group for #{variable[:name]}"
168
+ @objective_functions["objective_function_group_#{variable[:objective_function_index] + 1}"] = variable[:objective_function_group].to_f
169
+ end
170
+ else
171
+ @logger.warn "No results for objective function #{variable[:name]}"
172
+ @objective_functions["objective_function_#{variable[:objective_function_index] + 1}"] = Float::MAX
173
+ @objective_functions["objective_function_target_#{variable[:objective_function_index] + 1}"] = nil
174
+ @objective_functions["scaling_factor_#{variable[:objective_function_index] + 1}"] = nil
175
+ @objective_functions["objective_function_group_#{variable[:objective_function_index] + 1}"] = nil
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
182
+
183
+ private
184
+
185
+ # Load in the OpenStudio model. It is required for postprocessing
186
+ def load_model(filename)
187
+ model = nil
188
+ @logger.info 'Loading model'
189
+
190
+ # TODO: wrap this in an exception block and fail as appropriate
191
+ # assume that the seed model has been placed in the directory
192
+ if File.exist? filename
193
+ @logger.info "Reading in model #{filename}"
194
+ translator = OpenStudio::OSVersion::VersionTranslator.new
195
+ model = translator.loadModel(filename)
196
+ fail 'OpenStudio model is empty or could not be loaded' if model.empty?
197
+ model = model.get
198
+ else
199
+ fail "Model '#{filename}' did not exist"
200
+ end
201
+
202
+ model
203
+ end
204
+
205
+ # Run the prepackaged measures in the Gem.
206
+ def run_packaged_measures
207
+ # configure the workflow item json to pass
208
+ workflow_item = {
209
+ display_name: 'Standard Reports',
210
+ measure_definition_directory: File.expand_path(File.join(File.dirname(__FILE__), 'packaged_measures', 'StandardReports', 'measure.rb')),
211
+ measure_definition_class_name: 'StandardReports',
212
+ measure_type: 'ReportingMeasure',
213
+ name: 'standard_reports'
214
+ }
215
+ @logger.info 'Running packaged reporting measures'
216
+
217
+ apply_measure(workflow_item)
218
+
219
+ @logger.info 'Finished Running Packaged Measures'
220
+ end
221
+
222
+ def translate_csv_to_json
223
+ if File.exist?("#{@run_directory}/eplustbl.csv")
224
+ @logger.info 'Translating EnergyPlus table CSV to JSON file'
225
+ results = {}
226
+ csv = CSV.read("#{@run_directory}/eplustbl.csv")
227
+ csv.transpose.each do |k, v|
228
+ longname = k.gsub(/\(.*\)/, '').strip
229
+ short_name = longname.downcase.gsub(' ', '_')
230
+ units = k.match(/\(.*\)/)[0].gsub('(', '').gsub(')', '')
231
+ results[short_name.to_sym] = v.nil? ? nil : v.to_f
232
+ results["#{short_name}_units".to_sym] = units
233
+ results["#{short_name}_display_name".to_sym] = longname
234
+ end
235
+
236
+ @logger.info 'Saving results to json'
237
+
238
+ # save out results
239
+ File.open("#{@run_directory}/standard_report_legacy.json", 'w') { |f| f << JSON.pretty_generate(results) }
240
+ end
241
+ end
242
+
243
+ # TODO: THis is uglier than the one below! sorry.
244
+ def run_monthly_postprocess
245
+ def sql_query(sql, report_name, query)
246
+ val = nil
247
+ result = sql.execAndReturnFirstDouble("SELECT Value FROM TabularDataWithStrings WHERE ReportName='#{report_name}' AND #{query}")
248
+ if result.empty?
249
+ @logger.warn "Query for run_monthly_postprocess failed for #{query}"
250
+ else
251
+ begin
252
+ val = result.get
253
+ rescue => e
254
+ @logger.info "#{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
255
+ val = nil
256
+ end
257
+ end
258
+
259
+ val
260
+ end
261
+
262
+ def add_element(hash, var_name, value, xpath = nil)
263
+ values_hash = {}
264
+ values_hash['name'] = var_name
265
+
266
+ # store correct datatype
267
+ store_val = nil
268
+ if value.nil?
269
+ store_val = nil
270
+ elsif value == 'true'
271
+ store_val = true
272
+ elsif value == 'false'
273
+ store_val = false
274
+ else
275
+ test = value.to_s
276
+ value = test.match('\.').nil? ? Integer(test) : Float(test) rescue test.to_s
277
+ if value.is_a?(Fixnum) || value.is_a?(Float)
278
+ store_val = value.to_f
279
+ else
280
+ store_val = value.to_s
281
+ end
282
+ end
283
+ values_hash['value'] = store_val
284
+ values_hash['xpath'] = xpath unless xpath.nil?
285
+
286
+ hash['data']['variables'] << values_hash
287
+ end
288
+
289
+ # add results from sql method
290
+ def add_data(sql, query, hdr, area, val)
291
+ row = []
292
+ val = sql_query(sql, 'AnnualBuildingUtilityPerformanceSummary', query) if val.nil?
293
+ row << hdr
294
+ if area.nil?
295
+ row << val
296
+ else
297
+ row << (val * 1000) / area
298
+ end
299
+ row
300
+ end
301
+
302
+ # add results from sql method
303
+ def add_data2(sql, query, hdr, area, val)
304
+ row = []
305
+ val = sql_query(sql, 'BUILDING ENERGY PERFORMANCE - ELECTRICITY', query) if val.nil?
306
+ row << hdr
307
+ if area.nil?
308
+ row << val
309
+ else
310
+ row << (val * 1000) / area
311
+ end
312
+ row
313
+ end
314
+
315
+ # add results from sql method
316
+ def add_data3(sql, query, hdr, area, val)
317
+ row = []
318
+ val = sql_query(sql, 'BUILDING ENERGY PERFORMANCE - NATURAL GAS', query) if val.nil?
319
+ row << hdr
320
+ if area.nil?
321
+ row << val
322
+ else
323
+ row << (val * 1000) / area
324
+ end
325
+ row
326
+ end
327
+
328
+ # add results from sql method
329
+ def add_data4(sql, query, hdr, area, val)
330
+ row = []
331
+
332
+ if val.nil?
333
+ val = 0
334
+
335
+ ['INTERIORLIGHTS:ELECTRICITY', 'EXTERIORLIGHTS:ELECTRICITY', 'INTERIOREQUIPMENT:ELECTRICITY', 'EXTERIOREQUIPMENT:ELECTRICITY',
336
+ 'FANS:ELECTRICITY', 'PUMPS:ELECTRICITY', 'HEATING:ELECTRICITY', 'COOLING:ELECTRICITY', 'HEATREJECTION:ELECTRICITY',
337
+ 'HUMIDIFIER:ELECTRICITY', 'HEATRECOVERY:ELECTRICITY', 'WATERSYSTEMS:ELECTRICITY', 'COGENERATION:ELECTRICITY', 'REFRIGERATION:ELECTRICITY'].each do |end_use|
338
+
339
+ tmp_query = query + " AND ColumnName='#{end_use}'"
340
+ tmp_val = sql_query(sql, 'BUILDING ENERGY PERFORMANCE - ELECTRICITY', tmp_query)
341
+ val += tmp_val unless tmp_val.nil?
342
+ end
343
+ end
344
+
345
+ row << hdr
346
+ if area.nil?
347
+ row << val
348
+ else
349
+ row << (val * 1000) / area
350
+ end
351
+ row
352
+ end
353
+
354
+ # open sql file
355
+ sql_file = OpenStudio::SqlFile.new(@sql_filename)
356
+
357
+ # get building area
358
+ bldg_area = sql_query(sql_file, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Building Area' AND RowName='Net Conditioned Building Area' AND ColumnName='Area'")
359
+ # populate data array
360
+
361
+ tbl_data = []
362
+ tbl_data << add_data(sql_file, "TableName='Site and Source Energy' AND RowName='Total Site Energy' AND ColumnName='Energy Per Conditioned Building Area'", 'Total Energy (MJ/m2)', nil, nil)
363
+ tbl_data << add_data(sql_file, "TableName='Site and Source Energy' AND RowName='Total Source Energy' AND ColumnName='Energy Per Conditioned Building Area'", 'Total Source Energy (MJ/m2)', nil, nil)
364
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Total End Uses' AND ColumnName='Electricity'", 'Total Electricity (MJ/m2)', bldg_area, nil)
365
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Total End Uses' AND ColumnName='Natural Gas'", 'Total Natural Gas (MJ/m2)', bldg_area, nil)
366
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Heating' AND ColumnName='Electricity'", 'Heating Electricity (MJ/m2)', bldg_area, nil)
367
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Heating' AND ColumnName='Natural Gas'", 'Heating Natural Gas (MJ/m2)', bldg_area, nil)
368
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Cooling' AND ColumnName='Electricity'", 'Cooling Electricity (MJ/m2)', bldg_area, nil)
369
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Interior Lighting' AND ColumnName='Electricity'", 'Interior Lighting Electricity (MJ/m2)', bldg_area, nil)
370
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Exterior Lighting' AND ColumnName='Electricity'", 'Exterior Lighting Electricity (MJ/m2)', bldg_area, nil)
371
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Interior Equipment' AND ColumnName='Electricity'", 'Interior Equipment Electricity (MJ/m2)', bldg_area, nil)
372
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Interior Equipment' AND ColumnName='Natural Gas'", 'Interior Equipment Natural Gas (MJ/m2)', bldg_area, nil)
373
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Exterior Equipment' AND ColumnName='Electricity'", 'Exterior Equipment Electricity (MJ/m2)', bldg_area, nil)
374
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Fans' AND ColumnName='Electricity'", 'Fans Electricity (MJ/m2)', bldg_area, nil)
375
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Pumps' AND ColumnName='Electricity'", 'Pumps Electricity (MJ/m2)', bldg_area, nil)
376
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Heat Rejection' AND ColumnName='Electricity'", 'Heat Rejection Electricity (MJ/m2)', bldg_area, nil)
377
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Humidification' AND ColumnName='Electricity'", 'Humidification Electricity (MJ/m2)', bldg_area, nil)
378
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Water Systems' AND ColumnName='Electricity'", 'Water Systems Electricity (MJ/m2)', bldg_area, nil)
379
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Water Systems' AND ColumnName='Natural Gas'", 'Water Systems Natural Gas (MJ/m2)', bldg_area, nil)
380
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Refrigeration' AND ColumnName='Electricity'", 'Refrigeration Electricity (MJ/m2)', bldg_area, nil)
381
+ htg_hrs = sql_query(sql_file, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Comfort and Setpoint Not Met Summary' AND RowName='Time Setpoint Not Met During Occupied Heating' AND ColumnName='Facility'")
382
+ clg_hrs = sql_query(sql_file, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Comfort and Setpoint Not Met Summary' AND RowName='Time Setpoint Not Met During Occupied Cooling' AND ColumnName='Facility'")
383
+ tot_hrs = clg_hrs && htg_hrs ? htg_hrs + clg_hrs : nil
384
+ tbl_data << add_data(sql_file, nil, 'Heating Hours Unmet (hr)', nil, htg_hrs)
385
+ tbl_data << add_data(sql_file, nil, 'Cooling Hours Unmet (hr)', nil, clg_hrs)
386
+ tbl_data << add_data(sql_file, nil, 'Total Hours Unmet (hr)', nil, tot_hrs)
387
+ total_cost = sql_query(sql_file, 'Life-Cycle Cost Report', "TableName='Present Value by Category' AND RowName='Grand Total' AND ColumnName='Present Value'")
388
+ tbl_data << add_data(sql_file, nil, 'Total Life Cycle Cost ($)', nil, total_cost)
389
+ # cooling:electricity
390
+ tbl_data << add_data2(sql_file, "RowName='January' AND ColumnName='COOLING:ELECTRICITY'", 'Cooling Electricity Jan (J)', nil, nil)
391
+ tbl_data << add_data2(sql_file, "RowName='February' AND ColumnName='COOLING:ELECTRICITY'", 'Cooling Electricity Feb (J)', nil, nil)
392
+ tbl_data << add_data2(sql_file, "RowName='March' AND ColumnName='COOLING:ELECTRICITY'", 'Cooling Electricity Mar (J)', nil, nil)
393
+ tbl_data << add_data2(sql_file, "RowName='April' AND ColumnName='COOLING:ELECTRICITY'", 'Cooling Electricity Apr (J)', nil, nil)
394
+ tbl_data << add_data2(sql_file, "RowName='May' AND ColumnName='COOLING:ELECTRICITY'", 'Cooling Electricity May (J)', nil, nil)
395
+ tbl_data << add_data2(sql_file, "RowName='June' AND ColumnName='COOLING:ELECTRICITY'", 'Cooling Electricity Jun (J)', nil, nil)
396
+ tbl_data << add_data2(sql_file, "RowName='July' AND ColumnName='COOLING:ELECTRICITY'", 'Cooling Electricity Jul (J)', nil, nil)
397
+ tbl_data << add_data2(sql_file, "RowName='August' AND ColumnName='COOLING:ELECTRICITY'", 'Cooling Electricity Aug (J)', nil, nil)
398
+ tbl_data << add_data2(sql_file, "RowName='September' AND ColumnName='COOLING:ELECTRICITY'", 'Cooling Electricity Sep (J)', nil, nil)
399
+ tbl_data << add_data2(sql_file, "RowName='October' AND ColumnName='COOLING:ELECTRICITY'", 'Cooling Electricity Oct (J)', nil, nil)
400
+ tbl_data << add_data2(sql_file, "RowName='November' AND ColumnName='COOLING:ELECTRICITY'", 'Cooling Electricity Nov (J)', nil, nil)
401
+ tbl_data << add_data2(sql_file, "RowName='December' AND ColumnName='COOLING:ELECTRICITY'", 'Cooling Electricity Dec (J)', nil, nil)
402
+ # heating:gas
403
+ tbl_data << add_data3(sql_file, "RowName='January' AND ColumnName='HEATING:GAS'", 'Heating Gas Jan (J)', nil, nil)
404
+ tbl_data << add_data3(sql_file, "RowName='February' AND ColumnName='HEATING:GAS'", 'Heating Gas Feb (J)', nil, nil)
405
+ tbl_data << add_data3(sql_file, "RowName='March' AND ColumnName='HEATING:GAS'", 'Heating Gas Mar (J)', nil, nil)
406
+ tbl_data << add_data3(sql_file, "RowName='April' AND ColumnName='HEATING:GAS'", 'Heating Gas Apr (J)', nil, nil)
407
+ tbl_data << add_data3(sql_file, "RowName='May' AND ColumnName='HEATING:GAS'", 'Heating Gas May (J)', nil, nil)
408
+ tbl_data << add_data3(sql_file, "RowName='June' AND ColumnName='HEATING:GAS'", 'Heating Gas Jun (J)', nil, nil)
409
+ tbl_data << add_data3(sql_file, "RowName='July' AND ColumnName='HEATING:GAS'", 'Heating Gas Jul (J)', nil, nil)
410
+ tbl_data << add_data3(sql_file, "RowName='August' AND ColumnName='HEATING:GAS'", 'Heating Gas Aug (J)', nil, nil)
411
+ tbl_data << add_data3(sql_file, "RowName='September' AND ColumnName='HEATING:GAS'", 'Heating Gas Sep (J)', nil, nil)
412
+ tbl_data << add_data3(sql_file, "RowName='October' AND ColumnName='HEATING:GAS'", 'Heating Gas Oct (J)', nil, nil)
413
+ tbl_data << add_data3(sql_file, "RowName='November' AND ColumnName='HEATING:GAS'", 'Heating Gas Nov (J)', nil, nil)
414
+ tbl_data << add_data3(sql_file, "RowName='December' AND ColumnName='HEATING:GAS'", 'Heating Gas Dec (J)', nil, nil)
415
+ # total Electricity
416
+ tbl_data << add_data4(sql_file, "RowName='January'", 'Total Electricity Jan (J)', nil, nil)
417
+ tbl_data << add_data4(sql_file, "RowName='February'", 'Total Electricity Feb (J)', nil, nil)
418
+ tbl_data << add_data4(sql_file, "RowName='March'", 'Total Electricity Mar (J)', nil, nil)
419
+ tbl_data << add_data4(sql_file, "RowName='April'", 'Total Electricity Apr (J)', nil, nil)
420
+ tbl_data << add_data4(sql_file, "RowName='May'", 'Total Electricity May (J)', nil, nil)
421
+ tbl_data << add_data4(sql_file, "RowName='June'", 'Total Electricity Jun (J)', nil, nil)
422
+ tbl_data << add_data4(sql_file, "RowName='July'", 'Total Electricity Jul (J)', nil, nil)
423
+ tbl_data << add_data4(sql_file, "RowName='August'", 'Total Electricity Aug (J)', nil, nil)
424
+ tbl_data << add_data4(sql_file, "RowName='September'", 'Total Electricity Sep (J)', nil, nil)
425
+ tbl_data << add_data4(sql_file, "RowName='October'", 'Total Electricity Oct (J)', nil, nil)
426
+ tbl_data << add_data4(sql_file, "RowName='November'", 'Total Electricity Nov (J)', nil, nil)
427
+ tbl_data << add_data4(sql_file, "RowName='December'", 'Total Electricity Dec (J)', nil, nil) # close SQL file
428
+ sql_file.close
429
+ # transpose data
430
+ tbl_rows = tbl_data.transpose
431
+
432
+ @logger.info tbl_rows
433
+ # write electricity data to CSV
434
+ CSV.open("#{@run_directory}/eplustbl.csv", 'wb') do |csv|
435
+ tbl_rows.each do |row|
436
+ csv << row
437
+ end
438
+ end
439
+ end
440
+
441
+ # TODO: This is ugly. Move this out of here entirely and into a reporting measure if we need it at all
442
+ def run_standard_postprocess
443
+ def sql_query(sql, report_name, query)
444
+ val = nil
445
+ result = sql.execAndReturnFirstDouble("SELECT Value FROM TabularDataWithStrings WHERE ReportName='#{report_name}' AND #{query}")
446
+ if result.empty?
447
+ @logger.warn "Query for run_standard_postprocess failed for #{query}"
448
+ else
449
+ begin
450
+ val = result.get
451
+ rescue => e
452
+ @logger.info "#{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
453
+ val = nil
454
+ end
455
+ end
456
+
457
+ val
458
+ end
459
+
460
+ def add_element(hash, var_name, value, xpath = nil)
461
+ values_hash = {}
462
+ values_hash['name'] = var_name
463
+
464
+ # store correct datatype
465
+ store_val = nil
466
+ if value.nil?
467
+ store_val = nil
468
+ elsif value == 'true'
469
+ store_val = true
470
+ elsif value == 'false'
471
+ store_val = false
472
+ else
473
+ test = value.to_s
474
+ value = test.match('\.').nil? ? Integer(test) : Float(test) rescue test.to_s
475
+ if value.is_a?(Fixnum) || value.is_a?(Float)
476
+ store_val = value.to_f
477
+ else
478
+ store_val = value.to_s
479
+ end
480
+ end
481
+ values_hash['value'] = store_val
482
+ values_hash['xpath'] = xpath unless xpath.nil?
483
+
484
+ hash['data']['variables'] << values_hash
485
+ end
486
+
487
+ # add results from sql method
488
+ def add_data(sql, query, hdr, area, val)
489
+ row = []
490
+ val = sql_query(sql, 'AnnualBuildingUtilityPerformanceSummary', query) if val.nil?
491
+ row << hdr
492
+ if area.nil?
493
+ row << val
494
+ else
495
+ row << (val * 1000) / area
496
+ end
497
+ row
498
+ end
499
+
500
+ # open sql file
501
+ sql_file = OpenStudio::SqlFile.new(@sql_filename)
502
+
503
+ # get building area
504
+ bldg_area = sql_query(sql_file, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Building Area' AND RowName='Net Conditioned Building Area' AND ColumnName='Area'")
505
+ # populate data array
506
+
507
+ tbl_data = []
508
+ tbl_data << add_data(sql_file, "TableName='Site and Source Energy' AND RowName='Total Site Energy' AND ColumnName='Energy Per Conditioned Building Area'", 'Total Energy (MJ/m2)', nil, nil)
509
+ tbl_data << add_data(sql_file, "TableName='Site and Source Energy' AND RowName='Total Source Energy' AND ColumnName='Energy Per Conditioned Building Area'", 'Total Source Energy (MJ/m2)', nil, nil)
510
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Total End Uses' AND ColumnName='Electricity'", 'Total Electricity (MJ/m2)', bldg_area, nil)
511
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Total End Uses' AND ColumnName='Natural Gas'", 'Total Natural Gas (MJ/m2)', bldg_area, nil)
512
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Heating' AND ColumnName='Electricity'", 'Heating Electricity (MJ/m2)', bldg_area, nil)
513
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Heating' AND ColumnName='Natural Gas'", 'Heating Natural Gas (MJ/m2)', bldg_area, nil)
514
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Cooling' AND ColumnName='Electricity'", 'Cooling Electricity (MJ/m2)', bldg_area, nil)
515
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Interior Lighting' AND ColumnName='Electricity'", 'Interior Lighting Electricity (MJ/m2)', bldg_area, nil)
516
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Exterior Lighting' AND ColumnName='Electricity'", 'Exterior Lighting Electricity (MJ/m2)', bldg_area, nil)
517
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Interior Equipment' AND ColumnName='Electricity'", 'Interior Equipment Electricity (MJ/m2)', bldg_area, nil)
518
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Interior Equipment' AND ColumnName='Natural Gas'", 'Interior Equipment Natural Gas (MJ/m2)', bldg_area, nil)
519
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Exterior Equipment' AND ColumnName='Electricity'", 'Exterior Equipment Electricity (MJ/m2)', bldg_area, nil)
520
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Fans' AND ColumnName='Electricity'", 'Fans Electricity (MJ/m2)', bldg_area, nil)
521
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Pumps' AND ColumnName='Electricity'", 'Pumps Electricity (MJ/m2)', bldg_area, nil)
522
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Heat Rejection' AND ColumnName='Electricity'", 'Heat Rejection Electricity (MJ/m2)', bldg_area, nil)
523
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Humidification' AND ColumnName='Electricity'", 'Humidification Electricity (MJ/m2)', bldg_area, nil)
524
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Water Systems' AND ColumnName='Electricity'", 'Water Systems Electricity (MJ/m2)', bldg_area, nil)
525
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Water Systems' AND ColumnName='Natural Gas'", 'Water Systems Natural Gas (MJ/m2)', bldg_area, nil)
526
+ tbl_data << add_data(sql_file, "TableName='End Uses' AND RowName='Refrigeration' AND ColumnName='Electricity'", 'Refrigeration Electricity (MJ/m2)', bldg_area, nil)
527
+ htg_hrs = sql_query(sql_file, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Comfort and Setpoint Not Met Summary' AND RowName='Time Setpoint Not Met During Occupied Heating' AND ColumnName='Facility'")
528
+ clg_hrs = sql_query(sql_file, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Comfort and Setpoint Not Met Summary' AND RowName='Time Setpoint Not Met During Occupied Cooling' AND ColumnName='Facility'")
529
+ tot_hrs = clg_hrs && htg_hrs ? htg_hrs + clg_hrs : nil
530
+ tbl_data << add_data(sql_file, nil, 'Heating Hours Unmet (hr)', nil, htg_hrs)
531
+ tbl_data << add_data(sql_file, nil, 'Cooling Hours Unmet (hr)', nil, clg_hrs)
532
+ tbl_data << add_data(sql_file, nil, 'Total Hours Unmet (hr)', nil, tot_hrs)
533
+ total_cost = sql_query(sql_file, 'Life-Cycle Cost Report', "TableName='Present Value by Category' AND RowName='Grand Total' AND ColumnName='Present Value'")
534
+ tbl_data << add_data(sql_file, nil, 'Total Life Cycle Cost ($)', nil, total_cost)
535
+ # close SQL file
536
+ sql_file.close
537
+ # transpose data
538
+ tbl_rows = tbl_data.transpose
539
+
540
+ @logger.info tbl_rows
541
+ # write electricity data to CSV
542
+ CSV.open("#{@run_directory}/eplustbl.csv", 'wb') do |csv|
543
+ tbl_rows.each do |row|
544
+ csv << row
545
+ end
546
+ end
547
+ end
548
+ end