openstudio-extension 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/CHANGELOG.md +12 -0
  4. data/Gemfile +2 -0
  5. data/Jenkinsfile +1 -1
  6. data/LICENSE.md +1 -1
  7. data/Rakefile +1 -1
  8. data/doc_templates/LICENSE.md +1 -1
  9. data/doc_templates/copyright_erb.txt +1 -1
  10. data/doc_templates/copyright_js.txt +1 -1
  11. data/doc_templates/copyright_ruby.txt +1 -1
  12. data/init_templates/openstudio_module.rb +1 -1
  13. data/init_templates/spec.rb +1 -1
  14. data/init_templates/spec_helper.rb +1 -1
  15. data/init_templates/version.rb +1 -1
  16. data/lib/change_log.rb +1 -1
  17. data/lib/measures/openstudio_extension_test_measure/LICENSE.md +1 -1
  18. data/lib/measures/openstudio_extension_test_measure/measure.rb +1 -1
  19. data/lib/measures/openstudio_extension_test_measure/measure.xml +12 -12
  20. data/lib/measures/openstudio_extension_test_measure/resources/os_lib_helper_methods.rb +15 -2
  21. data/lib/openstudio-extension.rb +1 -1
  22. data/lib/openstudio/extension.rb +1 -1
  23. data/lib/openstudio/extension/core/CreateResults.rb +1 -1
  24. data/lib/openstudio/extension/core/check_air_sys_temps.rb +1 -1
  25. data/lib/openstudio/extension/core/check_calibration.rb +1 -1
  26. data/lib/openstudio/extension/core/check_cond_zns.rb +1 -1
  27. data/lib/openstudio/extension/core/check_domestic_hot_water.rb +1 -1
  28. data/lib/openstudio/extension/core/check_envelope_conductance.rb +1 -1
  29. data/lib/openstudio/extension/core/check_eui_by_end_use.rb +1 -1
  30. data/lib/openstudio/extension/core/check_eui_reasonableness.rb +1 -1
  31. data/lib/openstudio/extension/core/check_fan_pwr.rb +1 -1
  32. data/lib/openstudio/extension/core/check_internal_loads.rb +1 -1
  33. data/lib/openstudio/extension/core/check_mech_sys_capacity.rb +1 -1
  34. data/lib/openstudio/extension/core/check_mech_sys_efficiency.rb +1 -1
  35. data/lib/openstudio/extension/core/check_mech_sys_part_load_eff.rb +1 -1
  36. data/lib/openstudio/extension/core/check_mech_sys_type.rb +1 -1
  37. data/lib/openstudio/extension/core/check_part_loads.rb +1 -1
  38. data/lib/openstudio/extension/core/check_placeholder.rb +1 -1
  39. data/lib/openstudio/extension/core/check_plant_cap.rb +1 -1
  40. data/lib/openstudio/extension/core/check_plant_temps.rb +1 -1
  41. data/lib/openstudio/extension/core/check_plenum_loads.rb +1 -1
  42. data/lib/openstudio/extension/core/check_pump_pwr.rb +1 -1
  43. data/lib/openstudio/extension/core/check_sch_coord.rb +1 -1
  44. data/lib/openstudio/extension/core/check_schedules.rb +1 -1
  45. data/lib/openstudio/extension/core/check_simultaneous_heating_and_cooling.rb +1 -1
  46. data/lib/openstudio/extension/core/check_supply_air_and_thermostat_temp_difference.rb +1 -1
  47. data/lib/openstudio/extension/core/check_weather_files.rb +1 -1
  48. data/lib/openstudio/extension/core/deer_vintages.rb +1 -1
  49. data/lib/openstudio/extension/core/os_lib_aedg_measures.rb +5 -5
  50. data/lib/openstudio/extension/core/os_lib_constructions.rb +1 -1
  51. data/lib/openstudio/extension/core/os_lib_geometry.rb +1 -1
  52. data/lib/openstudio/extension/core/os_lib_helper_methods.rb +15 -2
  53. data/lib/openstudio/extension/core/os_lib_hvac.rb +1 -1
  54. data/lib/openstudio/extension/core/os_lib_lighting_and_equipment.rb +1 -1
  55. data/lib/openstudio/extension/core/os_lib_model_generation.rb +351 -207
  56. data/lib/openstudio/extension/core/os_lib_model_simplification.rb +1 -1
  57. data/lib/openstudio/extension/core/os_lib_outdoorair_and_infiltration.rb +1 -1
  58. data/lib/openstudio/extension/core/os_lib_reporting_qaqc.rb +1 -1
  59. data/lib/openstudio/extension/core/os_lib_schedules.rb +1 -1
  60. data/lib/openstudio/extension/rake_task.rb +1 -1
  61. data/lib/openstudio/extension/runner.rb +17 -5
  62. data/lib/openstudio/extension/runner_config.rb +1 -1
  63. data/lib/openstudio/extension/version.rb +2 -2
  64. data/openstudio-extension.gemspec +6 -5
  65. metadata +29 -16
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -204,7 +204,7 @@ module OsLib_AedgMeasures
204
204
  @aedgK12HowToTipHash['EL20'] = 'EL20 Twenty-Four Hour Lighting'
205
205
  @aedgK12HowToTipHash['EL21'] = 'EL21 Exterior Lighting Power-Parking Lots and Drives'
206
206
  @aedgK12HowToTipHash['EL22'] = 'EL22 Exterior Lighting Power-Walkways'
207
- @aedgK12HowToTipHash['EL23'] = 'EL23 Decorative Façade Lighting'
207
+ @aedgK12HowToTipHash['EL23'] = 'EL23 Decorative Facade Lighting'
208
208
  @aedgK12HowToTipHash['EL24'] = 'EL24 Sources'
209
209
  @aedgK12HowToTipHash['EL25'] = 'EL25 Controls'
210
210
 
@@ -273,7 +273,7 @@ module OsLib_AedgMeasures
273
273
 
274
274
  # commissioning tips
275
275
  @aedgK12HowToTipHash['QA01'] = 'QA1 Design and Construction Team'
276
- @aedgK12HowToTipHash['QA02'] = 'QA2 Owners Project Requirements and Basis of Design'
276
+ @aedgK12HowToTipHash['QA02'] = 'QA2 Owner\'s Project Requirements and Basis of Design'
277
277
  @aedgK12HowToTipHash['QA03'] = 'QA3 Selection of Quality Assurance Provider'
278
278
  @aedgK12HowToTipHash['QA04'] = 'QA4 Design and Construction Schedule'
279
279
  @aedgK12HowToTipHash['QA05'] = 'QA5 Design Review'
@@ -398,7 +398,7 @@ module OsLib_AedgMeasures
398
398
  aedgSmMdOffHowToTipHash['EL20'] = 'EL20 Twenty-Four Hour Lighting'
399
399
  aedgSmMdOffHowToTipHash['EL21'] = 'EL21 Exterior Lighting Power-Parking Lots and Drives'
400
400
  aedgSmMdOffHowToTipHash['EL22'] = 'EL22 Exterior Lighting Power-Walkways'
401
- aedgSmMdOffHowToTipHash['EL23'] = 'EL23 Decorative Façade Lighting'
401
+ aedgSmMdOffHowToTipHash['EL23'] = 'EL23 Decorative Facade Lighting'
402
402
  aedgSmMdOffHowToTipHash['EL24'] = 'EL24 Sources'
403
403
  aedgSmMdOffHowToTipHash['EL25'] = 'EL25 Controls'
404
404
 
@@ -463,7 +463,7 @@ Gas-Fired Boiler"
463
463
  # commissioning tips
464
464
  aedgSmMdOffHowToTipHash['QA01'] = 'QA1 Selecting the Design and Construction Team'
465
465
  aedgSmMdOffHowToTipHash['QA02'] = 'QA2 Selecting the QA Provider'
466
- aedgSmMdOffHowToTipHash['QA03'] = 'QA3 Owners Project Requirements (OPR) and Basis of Design (BoD)'
466
+ aedgSmMdOffHowToTipHash['QA03'] = 'QA3 Owner\'s Project Requirements (OPR) and Basis of Design (BoD)'
467
467
  aedgSmMdOffHowToTipHash['QA04'] = 'QA4 Design and Construction Schedule'
468
468
  aedgSmMdOffHowToTipHash['QA05'] = 'QA5 Design Review'
469
469
  aedgSmMdOffHowToTipHash['QA06'] = 'QA6 Defining QA at Pre-Bid'
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -265,7 +265,20 @@ module OsLib_HelperMethods
265
265
  result = measure_step.result.get
266
266
  result.stepValues.each do |arg|
267
267
  name = arg.name
268
- value = arg.valueAsVariant.to_s
268
+ # check if value, double, int, or bool
269
+ value_type = arg.variantType.valueDescription
270
+ if value_type == "Double"
271
+ value = arg.valueAsDouble
272
+ elsif value_type == "Integer"
273
+ value = arg.valueAsInteger
274
+ elsif value_type == "Boolean"
275
+ value = arg.valueAsBoolean
276
+ elsif value_type == "String"
277
+ value = arg.valueAsString
278
+ else
279
+ # catchall for unexpected value types
280
+ value = arg.valueAsVariant.to_s
281
+ end
269
282
  if name == arg_name
270
283
  arg_name_value[:value] = value
271
284
  arg_name_value[:measure_name] = measure_name
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,8 @@
1
+ # ComStock(TM), Copyright (c) 2020 Alliance for Sustainable Energy, LLC. All rights reserved.
2
+ # See top level LICENSE.txt file for license terms.
3
+
1
4
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
5
+ # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
6
  # All rights reserved.
4
7
  # Redistribution and use in source and binary forms, with or without
5
8
  # modification, are permitted provided that the following conditions are met:
@@ -37,7 +40,6 @@ module OsLib_ModelGeneration
37
40
  # simple list of building types that are valid for get_space_types_from_building_type
38
41
  # for general public use use extended = false
39
42
  def get_building_types(extended = false)
40
-
41
43
  # get building_types
42
44
  if extended
43
45
  doe = get_doe_building_types(true)
@@ -127,7 +129,6 @@ module OsLib_ModelGeneration
127
129
  # simple list of templates that are valid for get_space_types_from_building_type
128
130
  # for general public use use extended = false
129
131
  def get_templates(extended = false)
130
-
131
132
  # get templates
132
133
  if extended
133
134
  doe = get_doe_templates(true)
@@ -157,6 +158,12 @@ module OsLib_ModelGeneration
157
158
  array << '90.1-2007'
158
159
  array << '90.1-2010'
159
160
  array << '90.1-2013'
161
+ array << 'ComStock DOE Ref Pre-1980'
162
+ array << 'ComStock DOE Ref 1980-2004'
163
+ array << 'ComStock 90.1-2004'
164
+ array << 'ComStock 90.1-2007'
165
+ array << 'ComStock 90.1-2010'
166
+ array << 'ComStock 90.1-2013'
160
167
  if extended
161
168
  # array << '189.1-2009' # if turn this on need to update space_type_array for RetailStripmall
162
169
  array << 'NREL ZNE Ready 2017'
@@ -228,10 +235,9 @@ module OsLib_ModelGeneration
228
235
  # get_doe_climate_zones
229
236
  # for general public use use extended = false
230
237
  def get_doe_climate_zones(extended = false, extra = nil)
231
-
232
238
  # Lookup From Model should be added as an option where appropriate in the measure
233
239
  cz_choices = OpenStudio::StringVector.new
234
- if extra != nil
240
+ if !extra.nil?
235
241
  cz_choices << extra
236
242
  end
237
243
  cz_choices << 'ASHRAE 169-2013-1A'
@@ -262,10 +268,9 @@ module OsLib_ModelGeneration
262
268
  # get_deer_climate_zones
263
269
  # for general public use use extended = false
264
270
  def get_deer_climate_zones(extended = false, extra = nil)
265
-
266
271
  # Lookup From Model should be added as an option where appropriate in the measure
267
272
  cz_choices = OpenStudio::StringVector.new
268
- if extra != nil
273
+ if !extra.nil?
269
274
  cz_choices << extra
270
275
  end
271
276
  cz_choices << 'CEC T24-CEC1'
@@ -309,27 +314,27 @@ module OsLib_ModelGeneration
309
314
  primary_footprint = 73958.0
310
315
  primary_p = 619.0 # wrote measure using calculate_perimeter method in os_lib_geometry
311
316
  primary_ns_ew_ratio = 2.829268293 # estimated from ratio of ns/ew total wall area
312
- primary_width = Math.sqrt(primary_footprint/primary_ns_ew_ratio)
317
+ primary_width = Math.sqrt(primary_footprint / primary_ns_ew_ratio)
313
318
  primary_p_min = 2 * (primary_width + primary_width / primary_footprint)
314
319
  primary_p_mult = primary_p / primary_p_min
315
320
 
316
321
  secondary_footprint = 210887.0 / 2.0 # floor area divided by area instead of true footprint 128112.0)
317
322
  secondary_p = 708.0 # wrote measure using calculate_perimeter method in os_lib_geometry
318
323
  secondary_ns_ew_ratio = 2.069230769 # estimated from ratio of ns/ew total wall area
319
- secondary_width = Math.sqrt(secondary_footprint/secondary_ns_ew_ratio)
324
+ secondary_width = Math.sqrt(secondary_footprint / secondary_ns_ew_ratio)
320
325
  secondary_p_min = 2 * (secondary_width + secondary_width / secondary_footprint)
321
326
  secondary_p_mult = secondary_p / secondary_p_min
322
327
 
323
328
  outpatient_footprint = 40946.0 / 3.0 # floor area divided by area instead of true footprint 17872.0)
324
329
  outpatient_p = 537.0 # wrote measure using calculate_perimeter method in os_lib_geometry
325
330
  outpatient_ns_ew_ratio = 1.56448737 # estimated from ratio of ns/ew total wall area
326
- outpatient_width = Math.sqrt(outpatient_footprint/outpatient_ns_ew_ratio)
327
- outpatient_p_min = 2 * (outpatient_width + outpatient_footprint/outpatient_width)
331
+ outpatient_width = Math.sqrt(outpatient_footprint / outpatient_ns_ew_ratio)
332
+ outpatient_p_min = 2 * (outpatient_width + outpatient_footprint / outpatient_width)
328
333
  outpatient_p_mult = outpatient_p / outpatient_p_min
329
334
 
330
- #primary_aspet_ratio = calc_aspect_ratio(73958.0, 2060.0)
331
- #secondary_aspet_ratio = calc_aspect_ratio(128112.0, 2447.0)
332
- #outpatient_aspet_ratio = calc_aspect_ratio(14782.0, 588.0)
335
+ # primary_aspet_ratio = calc_aspect_ratio(73958.0, 2060.0)
336
+ # secondary_aspet_ratio = calc_aspect_ratio(128112.0, 2447.0)
337
+ # outpatient_aspet_ratio = calc_aspect_ratio(14782.0, 588.0)
333
338
  supermarket_a = 45001.0
334
339
  supermarket_p = 866.0
335
340
  supermarket_wwr = 1880.0 / (supermarket_p * 20.0)
@@ -402,13 +407,13 @@ module OsLib_ModelGeneration
402
407
  # TODO: - Confirm that these work for all standards
403
408
  # DOE Prototypes
404
409
  if building_type == 'SecondarySchool'
405
- if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004'].include?(template)
410
+ if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004', 'ComStock DOE Ref Pre-1980', 'ComStock DOE Ref 1980-2004'].include?(template)
406
411
  hash['Auditorium'] = { ratio: 0.0504, space_type_gen: true, default: false, story_height: 26.0 }
407
412
  hash['Cafeteria'] = { ratio: 0.0319, space_type_gen: true, default: false }
408
413
  hash['Classroom'] = { ratio: 0.3528, space_type_gen: true, default: true }
409
414
  hash['Corridor'] = { ratio: 0.2144, space_type_gen: true, default: false, circ: true }
410
- hash['Gym'] = { ratio: 0.1009, space_type_gen: true, default: false , story_height: 26.0 }
411
- hash['Gym - audience'] = { ratio: 0.0637, space_type_gen: true, default: false , story_height: 26.0 }
415
+ hash['Gym'] = { ratio: 0.1009, space_type_gen: true, default: false, story_height: 26.0 }
416
+ hash['Gym - audience'] = { ratio: 0.0637, space_type_gen: true, default: false, story_height: 26.0 }
412
417
  hash['Kitchen'] = { ratio: 0.0110, space_type_gen: true, default: false }
413
418
  hash['Library'] = { ratio: 0.0429, space_type_gen: true, default: false }
414
419
  hash['Lobby'] = { ratio: 0.0214, space_type_gen: true, default: false }
@@ -421,7 +426,7 @@ module OsLib_ModelGeneration
421
426
  hash['Classroom'] = { ratio: 0.3041, space_type_gen: true, default: true }
422
427
  hash['ComputerRoom'] = { ratio: 0.0487, space_type_gen: true, default: true }
423
428
  hash['Corridor'] = { ratio: 0.2144, space_type_gen: true, default: false, circ: true }
424
- hash['Gym'] = { ratio: 0.1646, space_type_gen: true, default: false , story_height: 26.0 }
429
+ hash['Gym'] = { ratio: 0.1646, space_type_gen: true, default: false, story_height: 26.0 }
425
430
  hash['Kitchen'] = { ratio: 0.0110, space_type_gen: true, default: false }
426
431
  hash['Library'] = { ratio: 0.0429, space_type_gen: true, default: false }
427
432
  hash['Lobby'] = { ratio: 0.0214, space_type_gen: true, default: false }
@@ -430,7 +435,7 @@ module OsLib_ModelGeneration
430
435
  hash['Restroom'] = { ratio: 0.0214, space_type_gen: true, default: false }
431
436
  end
432
437
  elsif building_type == 'PrimarySchool'
433
- if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004'].include?(template)
438
+ if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004', 'ComStock DOE Ref Pre-1980', 'ComStock DOE Ref 1980-2004'].include?(template)
434
439
  # updated to 2004 which includes library vs. pre-1980
435
440
  hash['Cafeteria'] = { ratio: 0.0458, space_type_gen: true, default: false }
436
441
  hash['Classroom'] = { ratio: 0.5610, space_type_gen: true, default: true }
@@ -448,7 +453,7 @@ module OsLib_ModelGeneration
448
453
  hash['Classroom'] = { ratio: 0.4793, space_type_gen: true, default: true }
449
454
  hash['ComputerRoom'] = { ratio: 0.0236, space_type_gen: true, default: true }
450
455
  hash['Corridor'] = { ratio: 0.1633, space_type_gen: true, default: false, circ: true }
451
- hash['Gym'] = { ratio: 0.0520, space_type_gen: true, default: false}
456
+ hash['Gym'] = { ratio: 0.0520, space_type_gen: true, default: false }
452
457
  hash['Kitchen'] = { ratio: 0.0244, space_type_gen: true, default: false }
453
458
  hash['Library'] = { ratio: 0.0581, space_type_gen: true, default: false }
454
459
  hash['Lobby'] = { ratio: 0.0249, space_type_gen: true, default: false }
@@ -494,7 +499,7 @@ module OsLib_ModelGeneration
494
499
  hash['WholeBuilding - Md Office'] = { ratio: 0.0, space_type_gen: true, default: false }
495
500
  end
496
501
  elsif building_type == 'LargeOffice'
497
- if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004'].include?(template)
502
+ if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004', 'ComStock DOE Ref Pre-1980', 'ComStock DOE Ref 1980-2004'].include?(template)
498
503
  if whole_building
499
504
  hash['WholeBuilding - Lg Office'] = { ratio: 1.0, space_type_gen: true, default: true }
500
505
  else
@@ -538,7 +543,7 @@ module OsLib_ModelGeneration
538
543
  end
539
544
  end
540
545
  elsif building_type == 'SmallHotel'
541
- if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004'].include?(template)
546
+ if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004', 'ComStock DOE Ref Pre-1980', 'ComStock DOE Ref 1980-2004'].include?(template)
542
547
  hash['Corridor'] = { ratio: 0.1313, space_type_gen: true, default: false, circ: true }
543
548
  hash['Elec/MechRoom'] = { ratio: 0.0038, space_type_gen: true, default: false }
544
549
  hash['ElevatorCore'] = { ratio: 0.0113, space_type_gen: true, default: false }
@@ -909,7 +914,6 @@ module OsLib_ModelGeneration
909
914
  stories_flat = []
910
915
  stories_flat_counter = 0
911
916
  bar_hash[:stories].each_with_index do |(k, v), i|
912
- #runner.registerInfo("STORY: k: #{k}, v: #{v}, index: #{i}")
913
917
  # k is invalid in some cases, old story object that has been removed, should be from low to high including basement
914
918
  # skip if source story insn't included in building area
915
919
  if v[:story_included_in_building_area].nil? || (v[:story_included_in_building_area] == true)
@@ -1088,12 +1092,10 @@ module OsLib_ModelGeneration
1088
1092
 
1089
1093
  # remove duplicate surfaces in a space (should be done after remove duplicate and collinear points)
1090
1094
  model.getSpaces.sort.each do |space|
1091
-
1092
1095
  # secondary array to compare against
1093
1096
  surfaces_b = space.surfaces.sort
1094
1097
 
1095
1098
  space.surfaces.sort.each do |surface_a|
1096
-
1097
1099
  # delete from secondary array
1098
1100
  surfaces_b.delete(surface_a)
1099
1101
 
@@ -1103,13 +1105,11 @@ module OsLib_ModelGeneration
1103
1105
  runner.registerWarning("#{surface_a.name} and #{surface_b.name} in #{space.name} have duplicate geometry, removing #{surface_b.name}.")
1104
1106
  surface_b.remove
1105
1107
  elsif surface_a.reverseEqualVertices(surface_b)
1106
- # todo - add logic to determine which face naormal is reversed and which is correct
1108
+ # TODO: - add logic to determine which face naormal is reversed and which is correct
1107
1109
  runner.registerWarning("#{surface_a.name} and #{surface_b.name} in #{space.name} have reversed geometry, removing #{surface_b.name}.")
1108
1110
  surface_b.remove
1109
1111
  end
1110
-
1111
1112
  end
1112
-
1113
1113
  end
1114
1114
  end
1115
1115
 
@@ -1120,7 +1120,7 @@ module OsLib_ModelGeneration
1120
1120
  model.getSpaces.sort.each do |space_a|
1121
1121
  spaces_b.delete(space_a)
1122
1122
  spaces_b.each do |space_b|
1123
- #runner.registerInfo("Intersecting and matching surfaces between #{space_a.name} and #{space.name}")
1123
+ # runner.registerInfo("Intersecting and matching surfaces between #{space_a.name} and #{space.name}")
1124
1124
  spaces_temp = OpenStudio::Model::SpaceVector.new
1125
1125
  spaces_temp << space_a
1126
1126
  spaces_temp << space_b
@@ -1130,7 +1130,7 @@ module OsLib_ModelGeneration
1130
1130
  end
1131
1131
  end
1132
1132
  runner.registerInfo('Intersecting and matching surfaces in model, this will create additional geometry.')
1133
- else #elsif bar_hash[:double_loaded_corridor] # only intersect spaces in each story, not between wtory
1133
+ else # elsif bar_hash[:double_loaded_corridor] # only intersect spaces in each story, not between wtory
1134
1134
  model.getBuilding.buildingStories.sort.each do |story|
1135
1135
  # intersect and surface match two pair by pair
1136
1136
  spaces_b = story.spaces.sort
@@ -1161,7 +1161,7 @@ module OsLib_ModelGeneration
1161
1161
  OpenStudio::Model.matchSurfaces(spaces)
1162
1162
  runner.registerInfo('Intersecting and matching surfaces in model, this will create additional geometry.')
1163
1163
  end
1164
- else #elsif bar_hash[:double_loaded_corridor] # only intersect spaces in each story, not between wtory
1164
+ else # elsif bar_hash[:double_loaded_corridor] # only intersect spaces in each story, not between wtory
1165
1165
  model.getBuilding.buildingStories.sort.each do |story|
1166
1166
  story_spaces = OpenStudio::Model::SpaceVector.new
1167
1167
  story.spaces.sort.each do |space|
@@ -1181,7 +1181,7 @@ module OsLib_ModelGeneration
1181
1181
  model.getBuildingStorys.sort.each do |story|
1182
1182
  next if !story.name.to_s.include?('Story B')
1183
1183
  story.spaces.sort.each do |space|
1184
- next if not new_spaces.include?(space)
1184
+ next if !new_spaces.include?(space)
1185
1185
  space.surfaces.sort.each do |surface|
1186
1186
  next if surface.surfaceType != 'Wall'
1187
1187
  next if surface.outsideBoundaryCondition != 'Outdoors'
@@ -1194,9 +1194,9 @@ module OsLib_ModelGeneration
1194
1194
  # sort stories (by name for now but need better way)
1195
1195
  sorted_stories = {}
1196
1196
  new_spaces.each do |space|
1197
- next if ! space.buildingStory.is_initialized
1197
+ next if !space.buildingStory.is_initialized
1198
1198
  story = space.buildingStory.get
1199
- if ! sorted_stories.has_key?(name.to_s)
1199
+ if !sorted_stories.key?(name.to_s)
1200
1200
  sorted_stories[story.name.to_s] = story
1201
1201
  end
1202
1202
  end
@@ -1229,7 +1229,7 @@ module OsLib_ModelGeneration
1229
1229
  party_wall_facades = stories_flat[i][:story_party_walls]
1230
1230
 
1231
1231
  story.spaces.each do |space|
1232
- next if not new_spaces.include?(space)
1232
+ next if !new_spaces.include?(space)
1233
1233
  space.surfaces. each do |surface|
1234
1234
  # set floor to adiabatic if requited
1235
1235
  if adiabatic_floor && surface.surfaceType == 'Floor'
@@ -1325,7 +1325,6 @@ module OsLib_ModelGeneration
1325
1325
  end
1326
1326
 
1327
1327
  return new_spaces
1328
-
1329
1328
  end
1330
1329
 
1331
1330
  # make selected surfaces adiabatic
@@ -1393,7 +1392,7 @@ module OsLib_ModelGeneration
1393
1392
  return bar
1394
1393
  end
1395
1394
 
1396
- def bar_hash_setup_run(runner,model,args,length,width,floor_height_si,center_of_footprint,space_types_hash,num_stories)
1395
+ def bar_hash_setup_run(runner, model, args, length, width, floor_height_si, center_of_footprint, space_types_hash, num_stories)
1397
1396
  # create envelope
1398
1397
  # populate bar_hash and create envelope with data from envelope_data_hash and user arguments
1399
1398
  bar_hash = {}
@@ -1585,31 +1584,31 @@ module OsLib_ModelGeneration
1585
1584
  roof_area = 0.0
1586
1585
  new_spaces.each do |space|
1587
1586
  space.surfaces.each do |surface|
1588
- if surface.surfaceType == "Floor" && surface.outsideBoundaryCondition == "Ground"
1587
+ if surface.surfaceType == 'Floor' && surface.outsideBoundaryCondition == 'Ground'
1589
1588
  ground_floor_area += surface.netArea
1590
- elsif surface.surfaceType == "RoofCeiling" && surface.outsideBoundaryCondition == "Outdoors"
1589
+ elsif surface.surfaceType == 'RoofCeiling' && surface.outsideBoundaryCondition == 'Outdoors'
1591
1590
  roof_area += surface.netArea
1592
1591
  end
1593
1592
  end
1594
1593
  end
1595
- # todo - extend to address when top and or bottom story are not exposed via argument
1594
+ # TODO: - extend to address when top and or bottom story are not exposed via argument
1596
1595
  if ground_floor_area > target_footprint + 0.001 || roof_area > target_footprint + 0.001
1597
- #runner.registerError("Ground exposed floor or Roof area is larger than footprint, likely inter-floor surface matching and intersection error.")
1598
- #return false
1596
+ # runner.registerError("Ground exposed floor or Roof area is larger than footprint, likely inter-floor surface matching and intersection error.")
1597
+ # return false
1599
1598
 
1600
1599
  # not providing adiabatic work around when top story is partial story.
1601
1600
  if args['num_stories_above_grade'].to_f != args['num_stories_above_grade'].ceil
1602
- runner.registerError("Ground exposed floor or Roof area is larger than footprint, likely inter-floor surface matching and intersection error.")
1601
+ runner.registerError('Ground exposed floor or Roof area is larger than footprint, likely inter-floor surface matching and intersection error.')
1603
1602
  return false
1604
1603
  else
1605
- runner.registerInfo("Ground exposed floor or Roof area is larger than footprint, likely inter-floor surface matching and intersection error, altering impacted surfaces boundary condition to be adiabatic.")
1604
+ runner.registerInfo('Ground exposed floor or Roof area is larger than footprint, likely inter-floor surface matching and intersection error, altering impacted surfaces boundary condition to be adiabatic.')
1606
1605
  match_error = true
1607
1606
  end
1608
1607
  else
1609
1608
  match_error = false
1610
1609
  end
1611
1610
 
1612
- # todo - should be able to remove this fix after OpenStudio intersection issue is fixed. At that time turn the above message into an error with return false after it
1611
+ # TODO: - should be able to remove this fix after OpenStudio intersection issue is fixed. At that time turn the above message into an error with return false after it
1613
1612
  if match_error
1614
1613
 
1615
1614
  # identify z value of top and bottom story
@@ -1635,35 +1634,34 @@ module OsLib_ModelGeneration
1635
1634
  if space.buildingStory.get.nominalZCoordinate.get > bottom_story
1636
1635
  # change floors
1637
1636
  space.surfaces.each do |surface|
1638
- next if not surface.surfaceType == "Floor" && surface.outsideBoundaryCondition == "Ground"
1639
- surface.setOutsideBoundaryCondition("Adiabatic")
1637
+ next if !(surface.surfaceType == 'Floor' && surface.outsideBoundaryCondition == 'Ground')
1638
+ surface.setOutsideBoundaryCondition('Adiabatic')
1640
1639
  end
1641
1640
  end
1642
1641
  if space.buildingStory.get.nominalZCoordinate.get < top_story
1643
1642
  # change ceilings
1644
1643
  space.surfaces.each do |surface|
1645
- next if not surface.surfaceType == "RoofCeiling" && surface.outsideBoundaryCondition == "Outdoors"
1646
- surface.setOutsideBoundaryCondition("Adiabatic")
1644
+ next if !(surface.surfaceType == 'RoofCeiling' && surface.outsideBoundaryCondition == 'Outdoors')
1645
+ surface.setOutsideBoundaryCondition('Adiabatic')
1647
1646
  end
1648
1647
  end
1649
1648
  end
1650
1649
  end
1651
1650
  end
1652
1651
 
1653
- # bar_from_building_type_ratios
1654
- # used for varieties of measures that create bar from building type ratios
1655
- def bar_from_building_type_ratios(model, runner, user_arguments)
1652
+ # bar_arg_check_setup
1653
+ def bar_arg_check_setup(model, runner, user_arguments, building_type_ratios = true)
1656
1654
 
1657
1655
  # assign the user inputs to variables
1658
1656
  args = OsLib_HelperMethods.createRunVariables(runner, model, user_arguments, arguments(model))
1659
1657
  if !args then return false end
1660
1658
 
1661
1659
  # add in arguments that may not be passed in
1662
- if !args.has_key?("double_loaded_corridor")
1663
- args["double_loaded_corridor"] = "None" # use None when not in measure building type data may not contain this
1660
+ if !args.key?('double_loaded_corridor')
1661
+ args['double_loaded_corridor'] = 'None' # use None when not in measure building type data may not contain this
1664
1662
  end
1665
- if ! args.has_key?("perim_mult")
1666
- args["perim_mult"] = 1.0 # will not make two bars for extended perimeter
1663
+ if !args.key?('perim_mult')
1664
+ args['perim_mult'] = 1.0 # will not make two bars for extended perimeter
1667
1665
  end
1668
1666
 
1669
1667
  # lookup and replace argument values from upstream measures
@@ -1689,10 +1687,12 @@ module OsLib_ModelGeneration
1689
1687
  end
1690
1688
 
1691
1689
  # check expected values of double arguments
1692
- fraction_args = ['bldg_type_b_fract_bldg_area',
1693
- 'bldg_type_c_fract_bldg_area',
1694
- 'bldg_type_d_fract_bldg_area',
1695
- 'wwr', 'party_wall_fraction']
1690
+ fraction_args = ['wwr', 'party_wall_fraction']
1691
+ if building_type_ratios
1692
+ fraction_args << 'bldg_type_b_fract_bldg_area'
1693
+ fraction_args << 'bldg_type_c_fract_bldg_area'
1694
+ fraction_args << 'bldg_type_d_fract_bldg_area'
1695
+ end
1696
1696
  fraction = OsLib_HelperMethods.checkDoubleAndIntegerArguments(runner, user_arguments, 'min' => 0.0, 'max' => 1.0, 'min_eq_bool' => true, 'max_eq_bool' => true, 'arg_array' => fraction_args)
1697
1697
 
1698
1698
  positive_args = ['total_bldg_floor_area']
@@ -1709,49 +1709,25 @@ module OsLib_ModelGeneration
1709
1709
  'party_wall_stories_east',
1710
1710
  'party_wall_stories_west',
1711
1711
  'single_floor_area',
1712
- 'bar_width',]
1712
+ 'bar_width']
1713
1713
  non_neg = OsLib_HelperMethods.checkDoubleAndIntegerArguments(runner, user_arguments, 'min' => 0.0, 'max' => nil, 'min_eq_bool' => true, 'max_eq_bool' => false, 'arg_array' => non_neg_args)
1714
1714
 
1715
1715
  # return false if any errors fail
1716
1716
  if !fraction then return false end
1717
1717
  if !positive then return false end
1718
- if !one_or_greater then return false end
1719
- if !non_neg then return false end
1720
-
1721
- # if aspect ratio, story height or wwr have argument value of 0 then use smart building type defaults
1722
- building_form_defaults = building_form_defaults(args['bldg_type_a'])
1718
+ return false if !one_or_greater
1719
+ return false if !non_neg
1723
1720
 
1724
- # store list of defaulted items
1725
- defaulted_args = []
1721
+ return args
1726
1722
 
1727
- if args['ns_to_ew_ratio'] == 0.0
1728
- args['ns_to_ew_ratio'] = building_form_defaults[:aspect_ratio]
1729
- runner.registerInfo("0.0 value for aspect ratio will be replaced with smart default for #{args['bldg_type_a']} of #{building_form_defaults[:aspect_ratio]}.")
1730
- end
1723
+ end
1731
1724
 
1732
- if args['perim_mult'] == 0.0
1733
- # if this is not defined then use default of 1.0
1734
- if !building_form_defaults.has_key?(:perim_mult)
1735
- args['perim_mult'] = 1.0
1736
- else
1737
- args['perim_mult'] = building_form_defaults[:perim_mult]
1738
- end
1739
- runner.registerInfo("0.0 value for minimum perimeter multiplier will be replaced with smart default for #{args['bldg_type_a']} of #{building_form_defaults[:perim_mult]}.")
1740
- elsif args['perim_mult'] < 1.0
1741
- runner.registerError("Other than the smart default value of 0, the minimum perimeter multiplier should be equal to 1.0 or greater.")
1742
- return false
1743
- end
1725
+ # bar_from_building_type_ratios
1726
+ # used for varieties of measures that create bar from building type ratios
1727
+ def bar_from_building_type_ratios(model, runner, user_arguments)
1744
1728
 
1745
- if args['floor_height'] == 0.0
1746
- args['floor_height'] = building_form_defaults[:typical_story]
1747
- runner.registerInfo("0.0 value for floor height will be replaced with smart default for #{args['bldg_type_a']} of #{building_form_defaults[:typical_story]}.")
1748
- defaulted_args << 'floor_height'
1749
- end
1750
- # because of this can't set wwr to 0.0. If that is desired then we can change this to check for 1.0 instead of 0.0
1751
- if args['wwr'] == 0.0
1752
- args['wwr'] = building_form_defaults[:wwr]
1753
- runner.registerInfo("0.0 value for window to wall ratio will be replaced with smart default for #{args['bldg_type_a']} of #{building_form_defaults[:wwr]}.")
1754
- end
1729
+ # prep arguments
1730
+ args = bar_arg_check_setup(model,runner,user_arguments)
1755
1731
 
1756
1732
  # check that sum of fractions for b,c, and d is less than 1.0 (so something is left for primary building type)
1757
1733
  bldg_type_a_fract_bldg_area = 1.0 - args['bldg_type_b_fract_bldg_area'] - args['bldg_type_c_fract_bldg_area'] - args['bldg_type_d_fract_bldg_area']
@@ -1761,7 +1737,7 @@ module OsLib_ModelGeneration
1761
1737
  end
1762
1738
 
1763
1739
  # Make the standard applier
1764
- standard = Standard.build("#{args['template']}")
1740
+ standard = Standard.build((args['template']).to_s)
1765
1741
 
1766
1742
  # report initial condition of model
1767
1743
  runner.registerInitialCondition("The building started with #{model.getSpaces.size} spaces.")
@@ -1791,14 +1767,14 @@ module OsLib_ModelGeneration
1791
1767
  # gather data for bldg_type_a
1792
1768
  building_type_hash[args['bldg_type_a']] = {}
1793
1769
  building_type_hash[args['bldg_type_a']][:frac_bldg_area] = bldg_type_a_fract_bldg_area
1794
- #building_type_hash[args['bldg_type_a']][:num_units] = args['bldg_type_a_num_units']
1770
+ # building_type_hash[args['bldg_type_a']][:num_units] = args['bldg_type_a_num_units']
1795
1771
  building_type_hash[args['bldg_type_a']][:space_types] = get_space_types_from_building_type(args['bldg_type_a'], args['template'], true)
1796
1772
 
1797
1773
  # gather data for bldg_type_b
1798
1774
  if args['bldg_type_b_fract_bldg_area'] > 0
1799
1775
  building_type_hash[args['bldg_type_b']] = {}
1800
1776
  building_type_hash[args['bldg_type_b']][:frac_bldg_area] = args['bldg_type_b_fract_bldg_area']
1801
- #building_type_hash[args['bldg_type_b']][:num_units] = args['bldg_type_b_num_units']
1777
+ # building_type_hash[args['bldg_type_b']][:num_units] = args['bldg_type_b_num_units']
1802
1778
  building_type_hash[args['bldg_type_b']][:space_types] = get_space_types_from_building_type(args['bldg_type_b'], args['template'], true)
1803
1779
  end
1804
1780
 
@@ -1806,7 +1782,7 @@ module OsLib_ModelGeneration
1806
1782
  if args['bldg_type_c_fract_bldg_area'] > 0
1807
1783
  building_type_hash[args['bldg_type_c']] = {}
1808
1784
  building_type_hash[args['bldg_type_c']][:frac_bldg_area] = args['bldg_type_c_fract_bldg_area']
1809
- #building_type_hash[args['bldg_type_c']][:num_units] = args['bldg_type_c_num_units']
1785
+ # building_type_hash[args['bldg_type_c']][:num_units] = args['bldg_type_c_num_units']
1810
1786
  building_type_hash[args['bldg_type_c']][:space_types] = get_space_types_from_building_type(args['bldg_type_c'], args['template'], true)
1811
1787
  end
1812
1788
 
@@ -1814,10 +1790,145 @@ module OsLib_ModelGeneration
1814
1790
  if args['bldg_type_d_fract_bldg_area'] > 0
1815
1791
  building_type_hash[args['bldg_type_d']] = {}
1816
1792
  building_type_hash[args['bldg_type_d']][:frac_bldg_area] = args['bldg_type_d_fract_bldg_area']
1817
- #building_type_hash[args['bldg_type_d']][:num_units] = args['bldg_type_d_num_units']
1793
+ # building_type_hash[args['bldg_type_d']][:num_units] = args['bldg_type_d_num_units']
1818
1794
  building_type_hash[args['bldg_type_d']][:space_types] = get_space_types_from_building_type(args['bldg_type_d'], args['template'], true)
1819
1795
  end
1820
1796
 
1797
+ # call bar_from_building_space_type_ratios to generate bar
1798
+ bar_from_space_type_ratios(model, runner, user_arguments, args, building_type_hash)
1799
+
1800
+ return true
1801
+
1802
+ end
1803
+
1804
+ # bar_from_space_type_ratios
1805
+ # used for varieties of measures that create bar from space type or building type ratios
1806
+ # args and building_type_hash should both be nil or neither shoould be nill
1807
+ def bar_from_space_type_ratios(model, runner, user_arguments, args = nil, building_type_hash = nil)
1808
+
1809
+ # do not setup arguments if they were already passed in to this method
1810
+ if args.nil?
1811
+ # prep arguments
1812
+ args = bar_arg_check_setup(model,runner,user_arguments,false) # false stops it from checking args on used in bar_from_building_type_ratios
1813
+
1814
+ # identify primary building type for building form defaults
1815
+ primary_building_type = "PrimarySchool" # see what building type represents the most floro area
1816
+ building_form_defaults = building_form_defaults(primary_building_type)
1817
+
1818
+ # process arg into hash
1819
+ space_type_hash_name = {}
1820
+ args['space_type_hash_string'][0..-1].split(/, /).each { |entry| entryMap = entry.split(/=>/); value_str = entryMap[1]; space_type_hash_name[entryMap[0].strip[0..-1].to_s] = value_str.nil? ? '' : value_str.strip[0..-1].to_f }
1821
+
1822
+ # create building type hasn from space type ratios
1823
+ building_type_hash = {}
1824
+ building_type_fraction_of_building = 0.0
1825
+ space_type_hash_name.each do |building_space_type,ratio|
1826
+ building_type = building_space_type.split("|")[0].strip
1827
+ space_type = building_space_type.split("|")[1].strip
1828
+
1829
+ # harvest height and circ info from get_space_types_from_building_type(building_type, template, whole_building = true)
1830
+ building_type_lookup_info = get_space_types_from_building_type(building_type,args['template'])
1831
+ if building_type_lookup_info.size == 0
1832
+ runner.registerWarning("#{building_type} looks like an invalid building type for #{args['template']}")
1833
+ end
1834
+ space_type_info_hash = {}
1835
+ if building_type_lookup_info.key?(space_type)
1836
+ if building_type_lookup_info[space_type].key?(:story_height)
1837
+ space_type_info_hash[:story_height] = building_type_lookup_info[space_type][:story_height]
1838
+ end
1839
+ if building_type_lookup_info[space_type].key?(:default)
1840
+ space_type_info_hash[:default] = building_type_lookup_info[space_type][:default]
1841
+ end
1842
+ if building_type_lookup_info[space_type].key?(:circ)
1843
+ space_type_info_hash[:circ] = building_type_lookup_info[space_type][:circ]
1844
+ end
1845
+ else
1846
+ runner.registerWarning("#{space_type} looks like an invalid space type for #{building_type}")
1847
+ end
1848
+
1849
+ # extend harvested data with custom ratios from space type ratio string argument.
1850
+ if building_type_hash.key?(building_type)
1851
+ building_type_hash[building_type][:frac_bldg_area] += ratio
1852
+ space_type_info_hash[:ratio] = ratio
1853
+ building_type_hash[building_type][:space_types][space_type] = space_type_info_hash
1854
+ else
1855
+ building_type_hash[building_type] = {}
1856
+ building_type_hash[building_type][:frac_bldg_area] = ratio
1857
+ space_type_info_hash[:ratio] = ratio
1858
+ space_types = {}
1859
+ space_types[space_type] = space_type_info_hash
1860
+ building_type_hash[building_type][:space_types] = space_types
1861
+ end
1862
+ building_type_fraction_of_building += ratio
1863
+ end
1864
+
1865
+ # todo - confirm if this will get normalized up/down later of if I should fix or stop here instead of just a warning
1866
+ if building_type_fraction_of_building > 1.0
1867
+ runner.registerWarning("Sum of Space Type Ratio of #{building_type_fraction_of_building} is greater than the expected value of 1.0")
1868
+ elsif building_type_fraction_of_building < 1.0
1869
+ runner.registerWarning("Sum of Space Type Ratio of #{building_type_fraction_of_building} is less than the expected value of 1.0")
1870
+ end
1871
+
1872
+ else # else is used when bar_from_building_type_ratio is used
1873
+
1874
+ # if aspect ratio, story height or wwr have argument value of 0 then use smart building type defaults
1875
+ primary_building_type = args['bldg_type_a']
1876
+
1877
+ end
1878
+
1879
+ # get defaults for the primary building type
1880
+ building_form_defaults = building_form_defaults(primary_building_type)
1881
+
1882
+ # store list of defaulted items
1883
+ defaulted_args = []
1884
+
1885
+ if args['ns_to_ew_ratio'] == 0.0
1886
+ args['ns_to_ew_ratio'] = building_form_defaults[:aspect_ratio]
1887
+ runner.registerInfo("0.0 value for aspect ratio will be replaced with smart default for #{primary_building_type} of #{building_form_defaults[:aspect_ratio]}.")
1888
+ end
1889
+
1890
+ if args['perim_mult'] == 0.0
1891
+ # if this is not defined then use default of 1.0
1892
+ if !building_form_defaults.has_key?(:perim_mult)
1893
+ args['perim_mult'] = 1.0
1894
+ else
1895
+ args['perim_mult'] = building_form_defaults[:perim_mult]
1896
+ end
1897
+ runner.registerInfo("0.0 value for minimum perimeter multiplier will be replaced with smart default for #{primary_building_type} of #{building_form_defaults[:perim_mult]}.")
1898
+ elsif args['perim_mult'] < 1.0
1899
+ runner.registerError("Other than the smart default value of 0, the minimum perimeter multiplier should be equal to 1.0 or greater.")
1900
+ return false
1901
+ end
1902
+
1903
+ if args['floor_height'] == 0.0
1904
+ args['floor_height'] = building_form_defaults[:typical_story]
1905
+ runner.registerInfo("0.0 value for floor height will be replaced with smart default for #{primary_building_type} of #{building_form_defaults[:typical_story]}.")
1906
+ defaulted_args << 'floor_height'
1907
+ end
1908
+ # because of this can't set wwr to 0.0. If that is desired then we can change this to check for 1.0 instead of 0.0
1909
+ if args['wwr'] == 0.0
1910
+ args['wwr'] = building_form_defaults[:wwr]
1911
+ runner.registerInfo("0.0 value for window to wall ratio will be replaced with smart default for #{primary_building_type} of #{building_form_defaults[:wwr]}.")
1912
+ end
1913
+
1914
+ # Make the standard applier
1915
+ standard = Standard.build("#{args['template']}")
1916
+
1917
+ # report initial condition of model
1918
+ runner.registerInitialCondition("The building started with #{model.getSpaces.size} spaces.")
1919
+
1920
+ # determine of ns_ew needs to be mirrored
1921
+ mirror_ns_ew = false
1922
+ rotation = model.getBuilding.northAxis
1923
+ if rotation > 45.0 && rotation < 135.0
1924
+ mirror_ns_ew = true
1925
+ elsif rotation > 45.0 && rotation < 135.0
1926
+ mirror_ns_ew = true
1927
+ end
1928
+
1929
+ # remove non-resource objects not removed by removing the building
1930
+ remove_non_resource_objects(runner, model)
1931
+
1821
1932
  # creating space types for requested building types
1822
1933
  building_type_hash.each do |building_type, building_type_hash|
1823
1934
  runner.registerInfo("Creating Space Types for #{building_type}.")
@@ -1840,8 +1951,8 @@ module OsLib_ModelGeneration
1840
1951
  # set color
1841
1952
  test = standard.space_type_apply_rendering_color(space_type) # this uses openstudio-standards
1842
1953
  if !test
1843
- # todo - once fixed in standards un-comment this
1844
- #runner.registerWarning("Could not find color for #{args['template']} #{space_type.name}")
1954
+ # TODO: - once fixed in standards un-comment this
1955
+ # runner.registerWarning("Could not find color for #{args['template']} #{space_type.name}")
1845
1956
  end
1846
1957
 
1847
1958
  # extend hash to hold new space type object
@@ -1869,7 +1980,7 @@ module OsLib_ModelGeneration
1869
1980
  runner.registerWarning('User-defined single floor area was used for calculation of total building floor area')
1870
1981
  # add warning if custom_height_bar is true and applicable building type is selected
1871
1982
  if args['custom_height_bar']
1872
- runner.registerWarning("Cannot use custom height bar with single floor area method, will not create custom height bar.")
1983
+ runner.registerWarning('Cannot use custom height bar with single floor area method, will not create custom height bar.')
1873
1984
  args['custom_height_bar'] = false
1874
1985
  end
1875
1986
  else
@@ -1884,8 +1995,7 @@ module OsLib_ModelGeneration
1884
1995
  building_type_hash = building_type_hash.sort_by { |k, v| v[:frac_bldg_area] }
1885
1996
  end
1886
1997
  building_type_hash.each do |building_type, building_type_hash|
1887
-
1888
- if args["double_loaded_corridor"] == "Primary Space Type"
1998
+ if args['double_loaded_corridor'] == 'Primary Space Type'
1889
1999
 
1890
2000
  # see if building type has circulation space type, if so then merge that along with default space type into hash key in place of space type
1891
2001
  default_st = nil
@@ -1900,8 +2010,8 @@ module OsLib_ModelGeneration
1900
2010
  runner.registerInfo("Combining #{default_st} and #{circ_st} into a group representing a double loaded corridor")
1901
2011
 
1902
2012
  # add new item
1903
- building_type_hash[:space_types]["Double Loaded Corridor"] = {}
1904
- double_loaded_st = building_type_hash[:space_types]["Double Loaded Corridor"]
2013
+ building_type_hash[:space_types]['Double Loaded Corridor'] = {}
2014
+ double_loaded_st = building_type_hash[:space_types]['Double Loaded Corridor']
1905
2015
  double_loaded_st[:ratio] = building_type_hash[:space_types][default_st][:ratio] + building_type_hash[:space_types][circ_st][:ratio]
1906
2016
  double_loaded_st[:double_loaded_corridor] = true
1907
2017
  double_loaded_st[:space_type] = model.getBuilding
@@ -1936,21 +2046,21 @@ module OsLib_ModelGeneration
1936
2046
  multi_height_space_types_hash[space_type][:wwr] = hash[:wwr]
1937
2047
  end
1938
2048
  else
1939
- # only add wwr if 0 used for wwr arg and if space type has wwr as key
1940
- space_types_hash[space_type] = { floor_area: final_floor_area, space_type: space_type }
1941
- if hash.key?(:orig_ratio) then space_types_hash[space_type][:orig_ratio] = hash[:orig_ratio] end
1942
- if args['wwr'] == 0 && hash.key?(:wwr)
1943
- space_types_hash[space_type][:wwr] = hash[:wwr]
1944
- end
1945
- if hash[:double_loaded_corridor]
1946
- space_types_hash[space_type][:children] = hash[:children]
1947
- end
2049
+ # only add wwr if 0 used for wwr arg and if space type has wwr as key
2050
+ space_types_hash[space_type] = { floor_area: final_floor_area, space_type: space_type }
2051
+ if hash.key?(:orig_ratio) then space_types_hash[space_type][:orig_ratio] = hash[:orig_ratio] end
2052
+ if args['wwr'] == 0 && hash.key?(:wwr)
2053
+ space_types_hash[space_type][:wwr] = hash[:wwr]
2054
+ end
2055
+ if hash[:double_loaded_corridor]
2056
+ space_types_hash[space_type][:children] = hash[:children]
2057
+ end
1948
2058
  end
1949
2059
  end
1950
2060
  end
1951
2061
 
1952
2062
  # resort if not sorted by building type
1953
- if args['space_type_sort_logic'] == "Size"
2063
+ if args['space_type_sort_logic'] == 'Size'
1954
2064
  # added code to convert to hash. I use sort_by 3 other times, but those seem to be working fine as is now.
1955
2065
  space_types_hash = Hash[space_types_hash.sort_by { |k, v| v[:floor_area] }]
1956
2066
  end
@@ -1958,14 +2068,14 @@ module OsLib_ModelGeneration
1958
2068
  # calculate targets for testing
1959
2069
  target_areas = {} # used for checks
1960
2070
  target_areas_cust_height = 0.0
1961
- space_types_hash.each do |k,v|
2071
+ space_types_hash.each do |k, v|
1962
2072
  if v.key?(:orig_ratio)
1963
2073
  target_areas[k] = v[:orig_ratio] * total_bldg_floor_area_si
1964
2074
  else
1965
2075
  target_areas[k] = v[:floor_area]
1966
2076
  end
1967
2077
  end
1968
- multi_height_space_types_hash.each do |k,v|
2078
+ multi_height_space_types_hash.each do |k, v|
1969
2079
  if v.key?(:orig_ratio)
1970
2080
  target_areas[k] = v[:orig_ratio] * total_bldg_floor_area_si
1971
2081
  target_areas_cust_height += v[:orig_ratio] * total_bldg_floor_area_si
@@ -1980,19 +2090,19 @@ module OsLib_ModelGeneration
1980
2090
  footprint_si = (total_bldg_floor_area_si - target_areas_cust_height) / num_stories.to_f
1981
2091
  end
1982
2092
  floor_height_si = OpenStudio.convert(args['floor_height'], 'ft', 'm').get
1983
- min_allow_size = OpenStudio.convert(15.0,'ft','m').get
1984
- specified_bar_width_si = OpenStudio.convert(args['bar_width'],'ft','m').get
2093
+ min_allow_size = OpenStudio.convert(15.0, 'ft', 'm').get
2094
+ specified_bar_width_si = OpenStudio.convert(args['bar_width'], 'ft', 'm').get
1985
2095
 
1986
2096
  # set custom width
1987
2097
  if specified_bar_width_si > 0
1988
- runner.registerInfo("Ignoring perimeter multiplier argument when non zero width argument is used")
2098
+ runner.registerInfo('Ignoring perimeter multiplier argument when non zero width argument is used')
1989
2099
  if footprint_si / specified_bar_width_si >= min_allow_size
1990
2100
  width = specified_bar_width_si
1991
2101
  length = footprint_si / width
1992
2102
  else
1993
2103
  length = min_allow_size
1994
2104
  width = footprint_si / length
1995
- runner.registerWarning("User specified width results in a length that is too short, adjusting width to be narrower than specified.")
2105
+ runner.registerWarning('User specified width results in a length that is too short, adjusting width to be narrower than specified.')
1996
2106
  end
1997
2107
  width_cust_height = specified_bar_width_si
1998
2108
  else
@@ -2002,29 +2112,29 @@ module OsLib_ModelGeneration
2002
2112
  end
2003
2113
  length_cust_height = target_areas_cust_height / width_cust_height
2004
2114
  if args['perim_mult'] > 1.0 && target_areas_cust_height > 0.0
2005
- # todo - update tests that hit this warning
2006
- runner.registerWarning("Ignoring perimeter multiplier for bar that represents custom height spaces.")
2115
+ # TODO: - update tests that hit this warning
2116
+ runner.registerWarning('Ignoring perimeter multiplier for bar that represents custom height spaces.')
2007
2117
  end
2008
2118
 
2009
2119
  # check if dual bar is needed
2010
2120
  dual_bar = false
2011
2121
  if specified_bar_width_si > 0.0 && args['bar_division_method'] == 'Multiple Space Types - Individual Stories Sliced'
2012
- if length/width != args['ns_to_ew_ratio']
2013
-
2014
- if args['ns_to_ew_ratio'] >= 1.0 && args['ns_to_ew_ratio'] > length/width
2015
- runner.registerWarning("Can't meet target aspect ratio of #{args['ns_to_ew_ratio']}, Lowering it to #{length/width} ")
2016
- args['ns_to_ew_ratio'] = length/width
2017
- elsif args['ns_to_ew_ratio'] < 1.0 && args['ns_to_ew_ratio'] > length/width
2018
- runner.registerWarning("Can't meet target aspect ratio of #{args['ns_to_ew_ratio']}, Increasing it to #{length/width} ")
2019
- args['ns_to_ew_ratio'] = length/width
2122
+ if length / width != args['ns_to_ew_ratio']
2123
+
2124
+ if args['ns_to_ew_ratio'] >= 1.0 && args['ns_to_ew_ratio'] > length / width
2125
+ runner.registerWarning("Can't meet target aspect ratio of #{args['ns_to_ew_ratio']}, Lowering it to #{length / width} ")
2126
+ args['ns_to_ew_ratio'] = length / width
2127
+ elsif args['ns_to_ew_ratio'] < 1.0 && args['ns_to_ew_ratio'] > length / width
2128
+ runner.registerWarning("Can't meet target aspect ratio of #{args['ns_to_ew_ratio']}, Increasing it to #{length / width} ")
2129
+ args['ns_to_ew_ratio'] = length / width
2020
2130
  else
2021
2131
  # check if each bar would be longer then 15 feet, then set as dual bar and override perimeter multiplier
2022
- length_alt1 = ((args['ns_to_ew_ratio'] * footprint_si) / width + 2 * args['ns_to_ew_ratio'] * width - 2 * width)/(1 + args['ns_to_ew_ratio'])
2132
+ length_alt1 = ((args['ns_to_ew_ratio'] * footprint_si) / width + 2 * args['ns_to_ew_ratio'] * width - 2 * width) / (1 + args['ns_to_ew_ratio'])
2023
2133
  length_alt2 = length - length_alt1
2024
- if [length_alt1,length_alt2].min >= min_allow_size
2134
+ if [length_alt1, length_alt2].min >= min_allow_size
2025
2135
  dual_bar = true
2026
2136
  else
2027
- runner.registerInfo("Second bar would be below minimum length, will model as single bar")
2137
+ runner.registerInfo('Second bar would be below minimum length, will model as single bar')
2028
2138
  # swap length and width if single bar and aspect ratio less than 1
2029
2139
  if args['ns_to_ew_ratio'] < 1.0
2030
2140
  width = length
@@ -2034,7 +2144,7 @@ module OsLib_ModelGeneration
2034
2144
  end
2035
2145
  end
2036
2146
  elsif args['perim_mult'] > 1.0 && args['bar_division_method'] == 'Multiple Space Types - Individual Stories Sliced'
2037
- runner.registerInfo("You selected a perimeter multiplier greater than 1.0 for a supported bar division method. This will result in two detached rectangular buildings if secondary bar meets minimum size requirements.")
2147
+ runner.registerInfo('You selected a perimeter multiplier greater than 1.0 for a supported bar division method. This will result in two detached rectangular buildings if secondary bar meets minimum size requirements.')
2038
2148
  dual_bar = true
2039
2149
  elsif args['perim_mult'] > 1.0
2040
2150
  runner.registerWarning("You selected a perimeter multiplier greater than 1.0 but didn't select a bar division method that supports this. The value for this argument will be ignored by the measure")
@@ -2058,7 +2168,7 @@ module OsLib_ModelGeneration
2058
2168
  # custom quadratic equation to solve two bars with common width 2l^2 - p*l + 4a = 0
2059
2169
  if target_perim**2 - 32 * footprint_si > 0
2060
2170
  if specified_bar_width_si > 0
2061
- runner.registerInfo("Ignoring perimeter multiplier argument and using use specified bar width.")
2171
+ runner.registerInfo('Ignoring perimeter multiplier argument and using use specified bar width.')
2062
2172
  dual_double_end_width = specified_bar_width_si
2063
2173
  dual_double_end_length = footprint_si / dual_double_end_width
2064
2174
  else
@@ -2067,7 +2177,7 @@ module OsLib_ModelGeneration
2067
2177
  end
2068
2178
 
2069
2179
  # now that stretched bar is made, determine where to split it and rotate
2070
- bar_a_length = (args['ns_to_ew_ratio'] * (dual_double_end_length + dual_double_end_width) - dual_double_end_width)/(1 + args['ns_to_ew_ratio'])
2180
+ bar_a_length = (args['ns_to_ew_ratio'] * (dual_double_end_length + dual_double_end_width) - dual_double_end_width) / (1 + args['ns_to_ew_ratio'])
2071
2181
  bar_b_length = dual_double_end_length - bar_a_length
2072
2182
  area_a = bar_a_length * dual_double_end_width
2073
2183
  area_b = bar_b_length * dual_double_end_width
@@ -2086,15 +2196,15 @@ module OsLib_ModelGeneration
2086
2196
  adiabatic_dual_double_end_width = footprint_si / adiabatic_dual_double_end_length
2087
2197
  # test for unexpected
2088
2198
  unexpected = false
2089
- if (target_area - adiabatic_dual_double_end_length*adiabatic_dual_double_end_width).abs > tol_testing then unexpected = true end
2199
+ if (target_area - adiabatic_dual_double_end_length * adiabatic_dual_double_end_width).abs > tol_testing then unexpected = true end
2090
2200
  if specified_bar_width_si == 0
2091
2201
  if (target_perim - (adiabatic_dual_double_end_length * 2 + adiabatic_dual_double_end_width * 2)).abs > tol_testing then unexpected = true end
2092
2202
  end
2093
2203
  if unexpected
2094
- runner.registerWarning("Unexpected values for dual rectangle adiabatic ends bar b.")
2204
+ runner.registerWarning('Unexpected values for dual rectangle adiabatic ends bar b.')
2095
2205
  end
2096
2206
  # now that stretched bar is made, determine where to split it and rotate
2097
- adiabatic_bar_a_length = (args['ns_to_ew_ratio'] * (adiabatic_dual_double_end_length + adiabatic_dual_double_end_width))/(1 + args['ns_to_ew_ratio'])
2207
+ adiabatic_bar_a_length = (args['ns_to_ew_ratio'] * (adiabatic_dual_double_end_length + adiabatic_dual_double_end_width)) / (1 + args['ns_to_ew_ratio'])
2098
2208
  adiabatic_bar_b_length = adiabatic_dual_double_end_length - adiabatic_bar_a_length
2099
2209
  adiabatic_area_a = adiabatic_bar_a_length * adiabatic_dual_double_end_width
2100
2210
  adiabatic_area_b = adiabatic_bar_b_length * adiabatic_dual_double_end_width
@@ -2113,28 +2223,28 @@ module OsLib_ModelGeneration
2113
2223
  # apply prescribed approach for stretched or dual bar
2114
2224
  if dual_bar_calc_approach == 'dual_bar'
2115
2225
  runner.registerInfo("Stretched #{OpenStudio.toNeatString(OpenStudio.convert(dual_double_end_length, 'm', 'ft').get, 0, true)} ft x #{OpenStudio.toNeatString(OpenStudio.convert(dual_double_end_width, 'm', 'ft').get, 0, true)} ft rectangle has an area of #{OpenStudio.toNeatString(OpenStudio.convert(dual_double_end_length * dual_double_end_width, 'm^2', 'ft^2').get, 0, true)} ft^2. When split in two the perimeter will be #{OpenStudio.toNeatString(OpenStudio.convert(dual_double_end_length * 2 + dual_double_end_width * 4, 'm', 'ft').get, 0, true)} ft")
2116
- if (target_area - dual_double_end_length*dual_double_end_width).abs > tol_testing || (target_perim - (dual_double_end_length * 2 + dual_double_end_width * 4)).abs > tol_testing
2117
- runner.registerWarning("Unexpected values for dual rectangle.")
2226
+ if (target_area - dual_double_end_length * dual_double_end_width).abs > tol_testing || (target_perim - (dual_double_end_length * 2 + dual_double_end_width * 4)).abs > tol_testing
2227
+ runner.registerWarning('Unexpected values for dual rectangle.')
2118
2228
  end
2119
2229
 
2120
- runner.registerInfo("For stretched split bar, to match target ns/ew aspect ratio #{OpenStudio.toNeatString(OpenStudio.convert(bar_a_length, 'm', 'ft').get, 0, true)} ft of bar should be horizontal, with #{OpenStudio.toNeatString(OpenStudio.convert(bar_b_length, 'm', 'ft').get, 0, true)} ft turned 90 degrees. Combined area is #{OpenStudio.toNeatString(OpenStudio.convert(area_a + area_b, 'm^2', 'ft^2').get, 0, true)} ft^2. Combined perimeter is #{OpenStudio.toNeatString(OpenStudio.convert(bar_a_length*2 + bar_b_length*2 + dual_double_end_width*4, 'm', 'ft').get, 0, true)} ft")
2121
- if (target_area - (area_a + area_b)).abs > tol_testing || (target_perim - (bar_a_length*2 + bar_b_length*2 + dual_double_end_width*4)).abs > tol_testing
2122
- runner.registerWarning("Unexpected values for rotated dual rectangle")
2230
+ runner.registerInfo("For stretched split bar, to match target ns/ew aspect ratio #{OpenStudio.toNeatString(OpenStudio.convert(bar_a_length, 'm', 'ft').get, 0, true)} ft of bar should be horizontal, with #{OpenStudio.toNeatString(OpenStudio.convert(bar_b_length, 'm', 'ft').get, 0, true)} ft turned 90 degrees. Combined area is #{OpenStudio.toNeatString(OpenStudio.convert(area_a + area_b, 'm^2', 'ft^2').get, 0, true)} ft^2. Combined perimeter is #{OpenStudio.toNeatString(OpenStudio.convert(bar_a_length * 2 + bar_b_length * 2 + dual_double_end_width * 4, 'm', 'ft').get, 0, true)} ft")
2231
+ if (target_area - (area_a + area_b)).abs > tol_testing || (target_perim - (bar_a_length * 2 + bar_b_length * 2 + dual_double_end_width * 4)).abs > tol_testing
2232
+ runner.registerWarning('Unexpected values for rotated dual rectangle')
2123
2233
  end
2124
2234
  elsif dual_bar_calc_approach == 'adiabatic_ends_bar_b'
2125
2235
  runner.registerInfo("Can't hit target perimeter with two rectangles, need to make two ends adiabatic")
2126
2236
 
2127
- runner.registerInfo("For dual bar with adiabatic ends on bar b, to reach target aspect ratio #{OpenStudio.toNeatString(OpenStudio.convert(adiabatic_bar_a_length, 'm', 'ft').get, 0, true)} ft of bar should be north/south, with #{OpenStudio.toNeatString(OpenStudio.convert(adiabatic_bar_b_length, 'm', 'ft').get, 0, true)} ft turned 90 degrees. Combined area is #{OpenStudio.toNeatString(OpenStudio.convert(adiabatic_area_a + adiabatic_area_b, 'm^2', 'ft^2').get, 0, true)} ft^2}. Combined perimeter is #{OpenStudio.toNeatString(OpenStudio.convert(adiabatic_bar_a_length*2 + adiabatic_bar_b_length*2 + adiabatic_dual_double_end_width*2, 'm', 'ft').get, 0, true)} ft")
2128
- if (target_area - (adiabatic_area_a + adiabatic_area_b)).abs > tol_testing || (target_perim - (adiabatic_bar_a_length*2 + adiabatic_bar_b_length*2 + adiabatic_dual_double_end_width*2)).abs > tol_testing
2129
- runner.registerWarning("Unexpected values for rotated dual rectangle adiabatic ends bar b")
2237
+ runner.registerInfo("For dual bar with adiabatic ends on bar b, to reach target aspect ratio #{OpenStudio.toNeatString(OpenStudio.convert(adiabatic_bar_a_length, 'm', 'ft').get, 0, true)} ft of bar should be north/south, with #{OpenStudio.toNeatString(OpenStudio.convert(adiabatic_bar_b_length, 'm', 'ft').get, 0, true)} ft turned 90 degrees. Combined area is #{OpenStudio.toNeatString(OpenStudio.convert(adiabatic_area_a + adiabatic_area_b, 'm^2', 'ft^2').get, 0, true)} ft^2}. Combined perimeter is #{OpenStudio.toNeatString(OpenStudio.convert(adiabatic_bar_a_length * 2 + adiabatic_bar_b_length * 2 + adiabatic_dual_double_end_width * 2, 'm', 'ft').get, 0, true)} ft")
2238
+ if (target_area - (adiabatic_area_a + adiabatic_area_b)).abs > tol_testing || (target_perim - (adiabatic_bar_a_length * 2 + adiabatic_bar_b_length * 2 + adiabatic_dual_double_end_width * 2)).abs > tol_testing
2239
+ runner.registerWarning('Unexpected values for rotated dual rectangle adiabatic ends bar b')
2130
2240
  end
2131
2241
  else # stretched bar
2132
2242
  dual_bar = false
2133
2243
 
2134
2244
  stretched_length = 0.25 * (target_perim + Math.sqrt(target_perim**2 - 16 * footprint_si))
2135
2245
  stretched_width = footprint_si / stretched_length
2136
- if (target_area - stretched_length*stretched_width).abs > tol_testing || (target_perim - (stretched_length + stretched_width)*2) > tol_testing
2137
- runner.registerWarning("Unexpected values for single stretched")
2246
+ if (target_area - stretched_length * stretched_width).abs > tol_testing || (target_perim - (stretched_length + stretched_width) * 2) > tol_testing
2247
+ runner.registerWarning('Unexpected values for single stretched')
2138
2248
  end
2139
2249
 
2140
2250
  width = stretched_width
@@ -2170,7 +2280,7 @@ module OsLib_ModelGeneration
2170
2280
  end
2171
2281
  bars['primary'][:floor_height_si] = floor_height_si # can make use of this when breaking out multi-height spaces
2172
2282
  bars['primary'][:num_stories] = num_stories
2173
- bars['primary'][:center_of_footprint] = OpenStudio::Point3d.new(0.0,0.0,0.0)
2283
+ bars['primary'][:center_of_footprint] = OpenStudio::Point3d.new(0.0, 0.0, 0.0)
2174
2284
  space_types_hash_secondary = {}
2175
2285
  if dual_bar
2176
2286
  # loop through each story and move portion for other bar to its own hash
@@ -2179,9 +2289,9 @@ module OsLib_ModelGeneration
2179
2289
  footprint_counter = primary_footprint
2180
2290
  secondary_footprint_counter = secondary_footprint
2181
2291
  story_counter = 0
2182
- pri_sec_tol = 0.0001 #m^2
2183
- pri_sec_min_area = 0.0001 #m^2
2184
- space_types_hash.each do |k,v|
2292
+ pri_sec_tol = 0.0001 # m^2
2293
+ pri_sec_min_area = 0.0001 # m^2
2294
+ space_types_hash.each do |k, v|
2185
2295
  space_type_left = v[:floor_area]
2186
2296
 
2187
2297
  # do not go to next space type until this one is evaulate, which may span stories
@@ -2189,23 +2299,23 @@ module OsLib_ModelGeneration
2189
2299
 
2190
2300
  # use secondary footprint if any left
2191
2301
  if secondary_footprint_counter > 0.0
2192
- hash_area = [space_type_left,secondary_footprint_counter].min
2302
+ hash_area = [space_type_left, secondary_footprint_counter].min
2193
2303
 
2194
2304
  # confirm that the part of space type use or what is left is greater than min allowed value
2195
2305
  projected_space_type_left = space_type_left - hash_area
2196
- test_a = if hash_area >= pri_sec_min_area then true else false end
2197
- test_b = if projected_space_type_left >= pri_sec_min_area || projected_space_type_left == 0.0 then true else false end
2198
- test_c = if k == space_types_hash.keys.last then true else false end # if last space type accept sliver, no other space to infil
2306
+ test_a = hash_area >= pri_sec_min_area
2307
+ test_b = projected_space_type_left >= pri_sec_min_area || projected_space_type_left == 0.0 ? true : false
2308
+ test_c = k == space_types_hash.keys.last # if last space type accept sliver, no other space to infil
2199
2309
  if (test_a && test_b) || test_c
2200
- if space_types_hash_secondary.has_key?(k)
2310
+ if space_types_hash_secondary.key?(k)
2201
2311
  # add to what was added for previous story
2202
2312
  space_types_hash_secondary[k][:floor_area] += hash_area
2203
2313
  else
2204
2314
  # add new space type to hash
2205
- if v.has_key?(:children)
2206
- space_types_hash_secondary[k] = {:floor_area => hash_area, :space_type => v[:space_type], :children => v[:children],}
2315
+ if v.key?(:children)
2316
+ space_types_hash_secondary[k] = { floor_area: hash_area, space_type: v[:space_type], children: v[:children] }
2207
2317
  else
2208
- space_types_hash_secondary[k] = {:floor_area => hash_area, :space_type => v[:space_type]}
2318
+ space_types_hash_secondary[k] = { floor_area: hash_area, space_type: v[:space_type] }
2209
2319
  end
2210
2320
  end
2211
2321
  space_types_hash[k][:floor_area] -= hash_area
@@ -2222,7 +2332,7 @@ module OsLib_ModelGeneration
2222
2332
  space_type_left = 0.0
2223
2333
  else
2224
2334
  # then look at primary bar
2225
- hash_area_pri = [space_type_left,footprint_counter].min
2335
+ hash_area_pri = [space_type_left, footprint_counter].min
2226
2336
  footprint_counter -= hash_area_pri
2227
2337
  space_type_left -= hash_area_pri
2228
2338
  end
@@ -2247,13 +2357,13 @@ module OsLib_ModelGeneration
2247
2357
  bars['primary'][:space_types_hash] = space_types_hash
2248
2358
  bars['primary'][:args] = args
2249
2359
  v = bars['primary']
2250
- bar_hash_setup_run(runner,model,v[:args],v[:length],v[:width],v[:floor_height_si],v[:center_of_footprint],v[:space_types_hash],v[:num_stories])
2360
+ bar_hash_setup_run(runner, model, v[:args], v[:length], v[:width], v[:floor_height_si], v[:center_of_footprint], v[:space_types_hash], v[:num_stories])
2251
2361
 
2252
2362
  # store offset value for multiple bars
2253
- if args.has_key?('bar_sep_dist_mult') && args['bar_sep_dist_mult'] > 0.0
2363
+ if args.key?('bar_sep_dist_mult') && args['bar_sep_dist_mult'] > 0.0
2254
2364
  offset_val = num_stories.ceil * floor_height_si * args['bar_sep_dist_mult']
2255
- elsif args.has_key?('bar_sep_dist_mult')
2256
- runner.registerWarning("Positive valu eis required for bar_sep_dist_mult, ignoring input and using value of 0.1")
2365
+ elsif args.key?('bar_sep_dist_mult')
2366
+ runner.registerWarning('Positive value is required for bar_sep_dist_mult, ignoring input and using value of 0.1')
2257
2367
  offset_val = num_stories.ceil * floor_height_si * 0.1
2258
2368
  else
2259
2369
  offset_val = num_stories.ceil * floor_height_si * 10.0
@@ -2289,21 +2399,21 @@ module OsLib_ModelGeneration
2289
2399
  else
2290
2400
  runner.registerInfo('Adiabatic ends added to secondary bar because target perimeter multiplier could not be met with two full rectangular footprints.')
2291
2401
  end
2292
- bars['secondary'][:center_of_footprint] = OpenStudio::Point3d.new(adiabatic_bar_a_length * 0.5 + adiabatic_dual_double_end_width * 0.5 + offset_val,adiabatic_bar_b_length * 0.5 + adiabatic_dual_double_end_width * 0.5 + offset_val,0.0)
2402
+ bars['secondary'][:center_of_footprint] = OpenStudio::Point3d.new(adiabatic_bar_a_length * 0.5 + adiabatic_dual_double_end_width * 0.5 + offset_val, adiabatic_bar_b_length * 0.5 + adiabatic_dual_double_end_width * 0.5 + offset_val, 0.0)
2293
2403
  else
2294
- bars['secondary'][:center_of_footprint] = OpenStudio::Point3d.new(bar_a_length * 0.5 + dual_double_end_width * 0.5 + offset_val,bar_b_length * 0.5 + dual_double_end_width * 0.5 + offset_val,0.0)
2404
+ bars['secondary'][:center_of_footprint] = OpenStudio::Point3d.new(bar_a_length * 0.5 + dual_double_end_width * 0.5 + offset_val, bar_b_length * 0.5 + dual_double_end_width * 0.5 + offset_val, 0.0)
2295
2405
  end
2296
2406
  bars['secondary'][:args] = args2
2297
2407
 
2298
2408
  # setup bar_hash and run create_bar
2299
2409
  v = bars['secondary']
2300
- bar_hash_setup_run(runner,model,v[:args],v[:length],v[:width],v[:floor_height_si],v[:center_of_footprint],v[:space_types_hash],v[:num_stories])
2410
+ bar_hash_setup_run(runner, model, v[:args], v[:length], v[:width], v[:floor_height_si], v[:center_of_footprint], v[:space_types_hash], v[:num_stories])
2301
2411
 
2302
2412
  end
2303
2413
 
2304
2414
  # future development (up against primary bar run intersection and surface matching after add all bars, avoid interior windows)
2305
2415
  # I could loop through each space type and give them unique height but for now will just take largest height and make bar of that height, which is fine for prototypes
2306
- if multi_height_space_types_hash.size > 0
2416
+ if !multi_height_space_types_hash.empty?
2307
2417
  args3 = args.clone
2308
2418
  bars['custom_height'] = {}
2309
2419
  if mirror_ns_ew
@@ -2314,7 +2424,7 @@ module OsLib_ModelGeneration
2314
2424
  bars['custom_height'][:width] = width_cust_height
2315
2425
  end
2316
2426
  if args['party_wall_stories_east'] + args['party_wall_stories_west'] + args['party_wall_stories_south'] + args['party_wall_stories_north'] > 0.0
2317
- runner.registerWarning("Ignorning party wall inputs for custom height bar")
2427
+ runner.registerWarning('Ignorning party wall inputs for custom height bar')
2318
2428
  end
2319
2429
 
2320
2430
  # disable party walls
@@ -2329,14 +2439,14 @@ module OsLib_ModelGeneration
2329
2439
 
2330
2440
  bars['custom_height'][:floor_height_si] = floor_height_si # can make use of this when breaking out multi-height spaces
2331
2441
  bars['custom_height'][:num_stories] = num_stories
2332
- bars['custom_height'][:center_of_footprint] = OpenStudio::Point3d.new(bars['primary'][:length] * -0.5 - length_cust_height * 0.5 - offset_val,0.0,0.0)
2333
- bars['custom_height'][:floor_height_si] = OpenStudio.convert(custom_story_heights.max,'ft','m').get
2442
+ bars['custom_height'][:center_of_footprint] = OpenStudio::Point3d.new(bars['primary'][:length] * -0.5 - length_cust_height * 0.5 - offset_val, 0.0, 0.0)
2443
+ bars['custom_height'][:floor_height_si] = OpenStudio.convert(custom_story_heights.max, 'ft', 'm').get
2334
2444
  bars['custom_height'][:num_stories] = 1
2335
2445
  bars['custom_height'][:space_types_hash] = multi_height_space_types_hash
2336
2446
  bars['custom_height'][:args] = args3
2337
2447
 
2338
2448
  v = bars['custom_height']
2339
- bar_hash_setup_run(runner,model,v[:args],v[:length],v[:width],v[:floor_height_si],v[:center_of_footprint],v[:space_types_hash],v[:num_stories])
2449
+ bar_hash_setup_run(runner, model, v[:args], v[:length], v[:width], v[:floor_height_si], v[:center_of_footprint], v[:space_types_hash], v[:num_stories])
2340
2450
  end
2341
2451
 
2342
2452
  # diagnostic log
@@ -2388,37 +2498,37 @@ module OsLib_ModelGeneration
2388
2498
  end
2389
2499
 
2390
2500
  # check ns/ew aspect ratio (harder to check when party walls are added)
2391
- wall_and_window_by_orientation = OsLib_Geometry.getExteriorWindowAndWllAreaByOrientation(model,model.getSpaces.sort)
2501
+ wall_and_window_by_orientation = OsLib_Geometry.getExteriorWindowAndWllAreaByOrientation(model, model.getSpaces)
2392
2502
  wall_ns = (wall_and_window_by_orientation['northWall'] + wall_and_window_by_orientation['southWall'])
2393
2503
  wall_ew = wall_and_window_by_orientation['eastWall'] + wall_and_window_by_orientation['westWall']
2394
- wall_ns_ip = OpenStudio.convert(wall_ns,'m^2','ft^2').get
2395
- wall_ew_ip = OpenStudio.convert(wall_ew,'m^2','ft^2').get
2396
- runner.registerValue('wall_area_ip',wall_ns_ip + wall_ew_ip,'ft^2')
2397
- runner.registerValue('ns_wall_area_ip',wall_ns_ip,'ft^2')
2398
- runner.registerValue('ew_wall_area_ip',wall_ew_ip,'ft^2')
2504
+ wall_ns_ip = OpenStudio.convert(wall_ns, 'm^2', 'ft^2').get
2505
+ wall_ew_ip = OpenStudio.convert(wall_ew, 'm^2', 'ft^2').get
2506
+ runner.registerValue('wall_area_ip', wall_ns_ip + wall_ew_ip, 'ft^2')
2507
+ runner.registerValue('ns_wall_area_ip', wall_ns_ip, 'ft^2')
2508
+ runner.registerValue('ew_wall_area_ip', wall_ew_ip, 'ft^2')
2399
2509
  # for now using perimeter of ground floor and average story area (building area / num_stories)
2400
- runner.registerValue('floor_area_to_perim_ratio',model.getBuilding.floorArea / (OsLib_Geometry.calculate_perimeter(model) * num_stories))
2401
- runner.registerValue('bar_width',OpenStudio.convert(bars['primary'][:width],'m','ft').get,'ft')
2510
+ runner.registerValue('floor_area_to_perim_ratio', model.getBuilding.floorArea / (OsLib_Geometry.calculate_perimeter(model) * num_stories))
2511
+ runner.registerValue('bar_width', OpenStudio.convert(bars['primary'][:width], 'm', 'ft').get, 'ft')
2402
2512
 
2403
2513
  if args['party_wall_fraction'] > 0 || args['party_wall_stories_north'] > 0 || args['party_wall_stories_south'] > 0 || args['party_wall_stories_east'] > 0 || args['party_wall_stories_west'] > 0
2404
- runner.registerInfo("Target facade area by orientation not validated when party walls are applied")
2514
+ runner.registerInfo('Target facade area by orientation not validated when party walls are applied')
2405
2515
  elsif args['num_stories_above_grade'] != args['num_stories_above_grade'].ceil
2406
- runner.registerInfo("Target facade area by orientation not validated when partial top story is used")
2516
+ runner.registerInfo('Target facade area by orientation not validated when partial top story is used')
2407
2517
  elsif dual_bar_calc_approach == 'stretched'
2408
- runner.registerInfo("Target facade area by orientation not validated when single stretched bar has to be used to meet target minimum perimeter multiplier")
2409
- elsif defaulted_args.include?('floor_height') && args['custom_height_bar'] && multi_height_space_types_hash.size > 0
2410
- runner.registerInfo("Target facade area by orientation not validated when a dedicated bar is added for space types with custom heights")
2518
+ runner.registerInfo('Target facade area by orientation not validated when single stretched bar has to be used to meet target minimum perimeter multiplier')
2519
+ elsif defaulted_args.include?('floor_height') && args['custom_height_bar'] && !multi_height_space_types_hash.empty?
2520
+ runner.registerInfo('Target facade area by orientation not validated when a dedicated bar is added for space types with custom heights')
2411
2521
  elsif args['bar_width'] > 0
2412
- runner.registerInfo("Target facade area by orientation not validated when a dedicated custom bar width is defined")
2522
+ runner.registerInfo('Target facade area by orientation not validated when a dedicated custom bar width is defined')
2413
2523
  else
2414
2524
 
2415
2525
  # adjust length versus width based on building rotation
2416
2526
  if mirror_ns_ew
2417
- wall_target_ns_ip = 2 * OpenStudio.convert(width,'m','ft').get * args['perim_mult'] * args['num_stories_above_grade'] * args['floor_height']
2418
- wall_target_ew_ip = 2 * OpenStudio.convert(length,'m','ft').get * args['perim_mult'] * args['num_stories_above_grade'] * args['floor_height']
2527
+ wall_target_ns_ip = 2 * OpenStudio.convert(width, 'm', 'ft').get * args['perim_mult'] * args['num_stories_above_grade'] * args['floor_height']
2528
+ wall_target_ew_ip = 2 * OpenStudio.convert(length, 'm', 'ft').get * args['perim_mult'] * args['num_stories_above_grade'] * args['floor_height']
2419
2529
  else
2420
- wall_target_ns_ip = 2 * OpenStudio.convert(length,'m','ft').get * args['perim_mult'] * args['num_stories_above_grade'] * args['floor_height']
2421
- wall_target_ew_ip = 2 * OpenStudio.convert(width,'m','ft').get * args['perim_mult'] * args['num_stories_above_grade'] * args['floor_height']
2530
+ wall_target_ns_ip = 2 * OpenStudio.convert(length, 'm', 'ft').get * args['perim_mult'] * args['num_stories_above_grade'] * args['floor_height']
2531
+ wall_target_ew_ip = 2 * OpenStudio.convert(width, 'm', 'ft').get * args['perim_mult'] * args['num_stories_above_grade'] * args['floor_height']
2422
2532
  end
2423
2533
  flag_error = false
2424
2534
  if (wall_target_ns_ip - wall_ns_ip).abs > 0.1
@@ -2458,7 +2568,6 @@ module OsLib_ModelGeneration
2458
2568
  # typical
2459
2569
  # used for varieties of measures that create typical building from model
2460
2570
  def typical_building_from_model(model, runner, user_arguments)
2461
-
2462
2571
  # assign the user inputs to variables
2463
2572
  args = OsLib_HelperMethods.createRunVariables(runner, model, user_arguments, arguments(model))
2464
2573
  if !args then return false end
@@ -2528,7 +2637,7 @@ module OsLib_ModelGeneration
2528
2637
  end
2529
2638
 
2530
2639
  # check that weekday start time plus duration does not exceed 24 hrs
2531
- if (wkdy_op_hrs_start_time_hr + wkdy_op_hrs_duration_hr + (wkdy_op_hrs_start_time_min + wkdy_op_hrs_duration_min)/60.0) > 24.0
2640
+ if (wkdy_op_hrs_start_time_hr + wkdy_op_hrs_duration_hr + (wkdy_op_hrs_start_time_min + wkdy_op_hrs_duration_min) / 60.0) > 24.0
2532
2641
  runner.registerInfo("Weekday start time of #{args['wkdy_op_hrs_start']} plus duration of #{args['wkdy_op_hrs_duration']} is more than 24 hrs, hours of operation overlap midnight.")
2533
2642
  end
2534
2643
  end
@@ -2568,7 +2677,7 @@ module OsLib_ModelGeneration
2568
2677
  end
2569
2678
 
2570
2679
  # check that weekend start time plus duration does not exceed 24 hrs
2571
- if (wknd_op_hrs_start_time_hr + wknd_op_hrs_duration_hr + (wknd_op_hrs_start_time_min + wknd_op_hrs_duration_min)/60.0) > 24.0
2680
+ if (wknd_op_hrs_start_time_hr + wknd_op_hrs_duration_hr + (wknd_op_hrs_start_time_min + wknd_op_hrs_duration_min) / 60.0) > 24.0
2572
2681
  runner.registerInfo("Weekend start time of #{args['wknd_op_hrs_start']} plus duration of #{args['wknd_op_hrs_duration']} is more than 24 hrs, hours of operation overlap midnight.")
2573
2682
  end
2574
2683
  end
@@ -2584,7 +2693,7 @@ module OsLib_ModelGeneration
2584
2693
  standard = Standard.build((args['template']).to_s)
2585
2694
 
2586
2695
  # validate climate zone
2587
- if !args.has_key?('climate_zone') || args['climate_zone'] == 'Lookup From Model'
2696
+ if !args.key?('climate_zone') || args['climate_zone'] == 'Lookup From Model'
2588
2697
  climate_zone = standard.model_get_building_climate_zone_and_building_type(model)['climate_zone']
2589
2698
  runner.registerInfo("Using climate zone #{climate_zone} from model")
2590
2699
  else
@@ -2679,8 +2788,10 @@ module OsLib_ModelGeneration
2679
2788
  # TODO: - allow building type and space type specific constructions set selection.
2680
2789
  if ['SmallHotel', 'LargeHotel', 'MidriseApartment', 'HighriseApartment'].include?(primary_bldg_type)
2681
2790
  is_residential = 'Yes'
2791
+ occ_type = 'Residential'
2682
2792
  else
2683
2793
  is_residential = 'No'
2794
+ occ_type = 'Nonresidential'
2684
2795
  end
2685
2796
  bldg_def_const_set = standard.model_add_construction_set(model, climate_zone, lookup_building_type, nil, is_residential)
2686
2797
  if bldg_def_const_set.is_initialized
@@ -2694,6 +2805,31 @@ module OsLib_ModelGeneration
2694
2805
  return false
2695
2806
  end
2696
2807
 
2808
+ # Replace the construction of any outdoor-facing "AtticFloor" surfaces
2809
+ # with the "ExteriorRoof" - "IEAD" construction for the specific climate zone and template.
2810
+ # This prevents creation of buildings where the DOE Prototype building construction set
2811
+ # assumes an attic but the supplied geometry used does not have an attic.
2812
+ new_construction = nil
2813
+ climate_zone_set = standard.model_find_climate_zone_set(model, climate_zone)
2814
+ model.getSurfaces.sort.each do |surf|
2815
+ next unless surf.outsideBoundaryCondition == 'Outdoors'
2816
+ next unless surf.surfaceType == 'RoofCeiling'
2817
+ next if surf.construction.empty?
2818
+ construction = surf.construction.get
2819
+ standards_info = construction.standardsInformation
2820
+ next if standards_info.intendedSurfaceType.empty?
2821
+ next unless standards_info.intendedSurfaceType.get == 'AtticFloor'
2822
+ if new_construction.nil?
2823
+ new_construction = standard.model_find_and_add_construction(model,
2824
+ climate_zone_set,
2825
+ 'ExteriorRoof',
2826
+ 'IEAD',
2827
+ occ_type)
2828
+ end
2829
+ surf.setConstruction(new_construction)
2830
+ runner.registerInfo("Changed the construction for #{surf.name} from #{construction.name} to #{new_construction.name} to avoid outdoor-facing attic floor constructions in buildings with no attic space.")
2831
+ end
2832
+
2697
2833
  # address any adiabatic surfaces that don't have hard assigned constructions
2698
2834
  model.getSurfaces.sort.each do |surface|
2699
2835
  next if surface.outsideBoundaryCondition != 'Adiabatic'
@@ -2838,13 +2974,13 @@ module OsLib_ModelGeneration
2838
2974
  end
2839
2975
 
2840
2976
  # add daylight controls, need to perform a sizing run for 2010
2841
- if args['template'] == '90.1-2010'
2977
+ if args['template'] == '90.1-2010' || args['template'] == 'ComStock 90.1-2010'
2842
2978
  if standard.model_run_sizing_run(model, "#{Dir.pwd}/SRvt") == false
2843
2979
  log_messages_to_runner(runner, debug = true)
2844
2980
  return false
2845
2981
  end
2846
2982
  end
2847
- standard.model_add_daylighting_controls(model)
2983
+ standard.model_add_daylighting_controls(model)
2848
2984
  end
2849
2985
 
2850
2986
  # add refrigeration
@@ -2971,7 +3107,10 @@ module OsLib_ModelGeneration
2971
3107
  end
2972
3108
 
2973
3109
  # Add the primary system to the primary zones
2974
- standard.model_add_hvac_system(model, sys_type, central_htg_fuel, zone_htg_fuel, clg_fuel, system_zones)
3110
+ unless standard.model_add_hvac_system(model, sys_type, central_htg_fuel, zone_htg_fuel, clg_fuel, system_zones)
3111
+ runner.registerError("HVAC system type '#{sys_type}' not recognized. Check input system type argument against Model.hvac.rb for valid hvac system type names.")
3112
+ return false
3113
+ end
2975
3114
 
2976
3115
  # Add the secondary system to the secondary zones (if any)
2977
3116
  if !pri_sec_zone_lists['secondary'].empty?
@@ -2981,7 +3120,10 @@ module OsLib_ModelGeneration
2981
3120
  cooled_only_zones = system_zones.select { |zone| !standard.thermal_zone_heated?(zone) && standard.thermal_zone_cooled?(zone) }
2982
3121
  system_zones = heated_and_cooled_zones + cooled_only_zones
2983
3122
  end
2984
- standard.model_add_hvac_system(model, sec_sys_type, central_htg_fuel, zone_htg_fuel, clg_fuel, system_zones)
3123
+ unless standard.model_add_hvac_system(model, sec_sys_type, central_htg_fuel, zone_htg_fuel, clg_fuel, system_zones)
3124
+ runner.registerError("HVAC system type '#{sys_type}' not recognized. Check input system type argument against Model.hvac.rb for valid hvac system type names.")
3125
+ return false
3126
+ end
2985
3127
  end
2986
3128
  end
2987
3129
  end
@@ -2997,7 +3139,10 @@ module OsLib_ModelGeneration
2997
3139
  # Add the user specified HVAC system for each story.
2998
3140
  # Single-zone systems will get one per zone.
2999
3141
  story_groups.each do |zones|
3000
- model.add_cbecs_hvac_system(standard, args['system_type'], zones)
3142
+ unless model.add_cbecs_hvac_system(standard, args['system_type'], zones)
3143
+ runner.registerError("HVAC system type '#{args['system_type']}' not recognized. Check input system type argument against Model.hvac.rb for valid hvac system type names.")
3144
+ return false
3145
+ end
3001
3146
  end
3002
3147
  end
3003
3148
  end
@@ -3045,7 +3190,7 @@ module OsLib_ModelGeneration
3045
3190
  if args['add_hvac']
3046
3191
  # set additional properties for building
3047
3192
  props = model.getBuilding.additionalProperties
3048
- props.setFeature('hvac_system_type',"#{args['system_type']}")
3193
+ props.setFeature('hvac_system_type', (args['system_type']).to_s)
3049
3194
 
3050
3195
  case args['system_type']
3051
3196
  when 'Ideal Air Loads'
@@ -3115,7 +3260,6 @@ module OsLib_ModelGeneration
3115
3260
  # wizard
3116
3261
  # used for varieties of measures that create space type and construction set wizard
3117
3262
  def wizard(model, runner, user_arguments)
3118
-
3119
3263
  # use the built-in error checking
3120
3264
  if !runner.validateUserArguments(arguments(model), user_arguments)
3121
3265
  return false
@@ -3159,7 +3303,7 @@ module OsLib_ModelGeneration
3159
3303
  lookup_building_type = standard.model_get_lookup_name(building_type)
3160
3304
 
3161
3305
  # remap small medium and large office to office
3162
- if building_type.include?("Office") then building_type = "Office" end
3306
+ if building_type.include?('Office') then building_type = 'Office' end
3163
3307
 
3164
3308
  # get array of new space types
3165
3309
  space_types_new = []
@@ -3287,4 +3431,4 @@ module OsLib_ModelGeneration
3287
3431
 
3288
3432
  return true
3289
3433
  end
3290
- end
3434
+ end