Class: GEBMetricsReport

Inherits:
OpenStudio::Measure::ReportingMeasure
  • Object
show all
Defined in:
lib/measures/GEB Metrics Report/measure.rb

Overview

start the measure

Instance Method Summary collapse

Instance Method Details

#argumentsObject

define the arguments that the user will input



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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/measures/GEB Metrics Report/measure.rb', line 43

def arguments
  args = OpenStudio::Measure::OSArgumentVector.new

  # populate arguments
  possible_sections.each do |method_name|
    begin
      # get display name
      arg = OpenStudio::Measure::OSArgument.makeBoolArgument(method_name, true)
      display_name = eval("OsLib_Reporting.#{method_name}(nil,nil,nil,nil,nil,true,nil)[:title]")
      arg.setDescription("Choose whether or not to report #{method_name}")
      arg.setDisplayName(display_name)
      arg.setDefaultValue(true)
      args << arg
    rescue
      next
    end
  end

  # make an argument for the start date of the reduction
  event_date = OpenStudio::Ruleset::OSArgument.makeStringArgument('event_date', true)
  event_date.setDisplayName('The event date for GEB metrics reporting purpose')
  event_date.setDescription('In MM-DD format')
  args << event_date

  # Make string arguments for shed period start time. Optional for some GEB measures like EV and DCV (DCV is EE focused)
  shed_start = OpenStudio::Measure::OSArgument.makeStringArgument('shed_start', false)
  shed_start.setDisplayName('Enter Starting Time for Shed Period:')
  shed_start.setDescription('Use 24 hour format HH:MM:SS')
  # shed_start.setDefaultValue('14:00')
  args << shed_start

  # Make string arguments for shed period end time. Optional for some GEB measures like EV and DCV (DCV is EE focused)
  shed_end = OpenStudio::Measure::OSArgument.makeStringArgument('shed_end', false)
  shed_end.setDisplayName('Enter End Time for Shed Period:')
  shed_end.setDescription('Use 24 hour format HH:MM:SS')
  # shed_end.setDefaultValue('18:00')
  args << shed_end

  # Make string arguments for take period start time. Optional for some GEB measures like EV and DCV (DCV is EE focused)
  take_start = OpenStudio::Measure::OSArgument.makeStringArgument('take_start', false)
  take_start.setDisplayName('Enter Starting Time for Take Period:')
  take_start.setDescription('Use 24 hour format HH:MM:SS')
  # take_start.setDefaultValue('10:00')
  args << take_start

  # Make string arguments for take period end time. Optional for some GEB measures like EV and DCV (DCV is EE focused)
  take_end = OpenStudio::Measure::OSArgument.makeStringArgument('take_end', false)
  take_end.setDisplayName('Enter End Time for Take Period:')
  take_end.setDescription('Use 24 hour format HH:MM:SS')
  # take_end.setDefaultValue('14:00')
  args << take_end

  # Output path, for sizing run
  baseline_run_output_path = OpenStudio::Measure::OSArgument.makePathArgument('baseline_run_output_path', true, "")
  baseline_run_output_path.setDisplayName('Output path')
  args << baseline_run_output_path

  args
end

#descriptionObject

human readable description



21
22
23
# File 'lib/measures/GEB Metrics Report/measure.rb', line 21

def description
  return 'This measure calculates GEB-related (mainly DF) metrics and reports them.'
end

#modeler_descriptionObject

human readable description of modeling approach



26
27
28
# File 'lib/measures/GEB Metrics Report/measure.rb', line 26

def modeler_description
  return 'GEB metrics compare between baseline and GEB measures. To enable the GEB metrics calculation, please make sure the output variable -Facility Net Purchased Electricity Rate- is added to both baseline and retrofit models.'
end

#nameObject

human readable name



15
16
17
18
# File 'lib/measures/GEB Metrics Report/measure.rb', line 15

def name
  # Measure name should be the title case of the class name.
  return 'GEB Metrics Report'
end

#outputsObject

define the outputs that the measure will create



104
105
106
107
108
109
110
# File 'lib/measures/GEB Metrics Report/measure.rb', line 104

def outputs
  outs = OpenStudio::Measure::OSOutputVector.new

  # this measure does not produce machine readable outputs with registerValue, return an empty list

  return outs
end

#possible_sectionsObject



31
32
33
34
35
36
37
38
39
40
# File 'lib/measures/GEB Metrics Report/measure.rb', line 31

def possible_sections
  result = []

  # methods for sections in order that they will appear in report
  ############################################################################
  result << 'geb_metrics_section'
  # TODO: will incorporate tables and figures later

  result
end

#run(runner, user_arguments) ⇒ Object

define what happens when the measure is run



131
132
133
134
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/measures/GEB Metrics Report/measure.rb', line 131

def run(runner, user_arguments)
  super(runner, user_arguments)

  # get sql, model, and web assets
  setup = OsLib_Reporting.setup(runner)
  unless setup
    return false
  end
  model = setup[:model]
  # workspace = setup[:workspace]
  sql_file = setup[:sqlFile]
  web_asset_path = setup[:web_asset_path]
  puts "Got measure sql file"

  # get all args except the section args
  event_date = runner.getStringArgumentValue('event_date', user_arguments)
  baseline_run_output_path = runner.getPathArgumentValue('baseline_run_output_path', user_arguments)

  # shed_start and shed_end must be a pair
  # report shed period missing if only take period is given
  # following scenarios are reasonable: (1) has shed, has take; (2) has shed, no take; (3) no shed, no take
  if user_arguments['shed_start'].hasValue && user_arguments['shed_end'].hasValue
    shed_start = runner.getStringArgumentValue('shed_start', user_arguments)
    shed_end = runner.getStringArgumentValue('shed_end', user_arguments)
    # check time format
    begin
      shed_start = Time.strptime(shed_start, '%H:%M')
      shed_end = Time.strptime(shed_end, '%H:%M')
    rescue ArgumentError
      runner.registerError('Shed period start and end times should be in format of %H:%M, e.g., 16:00.')
      return false
    end
    # Check if shed start and end are the same (Wrong inputs)
    if shed_start == shed_end
      runner.registerError('The start and end times of the shed period are the same.')
      return false
    end
    if user_arguments['take_start'].hasValue && user_arguments['take_end'].hasValue
      take_start = runner.getStringArgumentValue('take_start', user_arguments)
      take_end = runner.getStringArgumentValue('take_end', user_arguments)
      # check time format
      begin
        take_start = Time.strptime(take_start, '%H:%M')
        take_end = Time.strptime(take_end, '%H:%M')
      rescue ArgumentError
        runner.registerError('Take period start and end times should be in format of %H:%M, e.g., 16:00.')
        return false
      end
      # Check if shed and take periods have overlap (Assuming typically shed doesn't go overnight as midnight is not peak hours)
      if take_start.between?(shed_start+1, shed_end-1) || take_end.between?(shed_start+1, shed_end-1)   # +- 1 second in case boundaries join
        runner.registerError('The take and shed periods overlap.')
        return false
      end
      # Check if take start and end are the same (Wrong inputs)
      if take_start == take_end
        runner.registerError('The start and end times of the take period are the same.')
        return false
      end
    else
      take_start = nil
      take_end = nil
    end
  else
    shed_start = nil
    shed_end = nil
    take_start = nil
    take_end = nil
  end

  # get baseline model and sql
  base_sql_file_path = OpenStudio::Path.new(File.join(baseline_run_output_path.to_s, 'baseline', 'run', "eplusout.sql"))
  unless File.exist?(base_sql_file_path.to_s)
    runner.registerError('No baseline result sql file was found.')
    return false
  end
  base_sql_file = OpenStudio::SqlFile.new(base_sql_file_path)
  puts "Got baseline sql file"

  # assign the user inputs to variables
  args = OsLib_HelperMethods.createRunVariables(runner, model, user_arguments, arguments)
  puts "args: #{args}"
  unless args
    return false
  end

  # reporting final condition
  runner.registerInitialCondition('Gathering data from EnergyPlus SQL file and OSM model.')

  # pass measure display name to erb
  @name = name

  # create a array of sections to loop through in erb file
  @sections = []

  # generate data for requested sections
  sections_made = 0
  puts "possible_sections: #{possible_sections.inspect}"
  possible_sections.each do |method_name|
    puts "method_name: #{method_name}"
    next unless args[method_name]
    section = false
    eval("section = OsLib_Reporting.#{method_name}(model,sql_file,base_sql_file,event_date,runner,false,args,nil,shed_start, shed_end, take_start, take_end)")
    display_name = eval("OsLib_Reporting.#{method_name}(nil,nil,nil,nil,nil,true)[:title]")
    if section
      @sections << section
      sections_made += 1
      # look for emtpy tables and warn if skipped because returned empty
      section[:tables].each do |table|
        if !table
          runner.registerWarning("A table in #{display_name} section returned false and was skipped.")
          section[:messages] = ["One or more tables in #{display_name} section returned false and was skipped."]
        end
      end
    else
      runner.registerWarning("#{display_name} section returned false and was skipped.")
      section = {}
      section[:title] = display_name.to_s
      section[:tables] = []
      section[:messages] = []
      section[:messages] << "#{display_name} section returned false and was skipped."
      @sections << section
    end
    # rescue StandardError => e
    #   display_name = eval("OsLib_Reporting.#{method_name}(nil,nil,nil,true)[:title]")
    #   if display_name.nil? then display_name == method_name end
    #   runner.registerWarning("#{display_name} section failed and was skipped because: #{e}. Detail on error follows.")
    #   runner.registerWarning(e.backtrace.join("\n").to_s)

    #   # add in section heading with message if section fails
    #   section = eval("OsLib_Reporting.#{method_name}(nil,nil,nil,true)")
    #   section[:title] = display_name.to_s
    #   section[:tables] = []
    #   section[:messages] = []
    #   section[:messages] << "#{display_name} section failed and was skipped because: #{e}. Detail on error follows."
    #   section[:messages] << [e.backtrace.join("\n").to_s]
    #   @sections << section
  end

  # read in template
  html_in_path = "#{File.dirname(__FILE__)}/resources/report.html.erb"
  if File.exist?(html_in_path)
    html_in_path = html_in_path
  else
    html_in_path = "#{File.dirname(__FILE__)}/report.html.erb"
  end
  html_in = ''
  File.open(html_in_path, 'r') do |file|
    html_in = file.read
  end

  # configure template with variable values
  renderer = ERB.new(html_in)
  html_out = renderer.result(binding)

  # write html file
  html_out_path = File.join(baseline_run_output_path.to_s, 'report.html')
  File.open(html_out_path, 'w') do |file|
    file << html_out
    # make sure data is written to the disk one way or the other
    begin
      file.fsync
    rescue StandardError
      file.flush
    end
  end

  # closing the sql file
  base_sql_file.close
  sql_file.close

  # reporting final condition
  runner.registerFinalCondition("Generated report with #{sections_made} sections to #{html_out_path}.")

  true
end