openstudio-standards 0.2.12.rc4 → 0.2.12.rc5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/data/standards/OpenStudio_Standards-ashrae_90_1(space_types).xlsx +0 -0
  3. data/data/standards/OpenStudio_Standards-ashrae_90_1.xlsx +0 -0
  4. data/data/standards/test_performance_expected_dd_results.csv +950 -950
  5. data/lib/openstudio-standards.rb +8 -1
  6. data/lib/openstudio-standards/btap/btap.model.rb +1 -1
  7. data/lib/openstudio-standards/btap/economics.rb +14 -11
  8. data/lib/openstudio-standards/btap/envelope.rb +185 -257
  9. data/lib/openstudio-standards/btap/fileio.rb +1 -0
  10. data/lib/openstudio-standards/btap/geometry.rb +21 -1
  11. data/lib/openstudio-standards/btap/measures.rb +12 -11
  12. data/lib/openstudio-standards/btap/schedules.rb +3 -12
  13. data/lib/openstudio-standards/hvac_sizing/Siz.AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed.rb +178 -0
  14. data/lib/openstudio-standards/hvac_sizing/Siz.CoilCoolingDXMultiSpeed.rb +8 -8
  15. data/lib/openstudio-standards/hvac_sizing/Siz.Model.rb +3 -0
  16. data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +3 -3
  17. data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +25 -23
  18. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXMultiSpeed.rb +91 -0
  19. data/lib/openstudio-standards/standards/Standards.CoilDX.rb +20 -2
  20. data/lib/openstudio-standards/standards/Standards.CoilHeatingGasMultiStage.rb +39 -0
  21. data/lib/openstudio-standards/standards/Standards.Model.rb +29 -0
  22. data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +37 -4
  23. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.unitary_acs.json +15 -15
  24. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.unitary_acs.json +15 -15
  25. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.unitary_acs.json +5 -5
  26. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.unitary_acs.json +15 -15
  27. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/data/doe_ref_1980_2004.spc_typ.json +5963 -2723
  28. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/data/doe_ref_pre_1980.spc_typ.json +5917 -2697
  29. data/lib/openstudio-standards/standards/ashrae_90_1/nrel_zne_ready_2017/data/nrel_zne_ready_2017.spc_typ.json +2011 -1112
  30. data/lib/openstudio-standards/standards/ashrae_90_1/ze_aedg_multifamily/data/ze_aedg_multifamily.spc_typ.json +1946 -1106
  31. data/lib/openstudio-standards/standards/necb/BTAP1980TO2010/btap_1980to2010.rb +2 -18
  32. data/lib/openstudio-standards/standards/necb/BTAP1980TO2010/data/space_types.json +1677 -1005
  33. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/btap_pre1980.rb +64 -13
  34. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/building_envelope.rb +31 -19
  35. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/curves.json +75 -0
  36. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/heat_pumps.json +16 -16
  37. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/space_types.json +1677 -1005
  38. data/lib/openstudio-standards/standards/necb/ECMS/data/boiler_set.json +29 -0
  39. data/lib/openstudio-standards/standards/necb/ECMS/data/curves.json +913 -0
  40. data/lib/openstudio-standards/standards/necb/ECMS/data/equip_eff_lim.json +52 -0
  41. data/lib/openstudio-standards/standards/necb/ECMS/data/erv.json +105 -0
  42. data/lib/openstudio-standards/standards/necb/ECMS/data/furnace_set.json +23 -0
  43. data/lib/openstudio-standards/standards/necb/ECMS/data/heat_pumps.json +803 -0
  44. data/lib/openstudio-standards/standards/necb/ECMS/data/heat_pumps_heating.json +787 -0
  45. data/lib/openstudio-standards/standards/necb/ECMS/data/shw_set.json +29 -0
  46. data/lib/openstudio-standards/standards/necb/ECMS/ecms.rb +87 -0
  47. data/lib/openstudio-standards/standards/necb/ECMS/erv.rb +22 -0
  48. data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +1593 -0
  49. data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +68 -33
  50. data/lib/openstudio-standards/standards/necb/NECB2011/beps_compliance_path.rb +24 -13
  51. data/lib/openstudio-standards/standards/necb/NECB2011/building_envelope.rb +104 -99
  52. data/lib/openstudio-standards/standards/necb/NECB2011/data/constants.json +24 -24
  53. data/lib/openstudio-standards/standards/necb/NECB2011/data/curves.json +50 -0
  54. data/lib/openstudio-standards/standards/necb/NECB2011/data/erv.json +31 -0
  55. data/lib/openstudio-standards/standards/necb/NECB2011/data/led_lighting_data.json +2028 -0
  56. data/lib/openstudio-standards/standards/necb/NECB2011/data/space_types.json +1745 -1297
  57. data/lib/openstudio-standards/standards/necb/NECB2011/daylighting_control.md +70 -0
  58. data/lib/openstudio-standards/standards/necb/NECB2011/demand_controlled_ventilation.md +46 -0
  59. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_1_multi_speed.rb +69 -107
  60. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_1_single_speed.rb +24 -1
  61. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_multi_speed.rb +139 -141
  62. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_single_speed.rb +24 -0
  63. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +344 -234
  64. data/lib/openstudio-standards/standards/necb/NECB2011/led_lighting.md +51 -0
  65. data/lib/openstudio-standards/standards/necb/NECB2011/lighting.rb +57 -9
  66. data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +1060 -34
  67. data/lib/openstudio-standards/standards/necb/NECB2011/qaqc/necb_qaqc.rb +9 -1
  68. data/lib/openstudio-standards/standards/necb/NECB2011/service_water_heating.rb +1 -1
  69. data/lib/openstudio-standards/standards/necb/NECB2015/data/led_lighting_data.json +2883 -0
  70. data/lib/openstudio-standards/standards/necb/NECB2015/data/space_types.json +2554 -1916
  71. data/lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb +32 -1
  72. data/lib/openstudio-standards/standards/necb/NECB2017/data/led_lighting_data.json +2883 -0
  73. data/lib/openstudio-standards/standards/necb/NECB2017/data/space_types.json +2554 -1916
  74. data/lib/openstudio-standards/standards/necb/NECB2017/necb_2017.rb +29 -0
  75. data/lib/openstudio-standards/version.rb +1 -1
  76. metadata +21 -2
@@ -1,5 +1,29 @@
1
1
  class NECB2011
2
2
 
3
+ def add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating(model:,
4
+ zones:,
5
+ heating_coil_type:,
6
+ baseboard_type:,
7
+ hw_loop:,
8
+ new_auto_zoner: true,
9
+ multispeed: false)
10
+ if multispeed
11
+ add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating_multi_speed(model: model,
12
+ zones: zones,
13
+ heating_coil_type: heating_coil_type,
14
+ baseboard_type: baseboard_type,
15
+ hw_loop: hw_loop,
16
+ new_auto_zoner: new_auto_zoner)
17
+ else
18
+ add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating_single_speed(model: model,
19
+ zones: zones,
20
+ heating_coil_type: heating_coil_type,
21
+ baseboard_type: baseboard_type,
22
+ hw_loop: hw_loop,
23
+ new_auto_zoner: new_auto_zoner)
24
+ end
25
+ end
26
+
3
27
  # Some tests still require a simple way to set up a system without sizing.. so we are keeping the auto_zoner flag for this method.
4
28
  #
5
29
  def add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating_single_speed(model:,
@@ -367,6 +367,34 @@ class NECB2011
367
367
  return true
368
368
  end
369
369
 
370
+ # Sets the minimum effectiveness of the heat exchanger per
371
+ # the standard.
372
+ def heat_exchanger_air_to_air_sensible_and_latent_apply_efficiency(heat_exchanger_air_to_air_sensible_and_latent, erv_name = nil)
373
+ # Assumed to be sensible and latent at all flow
374
+ # This will now get data of the erv from the json file instead of hardcoding it. Defaults to NECB2011 erv we have been using.
375
+ erv_name = 'Rotary-Minimum-Eff-Existing' if erv_name.nil?
376
+ erv_info = @standards_data['erv'].detect { |item| item['erv_name'] == erv_name }
377
+
378
+ raise("Could not find #{erv_name} in #{self.class.name} class' erv.json file or it's parents. The available ervs are #{@standards_data['erv'].map{|item| item['erv_name']}}") if erv_info.nil?
379
+
380
+ heat_exchanger_air_to_air_sensible_and_latent.setHeatExchangerType(erv_info['HeatExchangerType'])
381
+ heat_exchanger_air_to_air_sensible_and_latent.setSensibleEffectivenessat100HeatingAirFlow(erv_info['SensibleEffectivenessat100HeatingAirFlow'])
382
+ heat_exchanger_air_to_air_sensible_and_latent.setLatentEffectivenessat100HeatingAirFlow(erv_info['LatentEffectivenessat100HeatingAirFlow'])
383
+ heat_exchanger_air_to_air_sensible_and_latent.setSensibleEffectivenessat75HeatingAirFlow(erv_info['SensibleEffectivenessat75HeatingAirFlow'])
384
+ heat_exchanger_air_to_air_sensible_and_latent.setLatentEffectivenessat75HeatingAirFlow(erv_info['LatentEffectivenessat75HeatingAirFlow'])
385
+ heat_exchanger_air_to_air_sensible_and_latent.setSensibleEffectivenessat100CoolingAirFlow(erv_info['SensibleEffectivenessat100CoolingAirFlow'])
386
+ heat_exchanger_air_to_air_sensible_and_latent.setLatentEffectivenessat100CoolingAirFlow(erv_info['LatentEffectivenessat100CoolingAirFlow'])
387
+ heat_exchanger_air_to_air_sensible_and_latent.setSensibleEffectivenessat75CoolingAirFlow(erv_info['SensibleEffectivenessat75CoolingAirFlow'])
388
+ heat_exchanger_air_to_air_sensible_and_latent.setLatentEffectivenessat75CoolingAirFlow(erv_info['LatentEffectivenessat75CoolingAirFlow'])
389
+ heat_exchanger_air_to_air_sensible_and_latent.setSupplyAirOutletTemperatureControl(erv_info['SupplyAirOutletTemperatureControl'])
390
+ heat_exchanger_air_to_air_sensible_and_latent.setFrostControlType(erv_info['FrostControlType'])
391
+ heat_exchanger_air_to_air_sensible_and_latent.setEconomizerLockout(erv_info['EconomizerLockout'])
392
+ heat_exchanger_air_to_air_sensible_and_latent.setThresholdTemperature(erv_info['ThresholdTemperature'])
393
+ heat_exchanger_air_to_air_sensible_and_latent.setInitialDefrostTimeFraction(erv_info['InitialDefrostTimeFraction'])
394
+ return true
395
+ end
396
+
397
+
370
398
  # Determine if demand control ventilation (DCV) is
371
399
  # required for this air loop.
372
400
  #
@@ -798,127 +826,118 @@ class NECB2011
798
826
  # @return [Bool] true if successful, false if not
799
827
  def coil_cooling_dx_multi_speed_apply_efficiency_and_curves(coil_cooling_dx_multi_speed, sql_db_vars_map)
800
828
  successfully_set_all_properties = true
829
+ model = coil_cooling_dx_multi_speed.model
830
+ multi_speed_heat_pump = coil_cooling_dx_multi_speed.containingHVACComponent.get.to_AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed.get
831
+ airloop = multi_speed_heat_pump.airLoopHVAC.get
801
832
 
802
- # Define the criteria to find the chiller properties
803
- # in the hvac standards data set.
804
- search_criteria = {}
805
- cooling_type = coil_cooling_dx_multi_speed.condenserType
806
- search_criteria['cooling_type'] = cooling_type
807
-
808
- # TODO: Standards - add split system vs single package to model
809
- # For now, assume single package as default
810
- sub_category = 'Single Package'
811
-
812
- # Determine the heating type if unitary or zone hvac
813
- heat_pump = false
814
- heating_type = nil
815
- containing_comp = nil
816
- if coil_cooling_dx_multi_speed.airLoopHVAC.empty?
817
- if coil_cooling_dx_multi_speed.containingHVACComponent.is_initialized
818
- containing_comp = coil_cooling_dx_multi_speed.containingHVACComponent.get
819
- if containing_comp.to_AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed.is_initialized
820
- htg_coil = containing_comp.to_AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed.get.heatingCoil
821
- if htg_coil.to_CoilHeatingDXMultiSpeed.is_initialized
822
- heat_pump = true
823
- heating_type = 'Electric Resistance or None'
824
- elsif htg_coil.to_CoilHeatingGasMultiStage.is_initialized
825
- heating_type = 'All Other'
826
- end
827
- end # TODO: Add other unitary systems
828
- elsif coil_cooling_dx_multi_speed.containingZoneHVACComponent.is_initialized
829
- containing_comp = coil_cooling_dx_multi_speed.containingZoneHVACComponent.get
830
- if containing_comp.to_ZoneHVACPackagedTerminalAirConditioner.is_initialized
831
- sub_category = 'PTAC'
832
- htg_coil = containing_comp.to_ZoneHVACPackagedTerminalAirConditioner.get.heatingCoil
833
- if htg_coil.to_CoilHeatingElectric.is_initialized
834
- heating_type = 'Electric Resistance or None'
835
- elsif htg_coil.to_CoilHeatingWater.is_initialized || htg_coil.to_CoilHeatingGas.is_initialized || htg_col.to_CoilHeatingGasMultiStage
836
- heating_type = 'All Other'
837
- end
838
- end # TODO: Add other zone hvac systems
839
- end
840
- end
833
+ # Define the criteria to find the properties in the hvac standards data set
834
+ search_criteria = coil_dx_find_search_criteria(coil_cooling_dx_multi_speed)
835
+ capacity_w = coil_cooling_dx_multi_speed_find_capacity(coil_cooling_dx_multi_speed)
841
836
 
842
- # Add the heating type to the search criteria
843
- unless heating_type.nil?
844
- search_criteria['heating_type'] = heating_type
845
- end
846
-
847
- search_criteria['subcategory'] = sub_category
848
-
849
- # Get the coil capacity
850
- capacity_w = nil
851
- clg_stages = stages
852
- if clg_stages.last.grossRatedTotalCoolingCapacity.is_initialized
853
- capacity_w = clg_stages.last.grossRatedTotalCoolingCapacity.get
854
- elsif coil_cooling_dx_multi_speed.autosizedSpeed4GrossRatedTotalCoolingCapacity.is_initialized
855
- capacity_w = coil_cooling_dx_multi_speed.autosizedSpeed4GrossRatedTotalCoolingCapacity.get
856
- else
857
- OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXMultiSpeed', "For #{coil_cooling_dx_multi_speed.name} capacity is not available, cannot apply efficiency standard.")
858
- successfully_set_all_properties = false
859
- return successfully_set_all_properties
837
+ # Find design outside air flow rate and flow fraction
838
+ controller_oa = nil
839
+ if airloop.airLoopHVACOutdoorAirSystem.is_initialized
840
+ oa_system = airloop.airLoopHVACOutdoorAirSystem.get
841
+ controller_oa = oa_system.getControllerOutdoorAir
860
842
  end
861
-
862
- # Volume flow rate
863
- flow_rate4 = nil
864
- if clg_stages.last.ratedAirFlowRate.is_initialized
865
- flow_rate4 = clg_stages.last.ratedAirFlowRate.get
866
- elsif coil_cooling_dx_multi_speed.autosizedSpeed4RatedAirFlowRate.is_initialized
867
- flow_rate4 = coil_cooling_dx_multi_speed.autosizedSpeed4RatedAirFlowRate.get
843
+ min_oa_flow_rate, oaf = 0.0,0.0
844
+ if controller_oa
845
+ min_oa_flow_rate = nil
846
+ if controller_oa.minimumOutdoorAirFlowRate.is_initialized
847
+ min_oa_flow_rate = controller_oa.minimumOutdoorAirFlowRate.get
848
+ elsif controller_oa.autosizedMinimumOutdoorAirFlowRate.is_initialized
849
+ min_oa_flow_rate = controller_oa.autosizedMinimumOutdoorAirFlowRate.get
850
+ end
851
+ if min_oa_flow_rate then oaf = min_oa_flow_rate.to_f / airloop.autosizedDesignSupplyAirFlowRate.to_f end
868
852
  end
869
853
 
870
- # Set number of stages
854
+ # Find required capacity of each stage and total number of stages based on NECB rules
855
+ # This implementation is limited to 4 stages only. The capacity of stages 1-3 is set to
856
+ # 66 kW as stipulated by NECB. The capacity of the 4th stage is then allowed to exceed 66 kW
857
+ # up to the design capacity.
871
858
  stage_cap = []
872
859
  num_stages = (capacity_w / (66.0 * 1000.0) + 0.5).round
873
- num_stages = [num_stages, 4].min
874
- if num_stages == 1
860
+ max_cap = 66.0 * 1000.0 * num_stages
861
+ final_num_stages = num_stages
862
+ case num_stages
863
+ when 1
875
864
  stage_cap[0] = capacity_w / 2.0
876
865
  stage_cap[1] = 2.0 * stage_cap[0]
877
- stage_cap[2] = stage_cap[1] + 0.1
878
- stage_cap[3] = stage_cap[2] + 0.1
866
+ final_num_stages = 2
879
867
  else
880
868
  stage_cap[0] = 66.0 * 1000.0
881
869
  stage_cap[1] = 2.0 * stage_cap[0]
882
- if num_stages == 2
883
- stage_cap[2] = stage_cap[1] + 0.1
884
- stage_cap[3] = stage_cap[2] + 0.1
885
- elsif num_stages == 3
870
+ case num_stages
871
+ when 2
872
+ when 3
886
873
  stage_cap[2] = 3.0 * stage_cap[0]
887
- stage_cap[3] = stage_cap[2] + 0.1
888
- elsif num_stages == 4
874
+ else
875
+ final_num_stages = 4
889
876
  stage_cap[2] = 3.0 * stage_cap[0]
890
- stage_cap[3] = 4.0 * stage_cap[0]
877
+ stage_cap[3] = max_cap
891
878
  end
892
879
  end
893
- # set capacities, flow rates, and sensible heat ratio for stages
894
- (0..3).each do |istage|
895
- clg_stages[istage].setGrossRatedTotalCoolingCapacity(stage_cap[istage])
896
- clg_stages[istage].setRatedAirFlowRate(flow_rate4 * stage_cap[istage] / capacity_w)
880
+
881
+ # Set final number of cooling stages and create missing stages if needed
882
+ for istage in 2..final_num_stages-1
883
+ new_clg_stage = OpenStudio::Model::CoilCoolingDXMultiSpeedStageData.new(model)
884
+ coil_cooling_dx_multi_speed.addStage(new_clg_stage)
885
+ end
886
+ multi_speed_heat_pump.setNumberofSpeedsforCooling(final_num_stages)
887
+
888
+ # Set final capacities for each of the stages. The flow rate for each of the stages
889
+ # is maintained above the outside air flow rate
890
+ coil_cooling_dx_multi_speed.stages[0].setGrossRatedTotalCoolingCapacity(stage_cap[0])
891
+ coil_cooling_dx_multi_speed.stages[1].setGrossRatedTotalCoolingCapacity(stage_cap[1])
892
+ case coil_cooling_dx_multi_speed.stages.size
893
+ when 2
894
+ if (oaf > 0.5) then multi_speed_heat_pump.setSpeed1SupplyAirFlowRateDuringCoolingOperation(min_oa_flow_rate) end
895
+ when 3
896
+ coil_cooling_dx_multi_speed.stages[2].setGrossRatedTotalCoolingCapacity(stage_cap[2])
897
+ if (oaf > 0.333) && (oaf <= 0.666)
898
+ multi_speed_heat_pump.setSpeed1SupplyAirFlowRateDuringCoolingOperation(min_oa_flow_rate)
899
+ elsif (oaf > 0.666)
900
+ multi_speed_heat_pump.setSpeed1SupplyAirFlowRateDuringCoolingOperation(min_oa_flow_rate)
901
+ multi_speed_heat_pump.setSpeed2SupplyAirFlowRateDuringCoolingOperation(min_oa_flow_rate)
902
+ end
903
+ when 4
904
+ coil_cooling_dx_multi_speed.stages[2].setGrossRatedTotalCoolingCapacity(stage_cap[2])
905
+ coil_cooling_dx_multi_speed.stages[3].setGrossRatedTotalCoolingCapacity(stage_cap[3])
906
+ if (oaf > 0.25) && (oaf <= 0.5)
907
+ multi_speed_heat_pump.setSpeed1SupplyAirFlowRateDuringCoolingOperation(min_oa_flow_rate)
908
+ elsif (oaf > 0.5) && (oaf <= 0.75)
909
+ multi_speed_heat_pump.setSpeed1SupplyAirFlowRateDuringCoolingOperation(min_oa_flow_rate)
910
+ multi_speed_heat_pump.setSpeed2SupplyAirFlowRateDuringCoolingOperation(min_oa_flow_rate)
911
+ elsif (oaf > 0.75)
912
+ multi_speed_heat_pump.setSpeed1SupplyAirFlowRateDuringCoolingOperation(min_oa_flow_rate)
913
+ multi_speed_heat_pump.setSpeed2SupplyAirFlowRateDuringCoolingOperation(min_oa_flow_rate)
914
+ multi_speed_heat_pump.setSpeed3SupplyAirFlowRateDuringCoolingOperation(min_oa_flow_rate)
915
+ end
897
916
  end
898
917
 
899
- # Convert capacity to Btu/hr
900
- capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get
901
- capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get
918
+ capacity_btu_per_hr = OpenStudio.convert(stage_cap.last, 'W', 'Btu/hr').get
919
+ capacity_kbtu_per_hr = OpenStudio.convert(stage_cap.last, 'W', 'kBtu/hr').get
902
920
 
903
921
  # Lookup efficiencies depending on whether it is a unitary AC or a heat pump
904
922
  ac_props = nil
905
- heat_pump_table = @standards_data['heat_pumps']
906
- unitary_acs_table = @standards_data['unitary_acs']
907
- ac_props = if heat_pump == true
908
- model_find_object(heat_pump_table, search_criteria, capacity_btu_per_hr, Date.today)
923
+ ac_props = if coil_dx_heat_pump?(coil_cooling_dx_multi_speed)
924
+ model_find_object(standards_data['heat_pumps'], search_criteria, capacity_btu_per_hr, Date.today)
909
925
  else
910
- model_find_object(unitary_acs_table, search_criteria, capacity_btu_per_hr, Date.today)
926
+ model_find_object(standards_data['unitary_acs'], search_criteria, capacity_btu_per_hr, Date.today)
911
927
  end
912
928
 
913
929
  # Check to make sure properties were found
914
930
  if ac_props.nil?
915
931
  OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXMultiSpeed', "For #{coil_cooling_dx_multi_speed.name}, cannot find efficiency info, cannot apply efficiency standard.")
916
932
  successfully_set_all_properties = false
917
- return successfully_set_all_properties
933
+ return sql_db_vars_map
918
934
  end
919
935
 
936
+ # get clg stages
937
+ clg_stages = coil_cooling_dx_multi_speed.stages
938
+
920
939
  # Make the COOL-CAP-FT curve
921
- cool_cap_ft = model_add_curve(model, ac_props['cool_cap_ft'], standards)
940
+ cool_cap_ft = model_add_curve(model, ac_props['cool_cap_ft'])
922
941
  if cool_cap_ft
923
942
  clg_stages.each do |stage|
924
943
  stage.setTotalCoolingCapacityFunctionofTemperatureCurve(cool_cap_ft)
@@ -926,10 +945,11 @@ class NECB2011
926
945
  else
927
946
  OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXMultiSpeed', "For #{coil_cooling_dx_multi_speed.name}, cannot find cool_cap_ft curve, will not be set.")
928
947
  successfully_set_all_properties = false
948
+ return sql_db_vars_map
929
949
  end
930
950
 
931
951
  # Make the COOL-CAP-FFLOW curve
932
- cool_cap_fflow = model_add_curve(model, ac_props['cool_cap_fflow'], standards)
952
+ cool_cap_fflow = model_add_curve(model, ac_props['cool_cap_fflow'])
933
953
  if cool_cap_fflow
934
954
  clg_stages.each do |stage|
935
955
  stage.setTotalCoolingCapacityFunctionofFlowFractionCurve(cool_cap_fflow)
@@ -937,10 +957,11 @@ class NECB2011
937
957
  else
938
958
  OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXMultiSpeed', "For #{coil_cooling_dx_multi_speed.name}, cannot find cool_cap_fflow curve, will not be set.")
939
959
  successfully_set_all_properties = false
960
+ return sql_db_vars_map
940
961
  end
941
962
 
942
963
  # Make the COOL-EIR-FT curve
943
- cool_eir_ft = model_add_curve(model, ac_props['cool_eir_ft'], standards)
964
+ cool_eir_ft = model_add_curve(model, ac_props['cool_eir_ft'])
944
965
  if cool_eir_ft
945
966
  clg_stages.each do |stage|
946
967
  stage.setEnergyInputRatioFunctionofTemperatureCurve(cool_eir_ft)
@@ -948,10 +969,11 @@ class NECB2011
948
969
  else
949
970
  OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXMultiSpeed', "For #{coil_cooling_dx_multi_speed.name}, cannot find cool_eir_ft curve, will not be set.")
950
971
  successfully_set_all_properties = false
972
+ return sql_db_vars_map
951
973
  end
952
974
 
953
975
  # Make the COOL-EIR-FFLOW curve
954
- cool_eir_fflow = model_add_curve(model, ac_props['cool_eir_fflow'], standards)
976
+ cool_eir_fflow = model_add_curve(model, ac_props['cool_eir_fflow'])
955
977
  if cool_eir_fflow
956
978
  clg_stages.each do |stage|
957
979
  stage.setEnergyInputRatioFunctionofFlowFractionCurve(cool_eir_fflow)
@@ -959,10 +981,11 @@ class NECB2011
959
981
  else
960
982
  OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXMultiSpeed', "For #{coil_cooling_dx_multi_speed.name}, cannot find cool_eir_fflow curve, will not be set.")
961
983
  successfully_set_all_properties = false
984
+ return sql_db_vars_map
962
985
  end
963
986
 
964
987
  # Make the COOL-PLF-FPLR curve
965
- cool_plf_fplr = model_add_curve(model, ac_props['cool_plf_fplr'], standards)
988
+ cool_plf_fplr = model_add_curve(model, ac_props['cool_plf_fplr'])
966
989
  if cool_plf_fplr
967
990
  clg_stages.each do |stage|
968
991
  stage.setPartLoadFractionCorrelationCurve(cool_plf_fplr)
@@ -970,128 +993,259 @@ class NECB2011
970
993
  else
971
994
  OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXMultiSpeed', "For #{coil_cooling_dx_multi_speed.name}, cannot find cool_plf_fplr curve, will not be set.")
972
995
  successfully_set_all_properties = false
996
+ return sql_db_vars_map
973
997
  end
974
998
 
975
- # Get the minimum efficiency standards
976
- cop = nil
977
-
978
- if coil_dx_subcategory(coil_cooling_dx_multi_speed) == 'PTAC'
979
- ptac_eer_coeff_1 = ac_props['ptac_eer_coefficient_1']
980
- ptac_eer_coeff_2 = ac_props['ptac_eer_coefficient_2']
981
- capacity_btu_per_hr = 7000 if capacity_btu_per_hr < 7000
982
- capacity_btu_per_hr = 15_000 if capacity_btu_per_hr > 15_000
983
- ptac_eer = ptac_eer_coeff_1 + (ptac_eer_coeff_2 * capacity_btu_per_hr)
984
- cop = eer_to_cop(ptac_eer)
985
- # self.setName("#{self.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{ptac_eer}EER")
986
- new_comp_name = "#{coil_cooling_dx_multi_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{ptac_eer}EER"
987
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilCoolingDXMultiSpeed', "For #{template}: #{coil_cooling_dx_multi_speed.name}: #{cooling_type} #{heating_type} #{subcategory} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{ptac_eer}")
988
- end
989
-
990
- # If specified as SEER
991
- unless ac_props['minimum_seasonal_energy_efficiency_ratio'].nil?
992
- min_seer = ac_props['minimum_seasonal_energy_efficiency_ratio']
993
- cop = seer_to_cop(min_seer)
994
- new_comp_name = "#{coil_cooling_dx_multi_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_seer}SEER"
995
- # self.setName("#{self.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_seer}SEER")
996
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilCoolingDXMultiSpeed', "For #{template}: #{coil_cooling_dx_multi_speed.name}: #{cooling_type} #{heating_type} #{subcategory} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; SEER = #{min_seer}")
997
- end
998
-
999
- # If specified as EER
1000
- unless ac_props['minimum_energy_efficiency_ratio'].nil?
1001
- min_eer = ac_props['minimum_energy_efficiency_ratio']
1002
- cop = eer_to_cop(min_eer)
1003
- new_comp_name = "#{coil_cooling_dx_multi_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_eer}EER"
1004
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilCoolingDXMultiSpeed', "For #{template}: #{coil_cooling_dx_multi_speed.name}: #{cooling_type} #{heating_type} #{subcategory} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{min_eer}")
1005
- end
1006
-
1007
- # if specified as SEER (heat pump)
1008
- unless ac_props['minimum_seasonal_efficiency'].nil?
1009
- min_seer = ac_props['minimum_seasonal_efficiency']
1010
- cop = seer_to_cop(min_seer)
1011
- new_comp_name = "#{coil_cooling_dx_multi_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_seer}SEER"
1012
- # self.setName("#{self.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_seer}SEER")
1013
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilCoolingDXMultiSpeed', "For #{template}: #{coil_cooling_dx_multi_speed.name}: #{cooling_type} #{heating_type} #{subcategory} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; SEER = #{min_seer}")
1014
- end
1015
-
1016
- # If specified as EER (heat pump)
1017
- unless ac_props['minimum_full_load_efficiency'].nil?
1018
- min_eer = ac_props['minimum_full_load_efficiency']
1019
- cop = eer_to_cop(min_eer)
1020
- new_comp_name = "#{coil_cooling_dx_multi_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_eer}EER"
1021
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilCoolingDXMultiSpeed', "For #{template}: #{coil_cooling_dx_multi_speed.name}: #{cooling_type} #{heating_type} #{subcategory} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{min_eer}")
1022
- end
1023
-
1024
- sql_db_vars_map[new_comp_name] = name.to_s
1025
- coil_cooling_dx_multi_speed.setName(new_comp_name)
1026
-
1027
- # Set the efficiency values
1028
-
999
+ # Set the COP values
1000
+ cop, new_comp_name = coil_cooling_dx_multi_speed_standard_minimum_cop(coil_cooling_dx_multi_speed)
1029
1001
  unless cop.nil?
1030
1002
  clg_stages.each do |istage|
1031
1003
  istage.setGrossRatedCoolingCOP(cop)
1032
1004
  end
1033
1005
  end
1006
+ sql_db_vars_map[new_comp_name] = coil_cooling_dx_multi_speed.name.to_s
1007
+ coil_cooling_dx_multi_speed.setName(new_comp_name)
1008
+
1009
+ # It was found that the heat pump OS object doesn't respond to the call to turn on from the
1010
+ # system availability manager night cycle. This EMS script is then implemented to check the status
1011
+ # of the system availability manager night cycle and force the heat pump to turn on when needed. The
1012
+ # heat pump is still turned on when its availability schedule calls for it.
1013
+ create_ems_to_turn_on_AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed_for_night_cycle(multi_speed_heat_pump)
1034
1014
 
1035
1015
  return sql_db_vars_map
1016
+
1017
+ end
1018
+
1019
+ # Create EMS to turn on "AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed" in response to a call
1020
+ # from the night cycle availability manager of the air loop. It was found that this object
1021
+ # doesn't respond properly to this call from the night cycle
1022
+ def create_ems_to_turn_on_AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed_for_night_cycle(multi_speed_heat_pump)
1023
+ model = multi_speed_heat_pump.model
1024
+ avail_manager_name = nil
1025
+ if multi_speed_heat_pump.airLoopHVAC.is_initialized
1026
+ if not multi_speed_heat_pump.airLoopHVAC.get.availabilityManagers.empty?
1027
+ avail_manager_name = multi_speed_heat_pump.airLoopHVAC.get.availabilityManagers[0].name.to_s
1028
+ end
1029
+ end
1030
+ if avail_manager_name
1031
+ avail_manager_out_var_name = "Availability Manager Night Cycle Control Status"
1032
+ avail_manager_out_var = OpenStudio::Model::OutputVariable.new(avail_manager_out_var_name, model)
1033
+ avail_manager_out_var.setKeyValue(avail_manager_name)
1034
+ avail_manager_out_var.setReportingFrequency("Timestep")
1035
+ night_cycle_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, avail_manager_out_var)
1036
+ heat_pump_avail_sch = nil
1037
+ if multi_speed_heat_pump.availabilitySchedule.is_initialized
1038
+ heat_pump_avail_sch = multi_speed_heat_pump.availabilitySchedule.get
1039
+ elsif multi_speed_heat_pump.airLoopHVAC.get.availabilitySchedule.is_initialized
1040
+ heat_pump_avail_sch = multi_speed_heat_pump.airLoopHVAC.get.availabilitySchedule.get
1041
+ else
1042
+ heat_pump_avail_sch = OpenStudio::Model::ScheduleConstant.new(model)
1043
+ heat_pump_avail_sch.setValue(1.0)
1044
+ end
1045
+ heat_pump_avail_sch_var = OpenStudio::Model::OutputVariable.new("Schedule Value", model)
1046
+ heat_pump_avail_sch_var.setKeyValue(heat_pump_avail_sch.name.to_s)
1047
+ heat_pump_avail_sch_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, heat_pump_avail_sch_var)
1048
+ updated_heat_pump_avail_sch = OpenStudio::Model::ScheduleConstant.new(model)
1049
+ multi_speed_heat_pump.setAvailabilitySchedule(updated_heat_pump_avail_sch)
1050
+ heat_pump_avail_sch_actuator = OpenStudio::Model::EnergyManagementSystemActuator.new(updated_heat_pump_avail_sch, "Schedule:Constant", "Schedule Value")
1051
+ heat_pump_avail_sch_prog = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
1052
+ heat_pump_avail_sch_prog.setName("#{multi_speed_heat_pump.name.to_s.gsub(/[ +-.]/,'_')} Availability Schedule Program by Line")
1053
+ heat_pump_avail_sch_prog_body = <<-EMS
1054
+ IF #{heat_pump_avail_sch_sensor.handle} > 0.0
1055
+ SET #{heat_pump_avail_sch_actuator.handle} = #{heat_pump_avail_sch_sensor.handle}
1056
+ ELSEIF #{night_cycle_sensor.handle} == 2.0
1057
+ SET #{heat_pump_avail_sch_actuator.handle} = 1.0
1058
+ ELSE
1059
+ SET #{heat_pump_avail_sch_actuator.handle} = 0.0
1060
+ ENDIF
1061
+ EMS
1062
+ heat_pump_avail_sch_prog.setBody(heat_pump_avail_sch_prog_body)
1063
+ pcm = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
1064
+ pcm.setName("#{heat_pump_avail_sch_prog.name.to_s.gsub(/[ +-.]/,'_')} Calling Manager")
1065
+ pcm.setCallingPoint('InsideHVACSystemIterationLoop')
1066
+ pcm.addProgram(heat_pump_avail_sch_prog)
1067
+ end
1036
1068
  end
1037
1069
 
1038
1070
  # Applies the standard efficiency ratings and typical performance curves to this object.
1039
1071
  #
1040
1072
  # @return [Bool] true if successful, false if not
1041
- def coil_heating_gas_multi_stage_apply_efficiency_and_curves(coil_heating_gas_multi_stage, standards)
1073
+ def coil_heating_gas_multi_stage_apply_efficiency_and_curves(coil_heating_gas_multi_stage)
1042
1074
  successfully_set_all_properties = true
1075
+ model = coil_heating_gas_multi_stage.model
1076
+
1077
+ # get multi speed heat pump and air loop
1078
+ multi_speed_heat_pump = nil
1079
+ multi_speed_heat_pumps = model.getAirLoopHVACUnitaryHeatPumpAirToAirMultiSpeeds
1080
+ multi_speed_heat_pumps.each do |iheat_pump|
1081
+ htg_coil = iheat_pump.heatingCoil
1082
+ if htg_coil.name.to_s.strip == coil_heating_gas_multi_stage.name.to_s.strip
1083
+ multi_speed_heat_pump = iheat_pump
1084
+ break
1085
+ end
1086
+ end
1087
+ airloop = multi_speed_heat_pump.airLoopHVAC.get
1043
1088
 
1044
- # Get the coil capacity
1045
- capacity_w = nil
1046
- htg_stages = stages
1047
- if htg_stages.last.nominalCapacity.is_initialized
1048
- capacity_w = htg_stages.last.nominalCapacity.get
1049
- elsif coil_heating_gas_multi_stage.autosizedStage4NominalCapacity.is_initialized
1050
- capacity_w = coil_heating_gas_multi_stage.autosizedStage4NominalCapacity.get
1051
- else
1052
- OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXMultiSpeed', "For #{coil_heating_gas_multi_stage.name} capacity is not available, cannot apply efficiency standard.")
1053
- successfully_set_all_properties = false
1054
- return successfully_set_all_properties
1089
+ # Define the criteria to find the properties in the hvac standards data set.
1090
+ search_criteria = coil_heating_gas_multi_stage_find_search_criteria(coil_heating_gas_multi_stage)
1091
+ fuel_type = search_criteria["fuel_type"]
1092
+ capacity_w = coil_heating_gas_multi_stage_find_capacity(coil_heating_gas_multi_stage)
1093
+
1094
+ # Find system design outside air flow rate and fraction
1095
+ controller_oa = nil
1096
+ if airloop.airLoopHVACOutdoorAirSystem.is_initialized
1097
+ oa_system = airloop.airLoopHVACOutdoorAirSystem.get
1098
+ controller_oa = oa_system.getControllerOutdoorAir
1099
+ end
1100
+ min_oa_flow_rate, oaf = 0.0,0.0
1101
+ if controller_oa
1102
+ min_oa_flow_rate = nil
1103
+ if controller_oa.minimumOutdoorAirFlowRate.is_initialized
1104
+ min_oa_flow_rate = controller_oa.minimumOutdoorAirFlowRate.get
1105
+ elsif controller_oa.autosizedMinimumOutdoorAirFlowRate.is_initialized
1106
+ min_oa_flow_rate = controller_oa.autosizedMinimumOutdoorAirFlowRate.get
1107
+ end
1108
+ if min_oa_flow_rate then oaf = min_oa_flow_rate.to_f / airloop.autosizedDesignSupplyAirFlowRate.to_f end
1055
1109
  end
1056
1110
 
1057
- # Set number of stages
1111
+ # Find capacities of each of the stages and the total number of stages required based on NECB rules.
1112
+ # This implementation is limited to 4 stages. The capacity of stages 1-3 is set to 66 kW as stipulated
1113
+ # by NECB. The capacity of the 4th stage can exceed 66 kW up to the design capacity.
1114
+ htg_stages = coil_heating_gas_multi_stage.stages
1058
1115
  num_stages = (capacity_w / (66.0 * 1000.0) + 0.5).round
1059
- num_stages = [num_stages, 4].min
1116
+ max_cap = 66.0 * 1000.0 * num_stages
1060
1117
  stage_cap = []
1061
- if num_stages == 1
1062
- stage_cap[0] = capacity_w / 2.0
1063
- stage_cap[1] = 2.0 * stage_cap[0]
1064
- stage_cap[2] = stage_cap[1] + 0.1
1065
- stage_cap[3] = stage_cap[2] + 0.1
1118
+ final_num_stages = num_stages
1119
+ if capacity_w == 0.001
1120
+ final_num_stages = 1
1121
+ stage_cap[0] = capacity_w
1066
1122
  else
1067
- stage_cap[0] = 66.0 * 1000.0
1068
- stage_cap[1] = 2.0 * stage_cap[0]
1069
- if num_stages == 2
1070
- stage_cap[2] = stage_cap[1] + 0.1
1071
- stage_cap[3] = stage_cap[2] + 0.1
1072
- elsif num_stages == 3
1073
- stage_cap[2] = 3.0 * stage_cap[0]
1074
- stage_cap[3] = stage_cap[2] + 0.1
1075
- elsif num_stages == 4
1076
- stage_cap[2] = 3.0 * stage_cap[0]
1077
- stage_cap[3] = 4.0 * stage_cap[0]
1123
+ case num_stages
1124
+ when 1
1125
+ stage_cap[0] = capacity_w / 2.0
1126
+ stage_cap[1] = 2.0 * stage_cap[0]
1127
+ final_num_stages = 2
1128
+ else
1129
+ stage_cap[0] = 66.0 * 1000.0
1130
+ stage_cap[1] = 2.0 * stage_cap[0]
1131
+ case num_stages
1132
+ when 2
1133
+ when 3
1134
+ stage_cap[2] = 3.0 * stage_cap[0]
1135
+ else
1136
+ final_num_stages = 4
1137
+ stage_cap[2] = 3.0 * stage_cap[0]
1138
+ stage_cap[3] = max_cap
1139
+ end
1078
1140
  end
1079
1141
  end
1080
- # set capacities, flow rates, and sensible heat ratio for stages
1081
- (0..3).each do |istage|
1082
- htg_stages[istage].setNominalCapacity(stage_cap[istage])
1142
+
1143
+ # Set final number of stages and create missing stages if needed
1144
+ for istage in 1..final_num_stages-1
1145
+ new_htg_stage = OpenStudio::Model::CoilHeatingGasMultiStageStageData.new(model)
1146
+ coil_heating_gas_multi_stage.addStage(new_htg_stage)
1147
+ end
1148
+ multi_speed_heat_pump.setNumberofSpeedsforHeating(final_num_stages)
1149
+
1150
+ # Set final capacities for each of the stages. The air flow rate for each of the stages
1151
+ # is maintained above the outside air flow rate
1152
+ coil_heating_gas_multi_stage.stages[0].setNominalCapacity(stage_cap[0])
1153
+ case coil_heating_gas_multi_stage.stages.size
1154
+ when 2
1155
+ coil_heating_gas_multi_stage.stages[1].setNominalCapacity(stage_cap[1])
1156
+ if (oaf > 0.5) then multi_speed_heat_pump.setSpeed1SupplyAirFlowRateDuringHeatingOperation(min_oa_flow_rate) end
1157
+ when 3
1158
+ coil_heating_gas_multi_stage.stages[1].setNominalCapacity(stage_cap[1])
1159
+ coil_heating_gas_multi_stage.stages[2].setNominalCapacity(stage_cap[2])
1160
+ if (oaf > 0.333) && (oaf <= 0.666)
1161
+ multi_speed_heat_pump.setSpeed1SupplyAirFlowRateDuringHeatingOperation(min_oa_flow_rate)
1162
+ elsif (oaf > 0.666)
1163
+ multi_speed_heat_pump.setSpeed1SupplyAirFlowRateDuringHeatingOperation(min_oa_flow_rate)
1164
+ multi_speed_heat_pump.setSpeed2SupplyAirFlowRateDuringHeatingOperation(min_oa_flow_rate)
1165
+ end
1166
+ when 4
1167
+ coil_heating_gas_multi_stage.stages[1].setNominalCapacity(stage_cap[1])
1168
+ coil_heating_gas_multi_stage.stages[2].setNominalCapacity(stage_cap[2])
1169
+ coil_heating_gas_multi_stage.stages[3].setNominalCapacity(stage_cap[3])
1170
+ if (oaf > 0.25) && (oaf <= 0.5)
1171
+ multi_speed_heat_pump.setSpeed1SupplyAirFlowRateDuringHeatingOperation(min_oa_flow_rate)
1172
+ elsif (oaf > 0.5) && (oaf <= 0.75)
1173
+ multi_speed_heat_pump.setSpeed1SupplyAirFlowRateDuringHeatingOperation(min_oa_flow_rate)
1174
+ multi_speed_heat_pump.setSpeed2SupplyAirFlowRateDuringHeatingOperation(min_oa_flow_rate)
1175
+ elsif (oaf > 0.75)
1176
+ multi_speed_heat_pump.setSpeed1SupplyAirFlowRateDuringHeatingOperation(min_oa_flow_rate)
1177
+ multi_speed_heat_pump.setSpeed2SupplyAirFlowRateDuringHeatingOperation(min_oa_flow_rate)
1178
+ multi_speed_heat_pump.setSpeed3SupplyAirFlowRateDuringHeatingOperation(min_oa_flow_rate)
1179
+ end
1180
+ end
1181
+
1182
+ # Convert capacity to Btu/hr
1183
+ capacity_btu_per_hr = OpenStudio.convert(stage_cap.last, 'W', 'Btu/hr').get
1184
+ capacity_kbtu_per_hr = OpenStudio.convert(stage_cap.last, 'W', 'kBtu/hr').get
1185
+
1186
+ # Lookup efficiencies
1187
+ heater_props = nil
1188
+ heater_props = model_find_object(standards_data['furnaces'], search_criteria, capacity_btu_per_hr, Date.today)
1189
+
1190
+ # Check to make sure properties were found
1191
+ if heater_props.nil?
1192
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingGasMultiSpeed', "For #{coil_heating_gas_multi_stage.name}, cannot find efficiency info, cannot apply efficiency standard.")
1193
+ successfully_set_all_properties = false
1194
+ return successfully_set_all_properties
1083
1195
  end
1084
- # PLF vs PLR curve
1085
- furnace_plffplr_curve_name = 'FURNACE-EFFPLR-NECB2011'
1086
1196
 
1087
- # plf vs plr curve for furnace
1088
- furnace_plffplr_curve = model_add_curve(coil_heating_gas_multi_stage.model, furnace_plffplr_curve_name, standards)
1089
- if furnace_plffplr_curve
1090
- coil_heating_gas_multi_stage.setPartLoadFractionCorrelationCurve(furnace_plffplr_curve)
1197
+ # Make the EFFPLR curve
1198
+ efffplr = model_add_curve(coil_heating_gas_multi_stage.model, heater_props['efffplr'])
1199
+ if efffplr
1200
+ coil_heating_gas_multi_stage.setPartLoadFractionCorrelationCurve(efffplr)
1091
1201
  else
1092
- OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingGasMultiStage', "For #{coil_heating_gas_multi_stage.name}, cannot find plffplr curve, will not be set.")
1202
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingGasMultiStage', "For #{coil_heating_gas_multi_stage.name}, cannot find efffplr curve, will not be set.")
1093
1203
  successfully_set_all_properties = false
1204
+ return successfully_set_all_properties
1094
1205
  end
1206
+
1207
+ # Get the minimum efficiency standards
1208
+ thermal_eff = nil
1209
+
1210
+ # If specified as AFUE
1211
+ unless heater_props['minimum_annual_fuel_utilization_efficiency'].nil?
1212
+ min_afue = heater_props['minimum_annual_fuel_utilization_efficiency']
1213
+ thermal_eff = afue_to_thermal_eff(min_afue)
1214
+ new_comp_name = "#{coil_heating_gas_multi_stage.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_afue} AFUE"
1215
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilHeatingGasMultiStage', "For #{template}: #{coil_heating_gas_multi_stage.name}: #{fuel_type} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; AFUE = #{min_afue}")
1216
+ end
1217
+
1218
+ # If specified as thermal efficiency
1219
+ unless heater_props['minimum_thermal_efficiency'].nil?
1220
+ thermal_eff = heater_props['minimum_thermal_efficiency']
1221
+ new_comp_name = "#{coil_heating_gas_multi_stage.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{thermal_eff} Thermal Eff"
1222
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilHeatingGasMultiStage', "For #{template}: #{coil_heating_gas_multi_stage.name}: #{fuel_type} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; Thermal Efficiency = #{thermal_eff}")
1223
+ end
1224
+
1225
+ # If specified as combustion efficiency
1226
+ unless heater_props['minimum_combustion_efficiency'].nil?
1227
+ min_comb_eff = heater_props['minimum_combustion_efficiency']
1228
+ thermal_eff = combustion_eff_to_thermal_eff(min_comb_eff)
1229
+ new_comp_name = "#{coil_heating_gas_multi_stage.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_comb_eff} Combustion Eff"
1230
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.BoilerHotWater', "For #{template}: #{coil_heating_gas_multi_stage.name}: #{fuel_type} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; Combustion Efficiency = #{min_comb_eff}")
1231
+ end
1232
+ coil_heating_gas_multi_stage.setName(new_comp_name)
1233
+
1234
+ # Set the name
1235
+ coil_heating_gas_multi_stage.setName(new_comp_name)
1236
+
1237
+ # Get heating stages
1238
+ htg_stages = coil_heating_gas_multi_stage.stages
1239
+
1240
+ # Set the efficiency values
1241
+ unless thermal_eff.nil?
1242
+ htg_stages.each do |stage|
1243
+ stage.setGasBurnerEfficiency(thermal_eff)
1244
+ end
1245
+ end
1246
+
1247
+ return successfully_set_all_properties
1248
+
1095
1249
  end
1096
1250
 
1097
1251
  # Determines the baseline fan impeller efficiency
@@ -1139,7 +1293,7 @@ class NECB2011
1139
1293
  # Assuming all fan motors are 4-pole ODP
1140
1294
  motor_use = 'FAN'
1141
1295
  motor_type = ''
1142
- if fan.class.name == 'OpenStudio::Model::FanConstantVolume'
1296
+ if (fan.class.name == 'OpenStudio::Model::FanConstantVolume') || (fan.class.name == 'OpenStudio::Model::FanOnOff')
1143
1297
  motor_type = 'CONSTANT'
1144
1298
  elsif fan.class.name == 'OpenStudio::Model::FanVariableVolume'
1145
1299
  # Is this a return or supply fan
@@ -1560,51 +1714,7 @@ class NECB2011
1560
1714
 
1561
1715
  return clg_tower
1562
1716
  end
1563
-
1564
-
1565
- # Creates thermal zones to contain each space, as defined for each building in the
1566
- # system_to_space_map inside the Prototype.building_name
1567
- # e.g. (Prototype.secondary_school.rb) file.
1568
- #
1569
- # @param (see #add_constructions)
1570
- # @return [Bool] returns true if successful, false if not
1571
- def model_create_thermal_zones(model,
1572
- space_multiplier_map = nil)
1573
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started creating thermal zones')
1574
- space_multiplier_map = {} if space_multiplier_map.nil?
1575
-
1576
- # Remove any Thermal zones assigned
1577
- model.getThermalZones.each(&:remove)
1578
-
1579
- # Create a thermal zone for each space in the self
1580
- model.getSpaces.sort.each do |space|
1581
- zone = OpenStudio::Model::ThermalZone.new(model)
1582
- zone.setName("#{space.name} ZN")
1583
- unless space_multiplier_map[space.name.to_s].nil? || (space_multiplier_map[space.name.to_s] == 1)
1584
- zone.setMultiplier(space_multiplier_map[space.name.to_s])
1585
- end
1586
- space.setThermalZone(zone)
1587
-
1588
- # Skip thermostat for spaces with no space type
1589
- next if space.spaceType.empty?
1590
-
1591
- # Add a thermostat
1592
- space_type_name = space.spaceType.get.name.get
1593
- thermostat_name = space_type_name + ' Thermostat'
1594
- thermostat = model.getThermostatSetpointDualSetpointByName(thermostat_name)
1595
- if thermostat.empty?
1596
- OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "Thermostat #{thermostat_name} not found for space name: #{space.name}")
1597
- else
1598
- thermostat_clone = thermostat.get.clone(model).to_ThermostatSetpointDualSetpoint.get
1599
- zone.setThermostatSetpointDualSetpoint(thermostat_clone)
1600
- # Set Ideal loads to thermal zone for sizing for NECB needs. We need this for sizing.
1601
- ideal_loads = OpenStudio::Model::ZoneHVACIdealLoadsAirSystem.new(model)
1602
- ideal_loads.addToThermalZone(zone)
1603
- end
1604
- end
1605
-
1606
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished creating thermal zones')
1607
- end
1717
+
1608
1718
 
1609
1719
  # This method cycles through the spaces in a thermal zone and then sorts them by story. The method then cycles
1610
1720
  # through the spaces on a story and then calculates the centroid of the spaces in the thermal zone on that floor. The