openstudio-extension 0.2.5 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/CHANGELOG.md +28 -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/gemspec.txt +7 -5
  13. data/init_templates/openstudio_module.rb +1 -1
  14. data/init_templates/spec.rb +1 -1
  15. data/init_templates/spec_helper.rb +1 -1
  16. data/init_templates/template_gemfile.txt +1 -4
  17. data/init_templates/version.rb +1 -1
  18. data/lib/change_log.rb +1 -1
  19. data/lib/measures/openstudio_extension_test_measure/LICENSE.md +1 -1
  20. data/lib/measures/openstudio_extension_test_measure/measure.rb +1 -1
  21. data/lib/measures/openstudio_extension_test_measure/measure.xml +12 -12
  22. data/lib/measures/openstudio_extension_test_measure/resources/os_lib_helper_methods.rb +15 -2
  23. data/lib/openstudio-extension.rb +1 -1
  24. data/lib/openstudio/extension.rb +4 -3
  25. data/lib/openstudio/extension/core/CreateResults.rb +1 -1
  26. data/lib/openstudio/extension/core/check_air_sys_temps.rb +1 -1
  27. data/lib/openstudio/extension/core/check_calibration.rb +1 -1
  28. data/lib/openstudio/extension/core/check_cond_zns.rb +1 -1
  29. data/lib/openstudio/extension/core/check_domestic_hot_water.rb +1 -1
  30. data/lib/openstudio/extension/core/check_envelope_conductance.rb +1 -1
  31. data/lib/openstudio/extension/core/check_eui_by_end_use.rb +1 -1
  32. data/lib/openstudio/extension/core/check_eui_reasonableness.rb +1 -1
  33. data/lib/openstudio/extension/core/check_fan_pwr.rb +1 -1
  34. data/lib/openstudio/extension/core/check_internal_loads.rb +1 -1
  35. data/lib/openstudio/extension/core/check_mech_sys_capacity.rb +1 -1
  36. data/lib/openstudio/extension/core/check_mech_sys_efficiency.rb +1 -1
  37. data/lib/openstudio/extension/core/check_mech_sys_part_load_eff.rb +1 -1
  38. data/lib/openstudio/extension/core/check_mech_sys_type.rb +1 -1
  39. data/lib/openstudio/extension/core/check_part_loads.rb +1 -1
  40. data/lib/openstudio/extension/core/check_placeholder.rb +1 -1
  41. data/lib/openstudio/extension/core/check_plant_cap.rb +1 -1
  42. data/lib/openstudio/extension/core/check_plant_temps.rb +1 -1
  43. data/lib/openstudio/extension/core/check_plenum_loads.rb +1 -1
  44. data/lib/openstudio/extension/core/check_pump_pwr.rb +1 -1
  45. data/lib/openstudio/extension/core/check_sch_coord.rb +1 -1
  46. data/lib/openstudio/extension/core/check_schedules.rb +1 -1
  47. data/lib/openstudio/extension/core/check_simultaneous_heating_and_cooling.rb +1 -1
  48. data/lib/openstudio/extension/core/check_supply_air_and_thermostat_temp_difference.rb +1 -1
  49. data/lib/openstudio/extension/core/check_weather_files.rb +1 -1
  50. data/lib/openstudio/extension/core/deer_vintages.rb +1 -1
  51. data/lib/openstudio/extension/core/os_lib_aedg_measures.rb +5 -5
  52. data/lib/openstudio/extension/core/os_lib_constructions.rb +1 -1
  53. data/lib/openstudio/extension/core/os_lib_geometry.rb +4 -4
  54. data/lib/openstudio/extension/core/os_lib_helper_methods.rb +15 -2
  55. data/lib/openstudio/extension/core/os_lib_hvac.rb +18 -18
  56. data/lib/openstudio/extension/core/os_lib_lighting_and_equipment.rb +1 -1
  57. data/lib/openstudio/extension/core/os_lib_model_generation.rb +393 -237
  58. data/lib/openstudio/extension/core/os_lib_model_simplification.rb +10 -10
  59. data/lib/openstudio/extension/core/os_lib_outdoorair_and_infiltration.rb +3 -3
  60. data/lib/openstudio/extension/core/os_lib_reporting_qaqc.rb +1 -1
  61. data/lib/openstudio/extension/core/os_lib_schedules.rb +1 -1
  62. data/lib/openstudio/extension/rake_task.rb +1 -1
  63. data/lib/openstudio/extension/runner.rb +35 -19
  64. data/lib/openstudio/extension/runner_config.rb +1 -1
  65. data/lib/openstudio/extension/version.rb +2 -2
  66. data/openstudio-extension.gemspec +6 -5
  67. metadata +28 -15
  68. data/lib/openstudio/extension/core/os_lib_reporting.rb +0 -4755
@@ -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:
@@ -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:
@@ -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:
@@ -765,7 +765,7 @@ module OsLib_Geometry
765
765
  story_hash.each_with_index do |(story_name, story_data), index|
766
766
  # make new story unless story at requested height already exists.
767
767
  story = nil
768
- model.getBuildingStorys.each do |ext_story|
768
+ model.getBuildingStorys.sort.each do |ext_story|
769
769
  if (ext_story.nominalZCoordinate.to_f - story_data[:space_origin_z].to_f).abs < 0.01
770
770
  story = ext_story
771
771
  end
@@ -1133,11 +1133,11 @@ module OsLib_Geometry
1133
1133
  # todo - also odd with multi-height spaces
1134
1134
  def self.calculate_perimeter(model)
1135
1135
  perimeter = 0
1136
- model.getSpaces.each do |space|
1136
+ model.getSpaces.sort.each do |space|
1137
1137
  # counter to use later
1138
1138
  edge_hash = {}
1139
1139
  edge_counter = 0
1140
- space.surfaces.each do |surface|
1140
+ space.surfaces.sort.each do |surface|
1141
1141
  # get vertices
1142
1142
  vertex_hash = {}
1143
1143
  vertex_counter = 0
@@ -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:
@@ -117,7 +117,7 @@ module OsLib_HVAC
117
117
  zonesUnconditioned = []
118
118
 
119
119
  # get thermal zones
120
- zones = model.getThermalZones
120
+ zones = model.getThermalZones.sort
121
121
  zones.each do |zone|
122
122
  # assign appropriate zones to zonesPlenum or zonesUnconditioned (those that don't have thermostats or zone HVAC equipment)
123
123
  # if not conditioned then add to zonesPlenum or zonesUnconditioned
@@ -177,9 +177,9 @@ module OsLib_HVAC
177
177
 
178
178
  def self.reportConditions(model, runner, condition,extra_string = '')
179
179
 
180
- airloops = model.getAirLoopHVACs
181
- plantLoops = model.getPlantLoops
182
- zones = model.getThermalZones
180
+ airloops = model.getAirLoopHVACs.sort
181
+ plantLoops = model.getPlantLoops.sort
182
+ zones = model.getThermalZones.sort
183
183
 
184
184
  # count up zone equipment (not counting zone exhaust fans)
185
185
  zoneHasEquip = false
@@ -205,9 +205,9 @@ module OsLib_HVAC
205
205
  end
206
206
 
207
207
  def self.removeEquipment(model, runner)
208
- airloops = model.getAirLoopHVACs
209
- plantLoops = model.getPlantLoops
210
- zones = model.getThermalZones
208
+ airloops = model.getAirLoopHVACs.sort
209
+ plantLoops = model.getPlantLoops.sort
210
+ zones = model.getThermalZones.sort
211
211
 
212
212
  # remove all airloops
213
213
  airloops.each(&:remove)
@@ -244,7 +244,7 @@ module OsLib_HVAC
244
244
  require "#{File.dirname(__FILE__)}/os_lib_schedules"
245
245
 
246
246
  schedulesHVAC = {}
247
- airloops = model.getAirLoopHVACs
247
+ airloops = model.getAirLoopHVACs.sort
248
248
 
249
249
  # find airloop with most primary spaces
250
250
  max_primary_spaces = 0
@@ -628,7 +628,7 @@ module OsLib_HVAC
628
628
 
629
629
  # check for water-cooled chillers
630
630
  waterCooledChiller = false
631
- model.getChillerElectricEIRs.each do |chiller|
631
+ model.getChillerElectricEIRs.sort.each do |chiller|
632
632
  next if waterCooledChiller == true
633
633
  if chiller.condenserType == 'WaterCooled'
634
634
  waterCooledChiller = true
@@ -678,7 +678,7 @@ module OsLib_HVAC
678
678
  pipe_supply_outlet.addToNode(condenser_loop.supplyOutletNode)
679
679
  setpoint_manager_follow_oa.addToNode(condenser_loop.supplyOutletNode)
680
680
  # demand side components
681
- model.getChillerElectricEIRs.each do |chiller|
681
+ model.getChillerElectricEIRs.sort.each do |chiller|
682
682
  if chiller.condenserType == 'WaterCooled' # works only if chillers not already connected to condenser loop(s)
683
683
  condenser_loop.addDemandBranchForComponent(chiller)
684
684
  end
@@ -771,7 +771,7 @@ module OsLib_HVAC
771
771
  primary_airloops = []
772
772
  # create primary airloop for each story
773
773
  assignedThermalZones = []
774
- model.getBuildingStorys.each do |building_story|
774
+ model.getBuildingStorys.sort.each do |building_story|
775
775
  # ML stories need to be reordered from the ground up
776
776
  thermalZonesToAdd = []
777
777
  building_story.spaces.each do |space|
@@ -1069,7 +1069,7 @@ module OsLib_HVAC
1069
1069
  def self.createSecondaryAirLoops(model, runner, options)
1070
1070
  secondary_airloops = []
1071
1071
  # create secondary airloop for each secondary zone
1072
- model.getThermalZones.each do |zone|
1072
+ model.getThermalZones.sort.each do |zone|
1073
1073
  if options['zonesSecondary'].include? zone
1074
1074
  # create secondary airloop
1075
1075
  airloop_secondary = OpenStudio::Model::AirLoopHVAC.new(model)
@@ -1314,7 +1314,7 @@ module OsLib_HVAC
1314
1314
  end
1315
1315
 
1316
1316
  def self.createPrimaryZoneEquipment(model, runner, options)
1317
- model.getThermalZones.each do |zone|
1317
+ model.getThermalZones.sort.each do |zone|
1318
1318
  if options['zonesPrimary'].include? zone
1319
1319
  if options['zoneHVAC'] == 'FanCoil'
1320
1320
  # create fan coil
@@ -1521,7 +1521,7 @@ module OsLib_HVAC
1521
1521
  def self.get_or_add_hot_water_loop(model)
1522
1522
  # How water loop
1523
1523
  hw_loop = nil
1524
- model.getLoops.each do |loop|
1524
+ model.getLoops.sort.each do |loop|
1525
1525
  if loop.name.to_s == 'Hot Water Loop' # sizingPlant has loopType method to do this better
1526
1526
  hw_loop = loop.to_PlantLoop.get
1527
1527
  end
@@ -1580,7 +1580,7 @@ module OsLib_HVAC
1580
1580
  # Chilled Water Plant
1581
1581
  # todo - add in logic here that if existing chw_loop is air cooled, replace it with this one.
1582
1582
  chw_loop = nil
1583
- model.getLoops.each do |loop|
1583
+ model.getLoops.sort.each do |loop|
1584
1584
  if loop.name.to_s == 'Chilled Water Loop'
1585
1585
  chw_loop = loop.to_PlantLoop.get
1586
1586
  end
@@ -1658,7 +1658,7 @@ module OsLib_HVAC
1658
1658
 
1659
1659
  # Condenser System
1660
1660
  cw_loop = nil
1661
- model.getLoops.each do |loop|
1661
+ model.getLoops.sort.each do |loop|
1662
1662
  if loop.name.to_s == 'Condenser Water Loop'
1663
1663
  cw_loop = loop.to_PlantLoop.get
1664
1664
  end
@@ -1702,7 +1702,7 @@ module OsLib_HVAC
1702
1702
  def self.get_or_add_air_cooled_chiller_loop(model)
1703
1703
  # Chilled Water Plant
1704
1704
  chw_loop = nil
1705
- model.getLoops.each do |loop|
1705
+ model.getLoops.sort.each do |loop|
1706
1706
  if loop.name.to_s == 'Chilled Water Loop'
1707
1707
  chw_loop = loop.to_PlantLoop.get
1708
1708
  end
@@ -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 }
@@ -1049,7 +1054,7 @@ module OsLib_ModelGeneration
1049
1054
  # only intersect if make_mid_story_surfaces_adiabatic false
1050
1055
  if diagnostic_intersect
1051
1056
 
1052
- model.getPlanarSurfaces.each do |surface|
1057
+ model.getPlanarSurfaces.sort.each do |surface|
1053
1058
  array = []
1054
1059
  vertices = surface.vertices
1055
1060
  fixed = false
@@ -1075,7 +1080,7 @@ module OsLib_ModelGeneration
1075
1080
  end
1076
1081
 
1077
1082
  # remove collinear points in a surface
1078
- model.getPlanarSurfaces.each do |surface|
1083
+ model.getPlanarSurfaces.sort.each do |surface|
1079
1084
  new_vertices = OpenStudio.removeCollinear(surface.vertices)
1080
1085
  starting_count = surface.vertices.size
1081
1086
  final_count = new_vertices.size
@@ -1086,13 +1091,11 @@ module OsLib_ModelGeneration
1086
1091
  end
1087
1092
 
1088
1093
  # remove duplicate surfaces in a space (should be done after remove duplicate and collinear points)
1089
- model.getSpaces.each do |space|
1090
-
1094
+ model.getSpaces.sort.each do |space|
1091
1095
  # secondary array to compare against
1092
1096
  surfaces_b = space.surfaces.sort
1093
1097
 
1094
1098
  space.surfaces.sort.each do |surface_a|
1095
-
1096
1099
  # delete from secondary array
1097
1100
  surfaces_b.delete(surface_a)
1098
1101
 
@@ -1102,13 +1105,11 @@ module OsLib_ModelGeneration
1102
1105
  runner.registerWarning("#{surface_a.name} and #{surface_b.name} in #{space.name} have duplicate geometry, removing #{surface_b.name}.")
1103
1106
  surface_b.remove
1104
1107
  elsif surface_a.reverseEqualVertices(surface_b)
1105
- # 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
1106
1109
  runner.registerWarning("#{surface_a.name} and #{surface_b.name} in #{space.name} have reversed geometry, removing #{surface_b.name}.")
1107
1110
  surface_b.remove
1108
1111
  end
1109
-
1110
1112
  end
1111
-
1112
1113
  end
1113
1114
  end
1114
1115
 
@@ -1119,7 +1120,7 @@ module OsLib_ModelGeneration
1119
1120
  model.getSpaces.sort.each do |space_a|
1120
1121
  spaces_b.delete(space_a)
1121
1122
  spaces_b.each do |space_b|
1122
- #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}")
1123
1124
  spaces_temp = OpenStudio::Model::SpaceVector.new
1124
1125
  spaces_temp << space_a
1125
1126
  spaces_temp << space_b
@@ -1129,8 +1130,8 @@ module OsLib_ModelGeneration
1129
1130
  end
1130
1131
  end
1131
1132
  runner.registerInfo('Intersecting and matching surfaces in model, this will create additional geometry.')
1132
- else #elsif bar_hash[:double_loaded_corridor] # only intersect spaces in each story, not between wtory
1133
- model.getBuilding.buildingStories.each do |story|
1133
+ else # elsif bar_hash[:double_loaded_corridor] # only intersect spaces in each story, not between wtory
1134
+ model.getBuilding.buildingStories.sort.each do |story|
1134
1135
  # intersect and surface match two pair by pair
1135
1136
  spaces_b = story.spaces.sort
1136
1137
  # looping through vector of each space
@@ -1160,8 +1161,8 @@ module OsLib_ModelGeneration
1160
1161
  OpenStudio::Model.matchSurfaces(spaces)
1161
1162
  runner.registerInfo('Intersecting and matching surfaces in model, this will create additional geometry.')
1162
1163
  end
1163
- else #elsif bar_hash[:double_loaded_corridor] # only intersect spaces in each story, not between wtory
1164
- model.getBuilding.buildingStories.each do |story|
1164
+ else # elsif bar_hash[:double_loaded_corridor] # only intersect spaces in each story, not between wtory
1165
+ model.getBuilding.buildingStories.sort.each do |story|
1165
1166
  story_spaces = OpenStudio::Model::SpaceVector.new
1166
1167
  story.spaces.sort.each do |space|
1167
1168
  story_spaces << space
@@ -1177,11 +1178,11 @@ module OsLib_ModelGeneration
1177
1178
  # set boundary conditions if not already set when geometry was created
1178
1179
  # todo - update this to use space original z value vs. story name
1179
1180
  if bar_hash[:num_stories_below_grade] > 0
1180
- model.getBuildingStorys.each do |story|
1181
+ model.getBuildingStorys.sort.each do |story|
1181
1182
  next if !story.name.to_s.include?('Story B')
1182
- story.spaces.each do |space|
1183
- next if not new_spaces.include?(space)
1184
- space.surfaces.each do |surface|
1183
+ story.spaces.sort.each do |space|
1184
+ next if !new_spaces.include?(space)
1185
+ space.surfaces.sort.each do |surface|
1185
1186
  next if surface.surfaceType != 'Wall'
1186
1187
  next if surface.outsideBoundaryCondition != 'Outdoors'
1187
1188
  surface.setOutsideBoundaryCondition('Ground')
@@ -1193,9 +1194,9 @@ module OsLib_ModelGeneration
1193
1194
  # sort stories (by name for now but need better way)
1194
1195
  sorted_stories = {}
1195
1196
  new_spaces.each do |space|
1196
- next if ! space.buildingStory.is_initialized
1197
+ next if !space.buildingStory.is_initialized
1197
1198
  story = space.buildingStory.get
1198
- if ! sorted_stories.has_key?(name.to_s)
1199
+ if !sorted_stories.key?(name.to_s)
1199
1200
  sorted_stories[story.name.to_s] = story
1200
1201
  end
1201
1202
  end
@@ -1228,7 +1229,7 @@ module OsLib_ModelGeneration
1228
1229
  party_wall_facades = stories_flat[i][:story_party_walls]
1229
1230
 
1230
1231
  story.spaces.each do |space|
1231
- next if not new_spaces.include?(space)
1232
+ next if !new_spaces.include?(space)
1232
1233
  space.surfaces. each do |surface|
1233
1234
  # set floor to adiabatic if requited
1234
1235
  if adiabatic_floor && surface.surfaceType == 'Floor'
@@ -1324,7 +1325,6 @@ module OsLib_ModelGeneration
1324
1325
  end
1325
1326
 
1326
1327
  return new_spaces
1327
-
1328
1328
  end
1329
1329
 
1330
1330
  # make selected surfaces adiabatic
@@ -1392,7 +1392,7 @@ module OsLib_ModelGeneration
1392
1392
  return bar
1393
1393
  end
1394
1394
 
1395
- 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)
1396
1396
  # create envelope
1397
1397
  # populate bar_hash and create envelope with data from envelope_data_hash and user arguments
1398
1398
  bar_hash = {}
@@ -1584,31 +1584,31 @@ module OsLib_ModelGeneration
1584
1584
  roof_area = 0.0
1585
1585
  new_spaces.each do |space|
1586
1586
  space.surfaces.each do |surface|
1587
- if surface.surfaceType == "Floor" && surface.outsideBoundaryCondition == "Ground"
1587
+ if surface.surfaceType == 'Floor' && surface.outsideBoundaryCondition == 'Ground'
1588
1588
  ground_floor_area += surface.netArea
1589
- elsif surface.surfaceType == "RoofCeiling" && surface.outsideBoundaryCondition == "Outdoors"
1589
+ elsif surface.surfaceType == 'RoofCeiling' && surface.outsideBoundaryCondition == 'Outdoors'
1590
1590
  roof_area += surface.netArea
1591
1591
  end
1592
1592
  end
1593
1593
  end
1594
- # 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
1595
1595
  if ground_floor_area > target_footprint + 0.001 || roof_area > target_footprint + 0.001
1596
- #runner.registerError("Ground exposed floor or Roof area is larger than footprint, likely inter-floor surface matching and intersection error.")
1597
- #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
1598
1598
 
1599
1599
  # not providing adiabatic work around when top story is partial story.
1600
1600
  if args['num_stories_above_grade'].to_f != args['num_stories_above_grade'].ceil
1601
- 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.')
1602
1602
  return false
1603
1603
  else
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.")
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.')
1605
1605
  match_error = true
1606
1606
  end
1607
1607
  else
1608
1608
  match_error = false
1609
1609
  end
1610
1610
 
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
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
1612
1612
  if match_error
1613
1613
 
1614
1614
  # identify z value of top and bottom story
@@ -1634,38 +1634,34 @@ module OsLib_ModelGeneration
1634
1634
  if space.buildingStory.get.nominalZCoordinate.get > bottom_story
1635
1635
  # change floors
1636
1636
  space.surfaces.each do |surface|
1637
- next if not surface.surfaceType == "Floor" && surface.outsideBoundaryCondition == "Ground"
1638
- surface.setOutsideBoundaryCondition("Adiabatic")
1637
+ next if !(surface.surfaceType == 'Floor' && surface.outsideBoundaryCondition == 'Ground')
1638
+ surface.setOutsideBoundaryCondition('Adiabatic')
1639
1639
  end
1640
1640
  end
1641
1641
  if space.buildingStory.get.nominalZCoordinate.get < top_story
1642
1642
  # change ceilings
1643
1643
  space.surfaces.each do |surface|
1644
- next if not surface.surfaceType == "RoofCeiling" && surface.outsideBoundaryCondition == "Outdoors"
1645
- surface.setOutsideBoundaryCondition("Adiabatic")
1644
+ next if !(surface.surfaceType == 'RoofCeiling' && surface.outsideBoundaryCondition == 'Outdoors')
1645
+ surface.setOutsideBoundaryCondition('Adiabatic')
1646
1646
  end
1647
1647
  end
1648
1648
  end
1649
-
1650
1649
  end
1651
-
1652
-
1653
1650
  end
1654
1651
 
1655
- # bar_from_building_type_ratios
1656
- # used for varieties of measures that create bar from building type ratios
1657
- 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)
1658
1654
 
1659
1655
  # assign the user inputs to variables
1660
1656
  args = OsLib_HelperMethods.createRunVariables(runner, model, user_arguments, arguments(model))
1661
1657
  if !args then return false end
1662
1658
 
1663
1659
  # add in arguments that may not be passed in
1664
- if !args.has_key?("double_loaded_corridor")
1665
- 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
1666
1662
  end
1667
- if ! args.has_key?("perim_mult")
1668
- 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
1669
1665
  end
1670
1666
 
1671
1667
  # lookup and replace argument values from upstream measures
@@ -1691,10 +1687,12 @@ module OsLib_ModelGeneration
1691
1687
  end
1692
1688
 
1693
1689
  # check expected values of double arguments
1694
- fraction_args = ['bldg_type_b_fract_bldg_area',
1695
- 'bldg_type_c_fract_bldg_area',
1696
- 'bldg_type_d_fract_bldg_area',
1697
- '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
1698
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)
1699
1697
 
1700
1698
  positive_args = ['total_bldg_floor_area']
@@ -1711,49 +1709,25 @@ module OsLib_ModelGeneration
1711
1709
  'party_wall_stories_east',
1712
1710
  'party_wall_stories_west',
1713
1711
  'single_floor_area',
1714
- 'bar_width',]
1712
+ 'bar_width']
1715
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)
1716
1714
 
1717
1715
  # return false if any errors fail
1718
1716
  if !fraction then return false end
1719
1717
  if !positive then return false end
1720
- if !one_or_greater then return false end
1721
- if !non_neg then return false end
1718
+ return false if !one_or_greater
1719
+ return false if !non_neg
1722
1720
 
1723
- # if aspect ratio, story height or wwr have argument value of 0 then use smart building type defaults
1724
- building_form_defaults = building_form_defaults(args['bldg_type_a'])
1721
+ return args
1725
1722
 
1726
- # store list of defaulted items
1727
- defaulted_args = []
1728
-
1729
- if args['ns_to_ew_ratio'] == 0.0
1730
- args['ns_to_ew_ratio'] = building_form_defaults[:aspect_ratio]
1731
- 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]}.")
1732
- end
1723
+ end
1733
1724
 
1734
- if args['perim_mult'] == 0.0
1735
- # if this is not defined then use default of 1.0
1736
- if !building_form_defaults.has_key?(:perim_mult)
1737
- args['perim_mult'] = 1.0
1738
- else
1739
- args['perim_mult'] = building_form_defaults[:perim_mult]
1740
- end
1741
- 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]}.")
1742
- elsif args['perim_mult'] < 1.0
1743
- runner.registerError("Other than the smart default value of 0, the minimum perimeter multiplier should be equal to 1.0 or greater.")
1744
- return false
1745
- 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)
1746
1728
 
1747
- if args['floor_height'] == 0.0
1748
- args['floor_height'] = building_form_defaults[:typical_story]
1749
- 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]}.")
1750
- defaulted_args << 'floor_height'
1751
- end
1752
- # 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
1753
- if args['wwr'] == 0.0
1754
- args['wwr'] = building_form_defaults[:wwr]
1755
- 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]}.")
1756
- end
1729
+ # prep arguments
1730
+ args = bar_arg_check_setup(model,runner,user_arguments)
1757
1731
 
1758
1732
  # check that sum of fractions for b,c, and d is less than 1.0 (so something is left for primary building type)
1759
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']
@@ -1763,7 +1737,7 @@ module OsLib_ModelGeneration
1763
1737
  end
1764
1738
 
1765
1739
  # Make the standard applier
1766
- standard = Standard.build("#{args['template']}")
1740
+ standard = Standard.build((args['template']).to_s)
1767
1741
 
1768
1742
  # report initial condition of model
1769
1743
  runner.registerInitialCondition("The building started with #{model.getSpaces.size} spaces.")
@@ -1793,14 +1767,14 @@ module OsLib_ModelGeneration
1793
1767
  # gather data for bldg_type_a
1794
1768
  building_type_hash[args['bldg_type_a']] = {}
1795
1769
  building_type_hash[args['bldg_type_a']][:frac_bldg_area] = bldg_type_a_fract_bldg_area
1796
- #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']
1797
1771
  building_type_hash[args['bldg_type_a']][:space_types] = get_space_types_from_building_type(args['bldg_type_a'], args['template'], true)
1798
1772
 
1799
1773
  # gather data for bldg_type_b
1800
1774
  if args['bldg_type_b_fract_bldg_area'] > 0
1801
1775
  building_type_hash[args['bldg_type_b']] = {}
1802
1776
  building_type_hash[args['bldg_type_b']][:frac_bldg_area] = args['bldg_type_b_fract_bldg_area']
1803
- #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']
1804
1778
  building_type_hash[args['bldg_type_b']][:space_types] = get_space_types_from_building_type(args['bldg_type_b'], args['template'], true)
1805
1779
  end
1806
1780
 
@@ -1808,7 +1782,7 @@ module OsLib_ModelGeneration
1808
1782
  if args['bldg_type_c_fract_bldg_area'] > 0
1809
1783
  building_type_hash[args['bldg_type_c']] = {}
1810
1784
  building_type_hash[args['bldg_type_c']][:frac_bldg_area] = args['bldg_type_c_fract_bldg_area']
1811
- #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']
1812
1786
  building_type_hash[args['bldg_type_c']][:space_types] = get_space_types_from_building_type(args['bldg_type_c'], args['template'], true)
1813
1787
  end
1814
1788
 
@@ -1816,10 +1790,145 @@ module OsLib_ModelGeneration
1816
1790
  if args['bldg_type_d_fract_bldg_area'] > 0
1817
1791
  building_type_hash[args['bldg_type_d']] = {}
1818
1792
  building_type_hash[args['bldg_type_d']][:frac_bldg_area] = args['bldg_type_d_fract_bldg_area']
1819
- #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']
1820
1794
  building_type_hash[args['bldg_type_d']][:space_types] = get_space_types_from_building_type(args['bldg_type_d'], args['template'], true)
1821
1795
  end
1822
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
+
1823
1932
  # creating space types for requested building types
1824
1933
  building_type_hash.each do |building_type, building_type_hash|
1825
1934
  runner.registerInfo("Creating Space Types for #{building_type}.")
@@ -1842,8 +1951,8 @@ module OsLib_ModelGeneration
1842
1951
  # set color
1843
1952
  test = standard.space_type_apply_rendering_color(space_type) # this uses openstudio-standards
1844
1953
  if !test
1845
- # todo - once fixed in standards un-comment this
1846
- #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}")
1847
1956
  end
1848
1957
 
1849
1958
  # extend hash to hold new space type object
@@ -1871,7 +1980,7 @@ module OsLib_ModelGeneration
1871
1980
  runner.registerWarning('User-defined single floor area was used for calculation of total building floor area')
1872
1981
  # add warning if custom_height_bar is true and applicable building type is selected
1873
1982
  if args['custom_height_bar']
1874
- 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.')
1875
1984
  args['custom_height_bar'] = false
1876
1985
  end
1877
1986
  else
@@ -1886,8 +1995,7 @@ module OsLib_ModelGeneration
1886
1995
  building_type_hash = building_type_hash.sort_by { |k, v| v[:frac_bldg_area] }
1887
1996
  end
1888
1997
  building_type_hash.each do |building_type, building_type_hash|
1889
-
1890
- if args["double_loaded_corridor"] == "Primary Space Type"
1998
+ if args['double_loaded_corridor'] == 'Primary Space Type'
1891
1999
 
1892
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
1893
2001
  default_st = nil
@@ -1902,8 +2010,8 @@ module OsLib_ModelGeneration
1902
2010
  runner.registerInfo("Combining #{default_st} and #{circ_st} into a group representing a double loaded corridor")
1903
2011
 
1904
2012
  # add new item
1905
- building_type_hash[:space_types]["Double Loaded Corridor"] = {}
1906
- 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']
1907
2015
  double_loaded_st[:ratio] = building_type_hash[:space_types][default_st][:ratio] + building_type_hash[:space_types][circ_st][:ratio]
1908
2016
  double_loaded_st[:double_loaded_corridor] = true
1909
2017
  double_loaded_st[:space_type] = model.getBuilding
@@ -1938,21 +2046,21 @@ module OsLib_ModelGeneration
1938
2046
  multi_height_space_types_hash[space_type][:wwr] = hash[:wwr]
1939
2047
  end
1940
2048
  else
1941
- # only add wwr if 0 used for wwr arg and if space type has wwr as key
1942
- space_types_hash[space_type] = { floor_area: final_floor_area, space_type: space_type }
1943
- if hash.key?(:orig_ratio) then space_types_hash[space_type][:orig_ratio] = hash[:orig_ratio] end
1944
- if args['wwr'] == 0 && hash.key?(:wwr)
1945
- space_types_hash[space_type][:wwr] = hash[:wwr]
1946
- end
1947
- if hash[:double_loaded_corridor]
1948
- space_types_hash[space_type][:children] = hash[:children]
1949
- 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
1950
2058
  end
1951
2059
  end
1952
2060
  end
1953
2061
 
1954
2062
  # resort if not sorted by building type
1955
- if args['space_type_sort_logic'] == "Size"
2063
+ if args['space_type_sort_logic'] == 'Size'
1956
2064
  # added code to convert to hash. I use sort_by 3 other times, but those seem to be working fine as is now.
1957
2065
  space_types_hash = Hash[space_types_hash.sort_by { |k, v| v[:floor_area] }]
1958
2066
  end
@@ -1960,14 +2068,14 @@ module OsLib_ModelGeneration
1960
2068
  # calculate targets for testing
1961
2069
  target_areas = {} # used for checks
1962
2070
  target_areas_cust_height = 0.0
1963
- space_types_hash.each do |k,v|
2071
+ space_types_hash.each do |k, v|
1964
2072
  if v.key?(:orig_ratio)
1965
2073
  target_areas[k] = v[:orig_ratio] * total_bldg_floor_area_si
1966
2074
  else
1967
2075
  target_areas[k] = v[:floor_area]
1968
2076
  end
1969
2077
  end
1970
- multi_height_space_types_hash.each do |k,v|
2078
+ multi_height_space_types_hash.each do |k, v|
1971
2079
  if v.key?(:orig_ratio)
1972
2080
  target_areas[k] = v[:orig_ratio] * total_bldg_floor_area_si
1973
2081
  target_areas_cust_height += v[:orig_ratio] * total_bldg_floor_area_si
@@ -1982,19 +2090,19 @@ module OsLib_ModelGeneration
1982
2090
  footprint_si = (total_bldg_floor_area_si - target_areas_cust_height) / num_stories.to_f
1983
2091
  end
1984
2092
  floor_height_si = OpenStudio.convert(args['floor_height'], 'ft', 'm').get
1985
- min_allow_size = OpenStudio.convert(15.0,'ft','m').get
1986
- 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
1987
2095
 
1988
2096
  # set custom width
1989
2097
  if specified_bar_width_si > 0
1990
- 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')
1991
2099
  if footprint_si / specified_bar_width_si >= min_allow_size
1992
2100
  width = specified_bar_width_si
1993
2101
  length = footprint_si / width
1994
2102
  else
1995
2103
  length = min_allow_size
1996
2104
  width = footprint_si / length
1997
- 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.')
1998
2106
  end
1999
2107
  width_cust_height = specified_bar_width_si
2000
2108
  else
@@ -2004,29 +2112,29 @@ module OsLib_ModelGeneration
2004
2112
  end
2005
2113
  length_cust_height = target_areas_cust_height / width_cust_height
2006
2114
  if args['perim_mult'] > 1.0 && target_areas_cust_height > 0.0
2007
- # todo - update tests that hit this warning
2008
- 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.')
2009
2117
  end
2010
2118
 
2011
2119
  # check if dual bar is needed
2012
2120
  dual_bar = false
2013
2121
  if specified_bar_width_si > 0.0 && args['bar_division_method'] == 'Multiple Space Types - Individual Stories Sliced'
2014
- if length/width != args['ns_to_ew_ratio']
2015
-
2016
- if args['ns_to_ew_ratio'] >= 1.0 && args['ns_to_ew_ratio'] > length/width
2017
- runner.registerWarning("Can't meet target aspect ratio of #{args['ns_to_ew_ratio']}, Lowering it to #{length/width} ")
2018
- args['ns_to_ew_ratio'] = length/width
2019
- elsif args['ns_to_ew_ratio'] < 1.0 && args['ns_to_ew_ratio'] > length/width
2020
- runner.registerWarning("Can't meet target aspect ratio of #{args['ns_to_ew_ratio']}, Increasing it to #{length/width} ")
2021
- 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
2022
2130
  else
2023
2131
  # check if each bar would be longer then 15 feet, then set as dual bar and override perimeter multiplier
2024
- 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'])
2025
2133
  length_alt2 = length - length_alt1
2026
- if [length_alt1,length_alt2].min >= min_allow_size
2134
+ if [length_alt1, length_alt2].min >= min_allow_size
2027
2135
  dual_bar = true
2028
2136
  else
2029
- 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')
2030
2138
  # swap length and width if single bar and aspect ratio less than 1
2031
2139
  if args['ns_to_ew_ratio'] < 1.0
2032
2140
  width = length
@@ -2036,7 +2144,7 @@ module OsLib_ModelGeneration
2036
2144
  end
2037
2145
  end
2038
2146
  elsif args['perim_mult'] > 1.0 && args['bar_division_method'] == 'Multiple Space Types - Individual Stories Sliced'
2039
- 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.')
2040
2148
  dual_bar = true
2041
2149
  elsif args['perim_mult'] > 1.0
2042
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")
@@ -2060,7 +2168,7 @@ module OsLib_ModelGeneration
2060
2168
  # custom quadratic equation to solve two bars with common width 2l^2 - p*l + 4a = 0
2061
2169
  if target_perim**2 - 32 * footprint_si > 0
2062
2170
  if specified_bar_width_si > 0
2063
- 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.')
2064
2172
  dual_double_end_width = specified_bar_width_si
2065
2173
  dual_double_end_length = footprint_si / dual_double_end_width
2066
2174
  else
@@ -2069,7 +2177,7 @@ module OsLib_ModelGeneration
2069
2177
  end
2070
2178
 
2071
2179
  # now that stretched bar is made, determine where to split it and rotate
2072
- 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'])
2073
2181
  bar_b_length = dual_double_end_length - bar_a_length
2074
2182
  area_a = bar_a_length * dual_double_end_width
2075
2183
  area_b = bar_b_length * dual_double_end_width
@@ -2088,15 +2196,15 @@ module OsLib_ModelGeneration
2088
2196
  adiabatic_dual_double_end_width = footprint_si / adiabatic_dual_double_end_length
2089
2197
  # test for unexpected
2090
2198
  unexpected = false
2091
- 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
2092
2200
  if specified_bar_width_si == 0
2093
2201
  if (target_perim - (adiabatic_dual_double_end_length * 2 + adiabatic_dual_double_end_width * 2)).abs > tol_testing then unexpected = true end
2094
2202
  end
2095
2203
  if unexpected
2096
- runner.registerWarning("Unexpected values for dual rectangle adiabatic ends bar b.")
2204
+ runner.registerWarning('Unexpected values for dual rectangle adiabatic ends bar b.')
2097
2205
  end
2098
2206
  # now that stretched bar is made, determine where to split it and rotate
2099
- 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'])
2100
2208
  adiabatic_bar_b_length = adiabatic_dual_double_end_length - adiabatic_bar_a_length
2101
2209
  adiabatic_area_a = adiabatic_bar_a_length * adiabatic_dual_double_end_width
2102
2210
  adiabatic_area_b = adiabatic_bar_b_length * adiabatic_dual_double_end_width
@@ -2115,28 +2223,28 @@ module OsLib_ModelGeneration
2115
2223
  # apply prescribed approach for stretched or dual bar
2116
2224
  if dual_bar_calc_approach == 'dual_bar'
2117
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")
2118
- 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
2119
- 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.')
2120
2228
  end
2121
2229
 
2122
- 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")
2123
- 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
2124
- 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')
2125
2233
  end
2126
2234
  elsif dual_bar_calc_approach == 'adiabatic_ends_bar_b'
2127
2235
  runner.registerInfo("Can't hit target perimeter with two rectangles, need to make two ends adiabatic")
2128
2236
 
2129
- 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")
2130
- 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
2131
- 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')
2132
2240
  end
2133
2241
  else # stretched bar
2134
2242
  dual_bar = false
2135
2243
 
2136
2244
  stretched_length = 0.25 * (target_perim + Math.sqrt(target_perim**2 - 16 * footprint_si))
2137
2245
  stretched_width = footprint_si / stretched_length
2138
- if (target_area - stretched_length*stretched_width).abs > tol_testing || (target_perim - (stretched_length + stretched_width)*2) > tol_testing
2139
- 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')
2140
2248
  end
2141
2249
 
2142
2250
  width = stretched_width
@@ -2172,7 +2280,7 @@ module OsLib_ModelGeneration
2172
2280
  end
2173
2281
  bars['primary'][:floor_height_si] = floor_height_si # can make use of this when breaking out multi-height spaces
2174
2282
  bars['primary'][:num_stories] = num_stories
2175
- 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)
2176
2284
  space_types_hash_secondary = {}
2177
2285
  if dual_bar
2178
2286
  # loop through each story and move portion for other bar to its own hash
@@ -2181,9 +2289,9 @@ module OsLib_ModelGeneration
2181
2289
  footprint_counter = primary_footprint
2182
2290
  secondary_footprint_counter = secondary_footprint
2183
2291
  story_counter = 0
2184
- pri_sec_tol = 0.0001 #m^2
2185
- pri_sec_min_area = 0.0001 #m^2
2186
- 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|
2187
2295
  space_type_left = v[:floor_area]
2188
2296
 
2189
2297
  # do not go to next space type until this one is evaulate, which may span stories
@@ -2191,23 +2299,23 @@ module OsLib_ModelGeneration
2191
2299
 
2192
2300
  # use secondary footprint if any left
2193
2301
  if secondary_footprint_counter > 0.0
2194
- hash_area = [space_type_left,secondary_footprint_counter].min
2302
+ hash_area = [space_type_left, secondary_footprint_counter].min
2195
2303
 
2196
2304
  # confirm that the part of space type use or what is left is greater than min allowed value
2197
2305
  projected_space_type_left = space_type_left - hash_area
2198
- test_a = if hash_area >= pri_sec_min_area then true else false end
2199
- test_b = if projected_space_type_left >= pri_sec_min_area || projected_space_type_left == 0.0 then true else false end
2200
- 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
2201
2309
  if (test_a && test_b) || test_c
2202
- if space_types_hash_secondary.has_key?(k)
2310
+ if space_types_hash_secondary.key?(k)
2203
2311
  # add to what was added for previous story
2204
2312
  space_types_hash_secondary[k][:floor_area] += hash_area
2205
2313
  else
2206
2314
  # add new space type to hash
2207
- if v.has_key?(:children)
2208
- 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] }
2209
2317
  else
2210
- 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] }
2211
2319
  end
2212
2320
  end
2213
2321
  space_types_hash[k][:floor_area] -= hash_area
@@ -2224,7 +2332,7 @@ module OsLib_ModelGeneration
2224
2332
  space_type_left = 0.0
2225
2333
  else
2226
2334
  # then look at primary bar
2227
- hash_area_pri = [space_type_left,footprint_counter].min
2335
+ hash_area_pri = [space_type_left, footprint_counter].min
2228
2336
  footprint_counter -= hash_area_pri
2229
2337
  space_type_left -= hash_area_pri
2230
2338
  end
@@ -2249,13 +2357,13 @@ module OsLib_ModelGeneration
2249
2357
  bars['primary'][:space_types_hash] = space_types_hash
2250
2358
  bars['primary'][:args] = args
2251
2359
  v = bars['primary']
2252
- 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])
2253
2361
 
2254
2362
  # store offset value for multiple bars
2255
- 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
2256
2364
  offset_val = num_stories.ceil * floor_height_si * args['bar_sep_dist_mult']
2257
- elsif args.has_key?('bar_sep_dist_mult')
2258
- 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')
2259
2367
  offset_val = num_stories.ceil * floor_height_si * 0.1
2260
2368
  else
2261
2369
  offset_val = num_stories.ceil * floor_height_si * 10.0
@@ -2291,21 +2399,21 @@ module OsLib_ModelGeneration
2291
2399
  else
2292
2400
  runner.registerInfo('Adiabatic ends added to secondary bar because target perimeter multiplier could not be met with two full rectangular footprints.')
2293
2401
  end
2294
- 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)
2295
2403
  else
2296
- 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)
2297
2405
  end
2298
2406
  bars['secondary'][:args] = args2
2299
2407
 
2300
2408
  # setup bar_hash and run create_bar
2301
2409
  v = bars['secondary']
2302
- 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])
2303
2411
 
2304
2412
  end
2305
2413
 
2306
2414
  # future development (up against primary bar run intersection and surface matching after add all bars, avoid interior windows)
2307
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
2308
- if multi_height_space_types_hash.size > 0
2416
+ if !multi_height_space_types_hash.empty?
2309
2417
  args3 = args.clone
2310
2418
  bars['custom_height'] = {}
2311
2419
  if mirror_ns_ew
@@ -2316,7 +2424,7 @@ module OsLib_ModelGeneration
2316
2424
  bars['custom_height'][:width] = width_cust_height
2317
2425
  end
2318
2426
  if args['party_wall_stories_east'] + args['party_wall_stories_west'] + args['party_wall_stories_south'] + args['party_wall_stories_north'] > 0.0
2319
- runner.registerWarning("Ignorning party wall inputs for custom height bar")
2427
+ runner.registerWarning('Ignorning party wall inputs for custom height bar')
2320
2428
  end
2321
2429
 
2322
2430
  # disable party walls
@@ -2331,14 +2439,14 @@ module OsLib_ModelGeneration
2331
2439
 
2332
2440
  bars['custom_height'][:floor_height_si] = floor_height_si # can make use of this when breaking out multi-height spaces
2333
2441
  bars['custom_height'][:num_stories] = num_stories
2334
- 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)
2335
- 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
2336
2444
  bars['custom_height'][:num_stories] = 1
2337
2445
  bars['custom_height'][:space_types_hash] = multi_height_space_types_hash
2338
2446
  bars['custom_height'][:args] = args3
2339
2447
 
2340
2448
  v = bars['custom_height']
2341
- 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])
2342
2450
  end
2343
2451
 
2344
2452
  # diagnostic log
@@ -2379,7 +2487,7 @@ module OsLib_ModelGeneration
2379
2487
  if args['party_wall_fraction'] > 0
2380
2488
  actual_ext_wall_area = model.getBuilding.exteriorWallArea
2381
2489
  actual_party_wall_area = 0.0
2382
- model.getSurfaces.each do |surface|
2490
+ model.getSurfaces.sort.each do |surface|
2383
2491
  next if surface.outsideBoundaryCondition != 'Adiabatic'
2384
2492
  next if surface.surfaceType != 'Wall'
2385
2493
  actual_party_wall_area += surface.grossArea * surface.space.get.multiplier
@@ -2390,37 +2498,37 @@ module OsLib_ModelGeneration
2390
2498
  end
2391
2499
 
2392
2500
  # check ns/ew aspect ratio (harder to check when party walls are added)
2393
- wall_and_window_by_orientation = OsLib_Geometry.getExteriorWindowAndWllAreaByOrientation(model,model.getSpaces)
2501
+ wall_and_window_by_orientation = OsLib_Geometry.getExteriorWindowAndWllAreaByOrientation(model, model.getSpaces)
2394
2502
  wall_ns = (wall_and_window_by_orientation['northWall'] + wall_and_window_by_orientation['southWall'])
2395
2503
  wall_ew = wall_and_window_by_orientation['eastWall'] + wall_and_window_by_orientation['westWall']
2396
- wall_ns_ip = OpenStudio.convert(wall_ns,'m^2','ft^2').get
2397
- wall_ew_ip = OpenStudio.convert(wall_ew,'m^2','ft^2').get
2398
- runner.registerValue('wall_area_ip',wall_ns_ip + wall_ew_ip,'ft^2')
2399
- runner.registerValue('ns_wall_area_ip',wall_ns_ip,'ft^2')
2400
- 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')
2401
2509
  # for now using perimeter of ground floor and average story area (building area / num_stories)
2402
- runner.registerValue('floor_area_to_perim_ratio',model.getBuilding.floorArea / (OsLib_Geometry.calculate_perimeter(model) * num_stories))
2403
- 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')
2404
2512
 
2405
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
2406
- 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')
2407
2515
  elsif args['num_stories_above_grade'] != args['num_stories_above_grade'].ceil
2408
- 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')
2409
2517
  elsif dual_bar_calc_approach == 'stretched'
2410
- runner.registerInfo("Target facade area by orientation not validated when single stretched bar has to be used to meet target minimum perimeter multiplier")
2411
- elsif defaulted_args.include?('floor_height') && args['custom_height_bar'] && multi_height_space_types_hash.size > 0
2412
- 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')
2413
2521
  elsif args['bar_width'] > 0
2414
- 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')
2415
2523
  else
2416
2524
 
2417
2525
  # adjust length versus width based on building rotation
2418
2526
  if mirror_ns_ew
2419
- wall_target_ns_ip = 2 * OpenStudio.convert(width,'m','ft').get * args['perim_mult'] * args['num_stories_above_grade'] * args['floor_height']
2420
- 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']
2421
2529
  else
2422
- wall_target_ns_ip = 2 * OpenStudio.convert(length,'m','ft').get * args['perim_mult'] * args['num_stories_above_grade'] * args['floor_height']
2423
- 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']
2424
2532
  end
2425
2533
  flag_error = false
2426
2534
  if (wall_target_ns_ip - wall_ns_ip).abs > 0.1
@@ -2460,7 +2568,6 @@ module OsLib_ModelGeneration
2460
2568
  # typical
2461
2569
  # used for varieties of measures that create typical building from model
2462
2570
  def typical_building_from_model(model, runner, user_arguments)
2463
-
2464
2571
  # assign the user inputs to variables
2465
2572
  args = OsLib_HelperMethods.createRunVariables(runner, model, user_arguments, arguments(model))
2466
2573
  if !args then return false end
@@ -2530,7 +2637,7 @@ module OsLib_ModelGeneration
2530
2637
  end
2531
2638
 
2532
2639
  # check that weekday start time plus duration does not exceed 24 hrs
2533
- 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
2534
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.")
2535
2642
  end
2536
2643
  end
@@ -2570,7 +2677,7 @@ module OsLib_ModelGeneration
2570
2677
  end
2571
2678
 
2572
2679
  # check that weekend start time plus duration does not exceed 24 hrs
2573
- 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
2574
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.")
2575
2682
  end
2576
2683
  end
@@ -2586,7 +2693,7 @@ module OsLib_ModelGeneration
2586
2693
  standard = Standard.build((args['template']).to_s)
2587
2694
 
2588
2695
  # validate climate zone
2589
- if !args.has_key?('climate_zone') || args['climate_zone'] == 'Lookup From Model'
2696
+ if !args.key?('climate_zone') || args['climate_zone'] == 'Lookup From Model'
2590
2697
  climate_zone = standard.model_get_building_climate_zone_and_building_type(model)['climate_zone']
2591
2698
  runner.registerInfo("Using climate zone #{climate_zone} from model")
2592
2699
  else
@@ -2613,7 +2720,7 @@ module OsLib_ModelGeneration
2613
2720
 
2614
2721
  # remove internal loads
2615
2722
  if args['remove_objects']
2616
- model.getSpaceLoads.each do |instance|
2723
+ model.getSpaceLoads.sort.each do |instance|
2617
2724
  next if instance.name.to_s.include?('Elevator') # most prototype building types model exterior elevators with name Elevator
2618
2725
  next if instance.to_InternalMass.is_initialized
2619
2726
  next if instance.to_WaterUseEquipment.is_initialized
@@ -2623,7 +2730,7 @@ module OsLib_ModelGeneration
2623
2730
  model.getDefaultScheduleSets.each(&:remove)
2624
2731
  end
2625
2732
 
2626
- model.getSpaceTypes.each do |space_type|
2733
+ model.getSpaceTypes.sort.each do |space_type|
2627
2734
  # Don't add infiltration here; will be added later in the script
2628
2735
  test = standard.space_type_apply_internal_loads(space_type, true, true, true, true, true, false)
2629
2736
  if test == false
@@ -2642,7 +2749,7 @@ module OsLib_ModelGeneration
2642
2749
 
2643
2750
  # warn if spaces in model without space type
2644
2751
  spaces_without_space_types = []
2645
- model.getSpaces.each do |space|
2752
+ model.getSpaces.sort.each do |space|
2646
2753
  next if space.spaceType.is_initialized
2647
2754
  spaces_without_space_types << space
2648
2755
  end
@@ -2653,7 +2760,7 @@ module OsLib_ModelGeneration
2653
2760
 
2654
2761
  # identify primary building type (used for construction, and ideally HVAC as well)
2655
2762
  building_types = {}
2656
- model.getSpaceTypes.each do |space_type|
2763
+ model.getSpaceTypes.sort.each do |space_type|
2657
2764
  # populate hash of building types
2658
2765
  if space_type.standardsBuildingType.is_initialized
2659
2766
  bldg_type = space_type.standardsBuildingType.get
@@ -2681,8 +2788,10 @@ module OsLib_ModelGeneration
2681
2788
  # TODO: - allow building type and space type specific constructions set selection.
2682
2789
  if ['SmallHotel', 'LargeHotel', 'MidriseApartment', 'HighriseApartment'].include?(primary_bldg_type)
2683
2790
  is_residential = 'Yes'
2791
+ occ_type = 'Residential'
2684
2792
  else
2685
2793
  is_residential = 'No'
2794
+ occ_type = 'Nonresidential'
2686
2795
  end
2687
2796
  bldg_def_const_set = standard.model_add_construction_set(model, climate_zone, lookup_building_type, nil, is_residential)
2688
2797
  if bldg_def_const_set.is_initialized
@@ -2696,8 +2805,33 @@ module OsLib_ModelGeneration
2696
2805
  return false
2697
2806
  end
2698
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
+
2699
2833
  # address any adiabatic surfaces that don't have hard assigned constructions
2700
- model.getSurfaces.each do |surface|
2834
+ model.getSurfaces.sort.each do |surface|
2701
2835
  next if surface.outsideBoundaryCondition != 'Adiabatic'
2702
2836
  next if surface.construction.is_initialized
2703
2837
  surface.setAdjacentSurface(surface)
@@ -2721,11 +2855,11 @@ module OsLib_ModelGeneration
2721
2855
  if args['add_elevators']
2722
2856
 
2723
2857
  # remove elevators as spaceLoads or exteriorLights
2724
- model.getSpaceLoads.each do |instance|
2858
+ model.getSpaceLoads.sort.each do |instance|
2725
2859
  next if !instance.name.to_s.include?('Elevator') # most prototype building types model exterior elevators with name Elevator
2726
2860
  instance.remove
2727
2861
  end
2728
- model.getExteriorLightss.each do |ext_light|
2862
+ model.getExteriorLightss.sort.each do |ext_light|
2729
2863
  next if !ext_light.name.to_s.include?('Fuel equipment') # some prototype building types model exterior elevators by this name
2730
2864
  ext_light.remove
2731
2865
  end
@@ -2737,8 +2871,9 @@ module OsLib_ModelGeneration
2737
2871
  elevator_def = elevators.electricEquipmentDefinition
2738
2872
  design_level = elevator_def.designLevel.get
2739
2873
  runner.registerInfo("Adding #{elevators.multiplier.round(1)} elevators each with power of #{OpenStudio.toNeatString(design_level, 0, true)} (W), plus lights and fans.")
2740
- elevator_def.setFractionLost(1.0)
2874
+ elevator_def.setFractionLatent(0.0)
2741
2875
  elevator_def.setFractionRadiant(0.0)
2876
+ elevator_def.setFractionLost(1.0)
2742
2877
  end
2743
2878
  end
2744
2879
 
@@ -2746,7 +2881,7 @@ module OsLib_ModelGeneration
2746
2881
  if args['add_exterior_lights']
2747
2882
 
2748
2883
  if args['remove_objects']
2749
- model.getExteriorLightss.each do |ext_light|
2884
+ model.getExteriorLightss.sort.each do |ext_light|
2750
2885
  next if ext_light.name.to_s.include?('Fuel equipment') # some prototype building types model exterior elevators by this name
2751
2886
  ext_light.remove
2752
2887
  end
@@ -2839,13 +2974,13 @@ module OsLib_ModelGeneration
2839
2974
  end
2840
2975
 
2841
2976
  # add daylight controls, need to perform a sizing run for 2010
2842
- if args['template'] == '90.1-2010'
2977
+ if args['template'] == '90.1-2010' || args['template'] == 'ComStock 90.1-2010'
2843
2978
  if standard.model_run_sizing_run(model, "#{Dir.pwd}/SRvt") == false
2844
2979
  log_messages_to_runner(runner, debug = true)
2845
2980
  return false
2846
2981
  end
2847
2982
  end
2848
- standard.model_add_daylighting_controls(model)
2983
+ standard.model_add_daylighting_controls(model)
2849
2984
  end
2850
2985
 
2851
2986
  # add refrigeration
@@ -2864,7 +2999,7 @@ module OsLib_ModelGeneration
2864
2999
  if args['add_internal_mass']
2865
3000
 
2866
3001
  if args['remove_objects']
2867
- model.getSpaceLoads.each do |instance|
3002
+ model.getSpaceLoads.sort.each do |instance|
2868
3003
  next unless instance.to_InternalMass.is_initialized
2869
3004
  instance.remove
2870
3005
  end
@@ -2887,7 +3022,7 @@ module OsLib_ModelGeneration
2887
3022
  model.getThermostatSetpointDualSetpoints.each(&:remove)
2888
3023
  end
2889
3024
 
2890
- model.getSpaceTypes.each do |space_type|
3025
+ model.getSpaceTypes.sort.each do |space_type|
2891
3026
  # create thermostat schedules
2892
3027
  # skip un-recognized space types
2893
3028
  next if standard.space_type_get_standards_data(space_type).empty?
@@ -2895,12 +3030,12 @@ module OsLib_ModelGeneration
2895
3030
  standard.space_type_apply_internal_load_schedules(space_type, false, false, false, false, false, false, true)
2896
3031
 
2897
3032
  # identify thermal thermostat and apply to zones (apply_internal_load_schedules names )
2898
- model.getThermostatSetpointDualSetpoints.each do |thermostat|
3033
+ model.getThermostatSetpointDualSetpoints.sort.each do |thermostat|
2899
3034
  next if thermostat.name.to_s != "#{space_type.name} Thermostat"
2900
3035
  next if !thermostat.coolingSetpointTemperatureSchedule.is_initialized
2901
3036
  next if !thermostat.heatingSetpointTemperatureSchedule.is_initialized
2902
3037
  runner.registerInfo("Assigning #{thermostat.name} to thermal zones with #{space_type.name} assigned.")
2903
- space_type.spaces.each do |space|
3038
+ space_type.spaces.sort.each do |space|
2904
3039
  next if !space.thermalZone.is_initialized
2905
3040
  space.thermalZone.get.setThermostatSetpointDualSetpoint(thermostat)
2906
3041
  end
@@ -2972,7 +3107,10 @@ module OsLib_ModelGeneration
2972
3107
  end
2973
3108
 
2974
3109
  # Add the primary system to the primary zones
2975
- 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
2976
3114
 
2977
3115
  # Add the secondary system to the secondary zones (if any)
2978
3116
  if !pri_sec_zone_lists['secondary'].empty?
@@ -2982,7 +3120,10 @@ module OsLib_ModelGeneration
2982
3120
  cooled_only_zones = system_zones.select { |zone| !standard.thermal_zone_heated?(zone) && standard.thermal_zone_cooled?(zone) }
2983
3121
  system_zones = heated_and_cooled_zones + cooled_only_zones
2984
3122
  end
2985
- 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
2986
3127
  end
2987
3128
  end
2988
3129
  end
@@ -2998,7 +3139,10 @@ module OsLib_ModelGeneration
2998
3139
  # Add the user specified HVAC system for each story.
2999
3140
  # Single-zone systems will get one per zone.
3000
3141
  story_groups.each do |zones|
3001
- 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
3002
3146
  end
3003
3147
  end
3004
3148
  end
@@ -3046,7 +3190,7 @@ module OsLib_ModelGeneration
3046
3190
  if args['add_hvac']
3047
3191
  # set additional properties for building
3048
3192
  props = model.getBuilding.additionalProperties
3049
- props.setFeature('hvac_system_type',"#{args['system_type']}")
3193
+ props.setFeature('hvac_system_type', (args['system_type']).to_s)
3050
3194
 
3051
3195
  case args['system_type']
3052
3196
  when 'Ideal Air Loads'
@@ -3074,6 +3218,20 @@ module OsLib_ModelGeneration
3074
3218
  end
3075
3219
  end
3076
3220
 
3221
+ # add internal mass
3222
+ if args['add_internal_mass']
3223
+
3224
+ if args['remove_objects']
3225
+ model.getSpaceLoads.sort.each do |instance|
3226
+ next unless instance.to_InternalMass.is_initialized
3227
+ instance.remove
3228
+ end
3229
+ end
3230
+
3231
+ # add internal mass to conditioned spaces; needs to happen after thermostats are applied
3232
+ standard.model_add_internal_mass(model, primary_bldg_type)
3233
+ end
3234
+
3077
3235
  # set unmet hours tolerance
3078
3236
  unmet_hrs_tol_r = args['unmet_hours_tolerance']
3079
3237
  unmet_hrs_tol_k = OpenStudio.convert(unmet_hrs_tol_r, 'R', 'K').get
@@ -3102,7 +3260,6 @@ module OsLib_ModelGeneration
3102
3260
  # wizard
3103
3261
  # used for varieties of measures that create space type and construction set wizard
3104
3262
  def wizard(model, runner, user_arguments)
3105
-
3106
3263
  # use the built-in error checking
3107
3264
  if !runner.validateUserArguments(arguments(model), user_arguments)
3108
3265
  return false
@@ -3117,8 +3274,8 @@ module OsLib_ModelGeneration
3117
3274
  set_building_defaults = runner.getBoolArgumentValue('set_building_defaults', user_arguments)
3118
3275
 
3119
3276
  # reporting initial condition of model
3120
- starting_spaceTypes = model.getSpaceTypes
3121
- starting_constructionSets = model.getDefaultConstructionSets
3277
+ starting_spaceTypes = model.getSpaceTypes.sort
3278
+ starting_constructionSets = model.getDefaultConstructionSets.sort
3122
3279
  runner.registerInitialCondition("The building started with #{starting_spaceTypes.size} space types and #{starting_constructionSets.size} construction sets.")
3123
3280
 
3124
3281
  # lookup space types for specified building type (false indicates not to use whole building type only)
@@ -3146,7 +3303,7 @@ module OsLib_ModelGeneration
3146
3303
  lookup_building_type = standard.model_get_lookup_name(building_type)
3147
3304
 
3148
3305
  # remap small medium and large office to office
3149
- if building_type.include?("Office") then building_type = "Office" end
3306
+ if building_type.include?('Office') then building_type = 'Office' end
3150
3307
 
3151
3308
  # get array of new space types
3152
3309
  space_types_new = []
@@ -3155,7 +3312,7 @@ module OsLib_ModelGeneration
3155
3312
  if create_space_types
3156
3313
 
3157
3314
  # array of starting space types
3158
- space_types_starting = model.getSpaceTypes
3315
+ space_types_starting = model.getSpaceTypes.sort
3159
3316
 
3160
3317
  # create stub space types
3161
3318
  space_type_hash.each do |space_type_name, hash|
@@ -3268,11 +3425,10 @@ module OsLib_ModelGeneration
3268
3425
  end
3269
3426
 
3270
3427
  # reporting final condition of model
3271
- finishing_spaceTypes = model.getSpaceTypes
3272
- finishing_constructionSets = model.getDefaultConstructionSets
3428
+ finishing_spaceTypes = model.getSpaceTypes.sort
3429
+ finishing_constructionSets = model.getDefaultConstructionSets.sort
3273
3430
  runner.registerFinalCondition("The building finished with #{finishing_spaceTypes.size} space types and #{finishing_constructionSets.size} construction sets.")
3274
3431
 
3275
3432
  return true
3276
3433
  end
3277
-
3278
- end
3434
+ end