openstudio-extension 0.2.0 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -810,6 +810,7 @@ module OsLib_Reporting
810
810
  summary_types << ['Heating Capacity', 'maxHeatingCapacity', 'W', 1, 'Btu/hr', 1]
811
811
  summary_types << ['Cooling Capacity', 'maxCoolingCapacity', 'W', 1, 'ton', 1]
812
812
  summary_types << ['Water Flow Rate', 'maxWaterFlowRate', 'm^3/s', 4, 'gal/min', 2]
813
+ summary_types << ['Rated Power', 'ratedPower', 'W', 1, 'W', 1]
813
814
  summary_types.each do |s|
814
815
  val_name = s[0]
815
816
  val_method = s[1]
@@ -1212,37 +1213,34 @@ module OsLib_Reporting
1212
1213
  thermal_zones.each do |zone|
1213
1214
  total_loop_floor_area += zone.floorArea
1214
1215
  end
1215
- #julien
1216
+
1216
1217
  source_units = 'm^2'
1217
1218
  if is_ip_units
1218
1219
  target_units = 'ft^2'
1219
1220
  else
1220
1221
  target_units = source_units
1221
1222
  end
1222
- total_loop_floor_area_ip = OpenStudio.convert(total_loop_floor_area, source_units, target_units).get
1223
- total_loop_floor_area_ip_neat = OpenStudio.toNeatString(total_loop_floor_area_ip, 0, true)
1223
+ total_loop_floor_area = OpenStudio.convert(total_loop_floor_area, source_units, target_units).get
1224
+ total_loop_floor_area_neat = OpenStudio.toNeatString(total_loop_floor_area, 0, true)
1224
1225
 
1225
1226
  # output zone and terminal data
1226
- #julien
1227
1227
  if is_ip_units
1228
- output_data_air_loops[:data] << ['Thermal Zones', 'Total Floor Area', "#{total_loop_floor_area_ip_neat} ft^2", '', thermal_zones.size]
1228
+ output_data_air_loops[:data] << ['Thermal Zones', 'Total Floor Area', "#{total_loop_floor_area_neat} ft^2", '', thermal_zones.size]
1229
1229
  else
1230
- output_data_air_loops[:data] << ['Thermal Zones', 'Total Floor Area', "#{total_loop_floor_area_ip_neat} m^2", '', thermal_zones.size]
1230
+ output_data_air_loops[:data] << ['Thermal Zones', 'Total Floor Area', "#{total_loop_floor_area_neat} m^2", '', thermal_zones.size]
1231
+ end
1232
+
1233
+ # heating and cooling temperature range data
1234
+ source_units = 'C'
1235
+ if is_ip_units
1236
+ target_units = 'F'
1237
+ target_units_display = 'F'
1238
+ else
1239
+ target_units = source_units
1240
+ target_units_display = 'C'
1231
1241
  end
1232
1242
  if cooling_temp_ranges.empty?
1233
1243
  cooling_temp_ranges_pretty = "can't inspect schedules"
1234
-
1235
- #julien
1236
- source_units = 'C'
1237
- if is_ip_units
1238
- target_units = 'F'
1239
- target_units_display = "F"
1240
- else
1241
- target_units = source_units
1242
- target_units_display = "C"
1243
- end
1244
-
1245
-
1246
1244
  else
1247
1245
  cooling_temp_ranges_pretty = "#{OpenStudio.convert(cooling_temp_ranges.min, source_units, target_units).get.round(1)} to #{OpenStudio.convert(cooling_temp_ranges.max, source_units, target_units).get.round(1)}"
1248
1246
  end
@@ -1251,17 +1249,6 @@ module OsLib_Reporting
1251
1249
  else
1252
1250
  heating_temps_ranges_pretty = "#{OpenStudio.convert(heating_temps_ranges.min, source_units, target_units).get.round(1)} to #{OpenStudio.convert(heating_temps_ranges.max, source_units, target_units).get.round(1)}"
1253
1251
  end
1254
-
1255
- #julien
1256
- source_units = 'C'
1257
- if is_ip_units
1258
- target_units = 'F'
1259
- target_units_display = "F"
1260
- else
1261
- target_units = source_units
1262
- target_units_display = "C"
1263
- end
1264
- #julien => ok? Tjs dans la boucle?
1265
1252
  output_data_air_loops[:data] << ['Thermal Zones', 'Cooling Setpoint Range', "#{cooling_temp_ranges_pretty} #{target_units_display}", '', '']
1266
1253
  output_data_air_loops[:data] << ['Thermal Zones', 'Heating Setpoint Range', "#{heating_temps_ranges_pretty} #{target_units_display}", '', '']
1267
1254
  output_data_air_loops[:data] << ['Terminal Types Used', terminals.uniq.sort.join(', '), '', '', terminals.size]
@@ -3024,6 +3011,13 @@ module OsLib_Reporting
3024
3011
  ann_env_pd = OsLib_Reporting.ann_env_pd(sqlFile)
3025
3012
  if ann_env_pd
3026
3013
 
3014
+ # store values about humidity fir reguster values
3015
+ zone_max_hours_over_70_rh = 0
3016
+ zone_max_hours_over_55_rh = 0
3017
+ rh_hours_threshold = 10 #hr
3018
+ num_zones_x_hours_over_70 = 0
3019
+ num_zones_x_hours_over_55 = 0
3020
+
3027
3021
  # get keys
3028
3022
  keys = sqlFile.availableKeyValues(ann_env_pd, 'Hourly', 'Zone Air Relative Humidity')
3029
3023
  keys.each do |key|
@@ -3032,6 +3026,10 @@ module OsLib_Reporting
3032
3026
  humidity_bins[k] = 0
3033
3027
  end
3034
3028
 
3029
+ # reset humidity zone flag
3030
+ zone_rh_count_hr_55 = 0.0
3031
+ zone_rh_count_hr_70 = 0.0
3032
+
3035
3033
  # get desired variable
3036
3034
  output_timeseries = sqlFile.timeSeries(ann_env_pd, 'Hourly', 'Zone Air Relative Humidity', key)
3037
3035
  # loop through timeseries and move the data from an OpenStudio timeseries to a normal Ruby array (vector)
@@ -3079,11 +3077,34 @@ module OsLib_Reporting
3079
3077
  else
3080
3078
  row_color << ''
3081
3079
  end
3080
+
3081
+ # populate rh data for register_values
3082
+ # catch greater than 70 and 80 for runner.registerValue
3083
+ if ['55-60','60-65','65-70','70-75','75-80','>= 80'].include?(k)
3084
+ zone_rh_count_hr_55 += v
3085
+ end
3086
+ if ['70-75','75-80','>= 80'].include?(k)
3087
+ zone_rh_count_hr_70 += v
3088
+ end
3089
+
3082
3090
  end
3083
3091
  row_data += ["#{mean.round(1)} (%)"]
3084
3092
  row_color += ['']
3085
3093
  humidity_table[:data] << row_data
3086
3094
  humidity_table[:data_color] << row_color
3095
+
3096
+ # apply rh zones and max hours
3097
+ if zone_rh_count_hr_55 >= rh_hours_threshold then num_zones_x_hours_over_55 += 1 end
3098
+ if zone_rh_count_hr_70 >= rh_hours_threshold then num_zones_x_hours_over_70 += 1 end
3099
+ if zone_max_hours_over_55_rh < zone_rh_count_hr_55 then zone_max_hours_over_55_rh = zone_rh_count_hr_55 end
3100
+ if zone_max_hours_over_70_rh < zone_rh_count_hr_70 then zone_max_hours_over_70_rh = zone_rh_count_hr_70 end
3101
+
3102
+ # add rh runner.registerValues to be used as output in analyses
3103
+ runner.registerValue("zone_max_hours_over_70_rh",zone_max_hours_over_70_rh,"hr")
3104
+ runner.registerValue("zone_max_hours_over_55_rh",zone_max_hours_over_55_rh,"hr")
3105
+ runner.registerValue("num_zones_x_hours_over_70",num_zones_x_hours_over_70,"zones")
3106
+ runner.registerValue("num_zones_x_hours_over_55",num_zones_x_hours_over_55,"zones")
3107
+
3087
3108
  end
3088
3109
  else
3089
3110
  runner.registerWarning('An annual simulation was not run. Cannot get annual timeseries data')
@@ -4649,4 +4670,86 @@ module OsLib_Reporting
4649
4670
 
4650
4671
  return @schedules_overview_section
4651
4672
  end
4652
- end
4673
+
4674
+ # create measure_warning_section (creates tables and runner.registerValues)
4675
+ def self.measure_warning_section(model, sqlFile, runner, name_only = false, is_ip_units = true)
4676
+ # array to hold tables
4677
+ measure_tables = []
4678
+
4679
+ # gather data for section
4680
+ @measure_warnings_section = {}
4681
+ @measure_warnings_section[:title] = 'Measure Warnings'
4682
+ @measure_warnings_section[:tables] = measure_tables
4683
+
4684
+ # stop here if only name is requested this is used to populate display name for arguments
4685
+ if name_only == true
4686
+ return @measure_warnings_section
4687
+ end
4688
+
4689
+ # will be used for registerValues
4690
+ num_measures_with_warnings = 0
4691
+ num_warnings = 0
4692
+ num_measures = 0
4693
+
4694
+ # loop through workflow steps
4695
+ runner.workflow.workflowSteps.each do |step|
4696
+ if step.to_MeasureStep.is_initialized
4697
+ measure_step = step.to_MeasureStep.get
4698
+ measure_name = measure_step.measureDirName
4699
+ num_measures += 1
4700
+ if measure_step.name.is_initialized
4701
+ measure_name = measure_step.name.get # this is instance name in PAT
4702
+ end
4703
+ if measure_step.result.is_initialized
4704
+ result = measure_step.result.get
4705
+ # create and populate table if warnings exist
4706
+ if result.warnings.size > 0
4707
+ measure_table_01 = {}
4708
+ measure_table_01[:title] = measure_name
4709
+ measure_table_01[:header] = ['Warning']
4710
+ measure_table_01[:data] = []
4711
+ num_measures_with_warnings += 1
4712
+
4713
+ # step through warnings
4714
+ start_counter = num_warnings
4715
+ result.warnings.each do |step|
4716
+ # add rows to table and register value
4717
+ num_warnings += 1
4718
+ if num_warnings < start_counter + 25
4719
+ measure_table_01[:data] << [step.logMessage]
4720
+ else
4721
+ measure_table_01[:data] << ["* See OSW file for full list of warnings. This measure has #{result.warnings.size} warnings."]
4722
+ end
4723
+ end
4724
+ # add table to section
4725
+ measure_tables << measure_table_01
4726
+ end
4727
+ else
4728
+ # puts "No result for #{measure_name}"
4729
+ end
4730
+ else
4731
+ # puts "This step is not a measure"
4732
+ end
4733
+ end
4734
+
4735
+ # add summary table (even when there are no warnings)
4736
+ measure_table_summary = {}
4737
+ measure_table_summary[:title] = "Measure Warning Summary"
4738
+ measure_table_summary[:header] = ['Description','Count']
4739
+ measure_table_summary[:data] = []
4740
+
4741
+ # add summary rows
4742
+ measure_table_summary[:data] << ['Number of measures in workflow',num_measures]
4743
+ measure_table_summary[:data] << ['Number of measures with warnings',num_measures_with_warnings]
4744
+ measure_table_summary[:data] << ['Total number of warnings',num_warnings]
4745
+
4746
+ # add table to section
4747
+ measure_tables << measure_table_summary
4748
+
4749
+ runner.registerValue("number_of_measures_with_warnings", num_measures_with_warnings)
4750
+ runner.registerValue("number_warnings", num_warnings)
4751
+
4752
+ return @measure_warnings_section
4753
+ end
4754
+
4755
+ end
@@ -49,14 +49,17 @@ module OpenStudio
49
49
  setup_subtasks(@name)
50
50
  end
51
51
 
52
- def set_extension_class(extension_class)
52
+ def set_extension_class(extension_class, github_repo = '')
53
53
  @extension_class = extension_class
54
54
  @extension = extension_class.new
55
55
  @root_dir = @extension.root_dir
56
- @measures_dir = @extension.measures_dir
56
+ # Catch if measures_dir is nil, then just make it an empty string
57
+ @measures_dir = @extension.measures_dir || ''
58
+ @staged_path = @measures_dir + '/staged'
57
59
  @core_dir = @extension.core_dir
58
60
  @doc_templates_dir = @extension.doc_templates_dir
59
61
  @files_dir = @extension.files_dir
62
+ @github_repo = github_repo
60
63
  end
61
64
 
62
65
  private
@@ -65,22 +68,20 @@ module OpenStudio
65
68
  namespace name do
66
69
  desc 'Run the CLI task to check for measure updates'
67
70
  task update_measures: ['measures:add_license', 'measures:add_readme', 'measures:copy_resources', 'update_copyright'] do
68
- puts 'updating measures...'
71
+ puts 'updating measures'
69
72
  runner = OpenStudio::Extension::Runner.new(Dir.pwd)
70
73
  runner.update_measures(@measures_dir)
71
74
  end
72
75
 
73
76
  desc 'List measures'
74
77
  task :list_measures do
75
- puts 'Listing measures...'
78
+ puts 'Listing measures'
76
79
  runner = OpenStudio::Extension::Runner.new(Dir.pwd)
77
80
  runner.list_measures(@measures_dir)
78
81
  end
79
82
 
80
83
  desc 'Use openstudio system ruby to run tests'
81
84
  task :test_with_openstudio do
82
- # puts Dir.pwd
83
- # puts Rake.original_dir
84
85
  puts 'testing with openstudio'
85
86
  runner = OpenStudio::Extension::Runner.new(Dir.pwd)
86
87
  result = runner.test_measures_with_cli(@measures_dir)
@@ -90,12 +91,6 @@ module OpenStudio
90
91
  end
91
92
  end
92
93
 
93
- # TODO: Implement this eventually... comment out for now.
94
- # desc 'Use openstudio docker image to run tests'
95
- # task :test_with_docker do
96
- # puts 'testing with docker'
97
- # end
98
-
99
94
  # namespace for measure operations
100
95
  namespace 'measures' do
101
96
  desc 'Copy the resources files to individual measures'
@@ -143,14 +138,233 @@ module OpenStudio
143
138
  runner.update_copyright(@root_dir, @doc_templates_dir)
144
139
  end
145
140
 
146
- desc 'Copy the measures to a location that can be uploaded to BCL'
147
- task :stage_bcl do
148
- puts 'Staging measures for BCL'
141
+ desc 'Print the change log from GitHub. Date format: yyyy-mm-dd'
142
+ task :change_log, [:start_date, :end_date, :apikey] do |t, args|
143
+ require 'change_log'
144
+ cl = ChangeLog.new(@github_repo, *args)
145
+ cl.process
146
+ cl.print_issues
149
147
  end
150
148
 
151
- desc 'Upload measures from the specified location.'
152
- task :push_bcl do
153
- puts 'Push measures to BCL'
149
+ namespace 'bcl' do
150
+ desc 'Test BCL login'
151
+ task :test_login do
152
+ puts 'test BCL login'
153
+ bcl = ::BCL::ComponentMethods.new
154
+ bcl.login
155
+ end
156
+
157
+ # for custom search, populate env var: bcl_search_keyword
158
+ desc 'Search BCL'
159
+ task :search_measures do
160
+ puts 'test search BCL'
161
+ bcl = ::BCL::ComponentMethods.new
162
+ bcl.login
163
+
164
+ # check for env var specifying keyword first
165
+ if ENV['bcl_search_keyword']
166
+ keyword = ENV['bcl_search_keyword']
167
+ else
168
+ keyword = 'Space'
169
+ end
170
+ num_results = 10
171
+ # bcl.search params: search_string, filter_string, return_all_results?
172
+ puts "searching BCL measures for keyword: #{keyword}"
173
+ results = bcl.search(keyword, "fq[]=bundle:nrel_measure&show_rows=#{num_results}", false)
174
+ puts "there are #{results[:result].count} results"
175
+ results[:result].each do |res|
176
+ puts(res[:measure][:name]).to_s
177
+ end
178
+ end
179
+
180
+ # to call with argument: "openstudio:bcl:stage[true]" (true = remove existing staged content)
181
+ desc 'Copy the measures/components to a location that can be uploaded to BCL'
182
+ task :stage, [:reset] do |t, args|
183
+ puts 'Staging measures for BCL'
184
+ # initialize BCL and login
185
+ bcl = ::BCL::ComponentMethods.new
186
+ bcl.login
187
+
188
+ # process reset options: true to clear out old staged content
189
+ options = { reset: false }
190
+ if args[:reset].to_s == 'true'
191
+ options[:reset] = true
192
+ end
193
+
194
+ # ensure staged dir exists
195
+ FileUtils.mkdir_p(@staged_path)
196
+
197
+ # delete existing tarballs if reset is true
198
+ if options[:reset]
199
+ puts 'Deleting existing staged content'
200
+ FileUtils.rm_rf(Dir.glob("#{@staged_path}/*"))
201
+ end
202
+
203
+ # create new and existing directories
204
+ FileUtils.mkdir_p(@staged_path.to_s + '/update')
205
+ FileUtils.mkdir_p(@staged_path.to_s + '/push/component')
206
+ FileUtils.mkdir_p(@staged_path.to_s + '/push/measure')
207
+
208
+ # keep track of noop, update, push
209
+ noops = 0
210
+ new_ones = 0
211
+ updates = 0
212
+
213
+ # get all content directories to process
214
+ dirs = Dir.glob("#{@measures_dir}/*")
215
+
216
+ dirs.each do |dir|
217
+ next if dir.include?('Rakefile') || File.basename(dir) == 'staged'
218
+ current_d = Dir.pwd
219
+ content_name = File.basename(dir)
220
+ puts '', '---'
221
+ puts "Generating #{content_name}"
222
+
223
+ Dir.chdir(dir)
224
+
225
+ # figure out whether to upload new or update existing
226
+ files = Pathname.glob('**/*')
227
+ uuid = nil
228
+ vid = nil
229
+ content_type = 'measure'
230
+
231
+ paths = []
232
+ files.each do |file|
233
+ # don't tar tests/outputs directory
234
+ next if file.to_s.start_with?('tests/output') # From measure testing process
235
+ next if file.to_s.start_with?('tests/test') # From openstudio-measure-tester-gem
236
+ next if file.to_s.start_with?('tests/coverage') # From openstudio-measure-tester-gem
237
+ next if file.to_s.start_with?('test_results') # From openstudio-measure-tester-gem
238
+ paths << file.to_s
239
+ if file.to_s =~ /^.{0,2}component.xml$/ || file.to_s =~ /^.{0,2}measure.xml$/
240
+ if file.to_s.match?(/^.{0,2}component.xml$/)
241
+ content_type = 'component'
242
+ end
243
+ # extract uuid and vid
244
+ uuid, vid = bcl.uuid_vid_from_xml(file)
245
+ end
246
+ end
247
+ puts "UUID: #{uuid}, VID: #{vid}"
248
+
249
+ # note: if uuid is missing, will assume new content
250
+ action = bcl.search_by_uuid(uuid, vid)
251
+ puts "#{content_name} ACTION TO TAKE: #{action}"
252
+ # new content functionality needs to know if measure or component. update is agnostic.
253
+ if action == 'noop' # ignore up-to-date content
254
+ puts " - WARNING: local #{content_name} uuid and vid match BCL... no update will be performed"
255
+ noops += 1
256
+ next
257
+ elsif action == 'update'
258
+ # puts "#{content_name} labeled as update for BCL"
259
+ destination = @staged_path + '/' + action + '/' + "#{content_name}.tar.gz"
260
+ updates += 1
261
+ elsif action == 'push'
262
+ # puts "#{content_name} labeled as new content for BCL"
263
+ destination = @staged_path + '/' + action + '/' + content_type + "/#{content_name}.tar.gz"
264
+ new_ones += 1
265
+ end
266
+
267
+ puts "destination: #{destination}"
268
+
269
+ # copy over only if 'reset_receipts' is set to TRUE. otherwise ignore if file exists already
270
+ if File.exist?(destination)
271
+ if options[:reset]
272
+ FileUtils.rm(destination)
273
+ ::BCL.tarball(destination, paths)
274
+ else
275
+ puts "*** WARNING: File #{content_name}.tar.gz already exists in staged directory... keeping existing file. To overwrite, set reset_receipts arg to true ***"
276
+ end
277
+ else
278
+ ::BCL.tarball(destination, paths)
279
+ end
280
+ Dir.chdir(current_d)
281
+ end
282
+ puts '', "****STAGING DONE**** #{new_ones} new content, #{updates} updates, #{noops} skipped (already up-to-date on BCL)", ''
283
+ end
284
+
285
+ desc 'Upload measures from the specified location.'
286
+ task :push do
287
+ puts 'Push measures to BCL'
288
+
289
+ # initialize BCL and login
290
+ bcl = ::BCL::ComponentMethods.new
291
+ bcl.login
292
+ reset = false
293
+
294
+ total_count = 0
295
+ successes = 0
296
+ errors = 0
297
+ skipped = 0
298
+
299
+ # grab all the new measure and component tar files and push to bcl
300
+ ['measure', 'component'].each do |content_type|
301
+ items = []
302
+ paths = Pathname.glob(@staged_path.to_s + "/push/#{content_type}/*.tar.gz")
303
+ paths.each do |path|
304
+ # puts path
305
+ items << path.to_s
306
+ end
307
+
308
+ items.each do |item|
309
+ puts item.split('/').last
310
+ total_count += 1
311
+
312
+ receipt_file = File.dirname(item) + '/' + File.basename(item, '.tar.gz') + '.receipt'
313
+ if !reset && File.exist?(receipt_file)
314
+ skipped += 1
315
+ puts 'SKIP: receipt file found'
316
+ next
317
+ end
318
+
319
+ valid, res = bcl.push_content(item, true, "nrel_#{content_type}")
320
+ if valid
321
+ successes += 1
322
+ else
323
+ errors += 1
324
+ if res.key?(:error)
325
+ puts " ERROR MESSAGE: #{res[:error]}"
326
+ else
327
+ puts "ERROR: #{res.inspect.chomp}"
328
+ end
329
+ end
330
+ puts '', '---'
331
+ end
332
+ end
333
+
334
+ # grab all the updated content (measures and components) tar files and push to bcl
335
+ items = []
336
+ paths = Pathname.glob(@staged_path.to_s + '/update/*.tar.gz')
337
+ paths.each do |path|
338
+ # puts path
339
+ items << path.to_s
340
+ end
341
+ items.each do |item|
342
+ puts item.split('/').last
343
+ total_count += 1
344
+
345
+ receipt_file = File.dirname(item) + '/' + File.basename(item, '.tar.gz') + '.receipt'
346
+ if !reset && File.exist?(receipt_file)
347
+ skipped += 1
348
+ puts 'SKIP: receipt file found'
349
+ next
350
+ end
351
+
352
+ valid, res = bcl.update_content(item, true)
353
+ if valid
354
+ successes += 1
355
+ else
356
+ errors += 1
357
+ if res.key?(:error)
358
+ puts " ERROR MESSAGE: #{res[:error]}"
359
+ else
360
+ puts "ERROR MESSAGE: #{res.inspect.chomp}"
361
+ end
362
+ end
363
+ puts '', '---'
364
+ end
365
+
366
+ puts "****UPLOAD DONE**** #{total_count} total, #{successes} success, #{errors} failures, #{skipped} skipped"
367
+ end
154
368
  end
155
369
  end
156
370
  end