-
Notifications
You must be signed in to change notification settings - Fork 27
Address energy outside of an HVAC season or during unavailable period #2151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 10 commits
8758181
aae60b1
e1c4950
0ff6650
1a40627
554afd1
2873982
e526e25
6eeaa29
3316eab
51bb6a7
897e276
a215af2
8ba115f
3a05c70
8c263cb
61a3792
c1c8046
9345759
2abcd8e
cd0d7ab
641094c
5e0541d
ecdc565
c8dd252
f1da956
b85e3c4
5147828
ba58f27
a4f9f01
13fab78
fd4513d
63dd002
439a213
76cddff
5c2f362
54238a3
2afbc95
44ea2e1
5e820e6
c585f32
5e8f794
69e7703
a6d7be1
546ddbb
9c4b80b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -456,11 +456,12 @@ def self.apply_air_source_hvac_systems(runner, model, weather, hpxml_bldg, hpxml | |
|
|
||
| add_variable_speed_power_ems_program(runner, model, air_loop_unitary, control_zone, heating_system, cooling_system, htg_supp_coil, clg_coil, htg_coil, schedules_file) | ||
|
|
||
| if is_heatpump | ||
| ems_program = apply_defrost_ems_program(model, htg_coil, control_zone.spaces[0], cooling_system, hpxml_bldg.building_construction.number_of_units) | ||
| if cooling_system.pan_heater_watts.to_f > 0 | ||
| if not cooling_system.nil? | ||
| if is_heatpump | ||
| ems_program = apply_defrost_ems_program(model, htg_coil, control_zone.spaces[0], cooling_system, hpxml_bldg.building_construction.number_of_units) | ||
| apply_pan_heater_ems_program(model, ems_program, htg_coil, control_zone.spaces[0], cooling_system, htg_ap.hp_min_temp, hvac_unavailable_periods[:htg]) | ||
| end | ||
| apply_crankcase_heater_ems_program(model, clg_coil, control_zone.spaces[0], cooling_system) | ||
| end | ||
| return air_loop | ||
| end | ||
|
|
@@ -1557,9 +1558,6 @@ def self.apply_setpoints(runner, model, weather, spaces, hpxml_bldg, hpxml_heade | |
| hvac_control.seasons_heating_end_month, hvac_control.seasons_heating_end_day) | ||
| hvac_season_days[:clg] = Calendar.get_daily_season(hpxml_header.sim_calendar_year, hvac_control.seasons_cooling_begin_month, hvac_control.seasons_cooling_begin_day, | ||
| hvac_control.seasons_cooling_end_month, hvac_control.seasons_cooling_end_day) | ||
| if hvac_season_days[:htg].include?(0) || hvac_season_days[:clg].include?(0) | ||
| runner.registerWarning('It is not possible to eliminate all HVAC energy use (e.g. crankcase/defrost energy) in EnergyPlus outside of an HVAC season.') | ||
| end | ||
|
|
||
| heating_sch = nil | ||
| cooling_sch = nil | ||
|
|
@@ -3078,7 +3076,7 @@ def self.create_dx_cooling_coil(model, obj_name, cooling_system, weather_max_dry | |
|
|
||
| clg_coil.setName(coil_name) | ||
| clg_coil.setCondenserType('AirCooled') | ||
| clg_coil.setCrankcaseHeaterCapacity(cooling_system.crankcase_heater_watts) | ||
| clg_coil.setCrankcaseHeaterCapacity(0) # We model crankcase heater via EMS. | ||
| clg_coil.additionalProperties.setFeature('HPXML_ID', cooling_system.id) # Used by reporting measure | ||
| if has_deadband_control | ||
| # Apply startup capacity degradation | ||
|
|
@@ -3246,7 +3244,7 @@ def self.create_dx_heating_coil(model, obj_name, heating_system, weather_min_dry | |
|
|
||
| # Per E+ documentation, if an air-to-air heat pump, the crankcase heater defined for the DX cooling coil is ignored and the crankcase heater power defined for the DX heating coil is used | ||
| htg_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(UnitConversions.convert(CrankcaseHeaterTemp, 'F', 'C')) | ||
| htg_coil.setCrankcaseHeaterCapacity(heating_system.crankcase_heater_watts) | ||
| htg_coil.setCrankcaseHeaterCapacity(0) # We model crankcase heater via EMS. | ||
| htg_coil.additionalProperties.setFeature('HPXML_ID', heating_system.id) # Used by reporting measure | ||
| htg_coil.additionalProperties.setFeature('FractionHeatLoadServed', heating_system.fraction_heat_load_served) # Used by reporting measure | ||
| if has_deadband_control | ||
|
|
@@ -4653,6 +4651,84 @@ def self.apply_installation_quality_ems_program(model, heating_system, cooling_s | |
| ) | ||
| end | ||
|
|
||
| # Creates an EMS program to add crankcase heater energy use for a heat pump. | ||
| # A crankcase heater ... | ||
| # | ||
| # @param model [OpenStudio::Model::Model] OpenStudio Model object | ||
| # @param clg_coil [OpenStudio::Model::CoilCoolingDXSingleSpeed or OpenStudio::Model::CoilCoolingDXMultiSpeed] OpenStudio Cooling Coil object | ||
| # @param conditioned_space [OpenStudio::Model::Space] OpenStudio Space object for conditioned zone | ||
| # @param heat_pump [HPXML::HeatPump] The HPXML heat pump of interest | ||
| # @return [nil] | ||
| def self.apply_crankcase_heater_ems_program(model, clg_coil, conditioned_space, heat_pump) | ||
| return unless heat_pump.crankcase_heater_watts.to_f > 0 | ||
|
|
||
| # Other equipment/actuator | ||
| cnt = model.getOtherEquipments.count { |e| e.endUseSubcategory.start_with? Constants::ObjectTypeCrankcaseHeater } # Ensure unique meter for each heat pump | ||
| crankcase_heater_energy_oe = Model.add_other_equipment( | ||
| model, | ||
| name: "#{clg_coil.name} crankcase heater energy", | ||
| end_use: "#{Constants::ObjectTypeCrankcaseHeater}#{cnt + 1}", | ||
| space: conditioned_space, | ||
| design_level: 0, | ||
| frac_radiant: 0, | ||
| frac_latent: 0, | ||
| frac_lost: 1, | ||
| schedule: model.alwaysOnDiscreteSchedule, | ||
| fuel_type: HPXML::FuelTypeElectricity | ||
| ) | ||
| crankcase_heater_energy_oe.additionalProperties.setFeature('HPXML_ID', heat_pump.id) # Used by reporting measure | ||
| if heat_pump.is_a? HPXML::CoolingSystem | ||
| crankcase_heater_energy_oe.additionalProperties.setFeature('FractionHeatLoadServed', 0.0) # Used by reporting measure | ||
| elsif heat_pump.is_a? HPXML::HeatPump | ||
| crankcase_heater_energy_oe.additionalProperties.setFeature('FractionHeatLoadServed', heat_pump.fraction_heat_load_served) # Used by reporting measure | ||
| end | ||
|
Comment on lines
+4751
to
+4755
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Used by the reporting measure for allocating crankcase either to heating or cooling end use. |
||
|
|
||
| crankcase_heater_energy_oe_act = Model.add_ems_actuator( | ||
| name: "#{crankcase_heater_energy_oe.name} act", | ||
| model_object: crankcase_heater_energy_oe, | ||
| comp_type_and_control: EPlus::EMSActuatorOtherEquipmentPower | ||
| ) | ||
|
|
||
| # Sensors | ||
| tout_db_sensor = Model.add_ems_sensor( | ||
| model, | ||
| name: "#{clg_coil.name} tout s", | ||
| output_var_or_meter_name: 'Site Outdoor Air Drybulb Temperature', | ||
| key_name: 'Environment' | ||
| ) | ||
|
|
||
| hvac_avail_sensor = model.getEnergyManagementSystemSensors.find { |s| s.additionalProperties.getFeatureAsString('ObjectType').to_s == Constants::ObjectTypeHVACAvailabilitySensor } | ||
|
|
||
| # EMS program | ||
| if clg_coil.is_a? OpenStudio::Model::CoilCoolingDXSingleSpeed | ||
| max_oat_crankcase = clg_coil.maximumOutdoorDryBulbTemperatureForCrankcaseHeaterOperation | ||
| elsif clg_coil.is_a? OpenStudio::Model::CoilCoolingDXMultiSpeed | ||
| max_oat_crankcase = clg_coil.maximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation | ||
| end | ||
| program = Model.add_ems_program( | ||
| model, | ||
| name: "#{clg_coil.name} crankcase program" | ||
| ) | ||
| program.addLine("Set T_out = #{tout_db_sensor.name}") | ||
| temp_criteria = "If (T_out < #{max_oat_crankcase})" | ||
|
||
| if not hvac_avail_sensor.nil? | ||
| # Don't run crankcase heater during HVAC unavailable period either | ||
| temp_criteria += " && (#{hvac_avail_sensor.name} == 1)" | ||
|
||
| end | ||
| program.addLine(temp_criteria) | ||
| program.addLine(" Set #{crankcase_heater_energy_oe_act.name} = #{heat_pump.crankcase_heater_watts}") | ||
| program.addLine('Else') | ||
| program.addLine(" Set #{crankcase_heater_energy_oe_act.name} = 0.0") | ||
| program.addLine('EndIf') | ||
|
|
||
| Model.add_ems_program_calling_manager( | ||
| model, | ||
| name: "#{program.name} calling manager", | ||
| calling_point: 'InsideHVACSystemIterationLoop', | ||
| ems_programs: [program] | ||
| ) | ||
| end | ||
|
|
||
| # Creates an EMS program to add pan heater energy use for a heat pump. | ||
| # A pan heater ensures that water melted during the defrost cycle does not refreeze into ice and | ||
| # result in fan obstruction or coil damage. | ||
|
|
@@ -4666,6 +4742,8 @@ def self.apply_installation_quality_ems_program(model, heating_system, cooling_s | |
| # @param heating_unavailable_periods [HPXML::UnavailablePeriods] Unavailable periods for heating | ||
| # @return [nil] | ||
| def self.apply_pan_heater_ems_program(model, ems_program, htg_coil, conditioned_space, heat_pump, hp_min_temp, heating_unavailable_periods) | ||
| return unless heat_pump.pan_heater_watts.to_f > 0 | ||
|
|
||
| # Other equipment/actuator | ||
| cnt = model.getOtherEquipments.count { |e| e.endUseSubcategory.start_with? Constants::ObjectTypePanHeater } # Ensure unique meter for each heat pump | ||
| pan_heater_energy_oe = Model.add_other_equipment( | ||
|
|
@@ -4717,6 +4795,7 @@ def self.apply_pan_heater_ems_program(model, ems_program, htg_coil, conditioned_ | |
| ems_program.addLine('Else') | ||
| ems_program.addLine(" Set #{pan_heater_energy_oe_act.name} = 0.0") | ||
| ems_program.addLine('EndIf') | ||
| return ems_program | ||
| end | ||
|
|
||
| # Create EMS program and Other equipment objects to account for delivered cooling load and supplemental heating energy during defrost. | ||
|
|
@@ -5011,7 +5090,6 @@ def self.apply_unit_multiplier(hpxml_bldg, hpxml_header) | |
| clg_sys.cooling_capacity *= unit_multiplier | ||
| clg_sys.cooling_design_airflow_cfm *= unit_multiplier | ||
| clg_ap.cooling_actual_airflow_cfm *= unit_multiplier | ||
| clg_sys.crankcase_heater_watts *= unit_multiplier unless clg_sys.crankcase_heater_watts.nil? | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Meters incoporate thermal zone multipliers. |
||
| clg_sys.integrated_heating_system_capacity *= unit_multiplier unless clg_sys.integrated_heating_system_capacity.nil? | ||
| clg_sys.integrated_heating_system_airflow_cfm *= unit_multiplier unless clg_sys.integrated_heating_system_airflow_cfm.nil? | ||
| clg_sys.cooling_detailed_performance_data.each do |dp| | ||
|
|
@@ -5028,7 +5106,6 @@ def self.apply_unit_multiplier(hpxml_bldg, hpxml_header) | |
| hp_ap.heating_actual_airflow_cfm *= unit_multiplier | ||
| hp_sys.heating_capacity_17F *= unit_multiplier unless hp_sys.heating_capacity_17F.nil? | ||
| hp_sys.backup_heating_capacity *= unit_multiplier unless hp_sys.backup_heating_capacity.nil? | ||
| hp_sys.crankcase_heater_watts *= unit_multiplier unless hp_sys.crankcase_heater_watts.nil? | ||
| hpxml_header.heat_pump_backup_heating_capacity_increment *= unit_multiplier unless hpxml_header.heat_pump_backup_heating_capacity_increment.nil? | ||
| hp_sys.heating_detailed_performance_data.each do |dp| | ||
| dp.capacity *= unit_multiplier unless dp.capacity.nil? | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1240,22 +1240,25 @@ def test_air_to_air_heat_pump_1_speed_onoff_thermostat | |
| _check_onoff_thermostat_EMS(model, clg_coil, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | ||
| end | ||
|
|
||
| def test_heat_pump_defrost_and_pan_heater | ||
| def test_heat_pump_defrost_and_pan_heater_and_crankcase_heater | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move the existing crankcase test into here since we're now, like defrost and pan heater, using EMS programs. |
||
| # Single Speed heat pump test | ||
| args_hash = {} | ||
| args_hash['hpxml_path'] = @tmp_hpxml_path | ||
| hpxml, hpxml_bldg = _create_hpxml('base-hvac-air-to-air-heat-pump-1-speed.xml') | ||
| hpxml_bldg.heat_pumps[0].pan_heater_watts = 60.0 | ||
| hpxml_bldg.heat_pumps[0].crankcase_heater_watts = 20.0 | ||
| XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path) | ||
| model, _hpxml, hpxml_bldg = _test_measure(args_hash) | ||
|
|
||
| # Get HPXML values | ||
| backup_fuel = EPlus.fuel_type(hpxml_bldg.heat_pumps[0].backup_heating_fuel) | ||
| pan_heater_watts = hpxml_bldg.heat_pumps[0].pan_heater_watts | ||
| crankcase_heater_watts = hpxml_bldg.heat_pumps[0].crankcase_heater_watts | ||
|
|
||
| assert_equal(1, model.getCoilHeatingDXSingleSpeeds.size) | ||
| htg_coil = model.getCoilHeatingDXSingleSpeeds[0] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 10000, 1.0, backup_fuel, 0.1, 0.0, pan_heater_watts) | ||
| clg_coil = model.getCoilCoolingDXSingleSpeeds[0] | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, clg_coil, 10000, 1.0, backup_fuel, 0.1, 0.0, pan_heater_watts, crankcase_heater_watts) | ||
|
|
||
| # Ductless heat pump test | ||
| args_hash = {} | ||
|
|
@@ -1267,7 +1270,8 @@ def test_heat_pump_defrost_and_pan_heater | |
|
|
||
| assert_equal(1, model.getCoilHeatingDXMultiSpeeds.size) | ||
| htg_coil = model.getCoilHeatingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 0.0, 0.0, backup_fuel, 0.06667, 0.0) | ||
| clg_coil = model.getCoilCoolingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, clg_coil, 0.0, 0.0, backup_fuel, 0.06667, 0.0) | ||
|
|
||
| # Ductless heat pump w/ backup heat during defrost test | ||
| args_hash = {} | ||
|
|
@@ -1279,7 +1283,8 @@ def test_heat_pump_defrost_and_pan_heater | |
|
|
||
| assert_equal(1, model.getCoilHeatingDXMultiSpeeds.size) | ||
| htg_coil = model.getCoilHeatingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 10000, 1.0, backup_fuel, 0.06667, 0.0) | ||
| clg_coil = model.getCoilCoolingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, clg_coil, 10000, 1.0, backup_fuel, 0.06667, 0.0) | ||
|
|
||
| # Dual fuel heat pump test | ||
| args_hash = {} | ||
|
|
@@ -1291,7 +1296,8 @@ def test_heat_pump_defrost_and_pan_heater | |
|
|
||
| assert_equal(1, model.getCoilHeatingDXMultiSpeeds.size) | ||
| htg_coil = model.getCoilHeatingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 10000, 0.95, backup_fuel, 0.06667, 0.0) | ||
| clg_coil = model.getCoilCoolingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, clg_coil, 10000, 0.95, backup_fuel, 0.06667, 0.0) | ||
|
|
||
| # Two heat pump test | ||
| args_hash = {} | ||
|
|
@@ -1304,10 +1310,12 @@ def test_heat_pump_defrost_and_pan_heater | |
|
|
||
| assert_equal(2, model.getCoilHeatingDXMultiSpeeds.size) | ||
| htg_coil = model.getCoilHeatingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 10000, 1.0, backup_fuel, 0.06667, 0.0, 150.0, 2) | ||
| clg_coil = model.getCoilCoolingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, clg_coil, 10000, 1.0, backup_fuel, 0.06667, 0.0, 150.0, 30.0, 2) | ||
|
|
||
| htg_coil = model.getCoilHeatingDXMultiSpeeds[1] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 10000, 1.0, backup_fuel, 0.06667, 0.0, 150.0, 2) | ||
| clg_coil = model.getCoilCoolingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, clg_coil, 10000, 1.0, backup_fuel, 0.06667, 0.0, 150.0, 30.0, 2) | ||
|
|
||
| # Separate backup heat pump test | ||
| args_hash = {} | ||
|
|
@@ -1319,7 +1327,8 @@ def test_heat_pump_defrost_and_pan_heater | |
|
|
||
| assert_equal(1, model.getCoilHeatingDXMultiSpeeds.size) | ||
| htg_coil = model.getCoilHeatingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 0.0, 0.0, backup_fuel, 0.06667, 0.0) | ||
| clg_coil = model.getCoilCoolingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, clg_coil, 0.0, 0.0, backup_fuel, 0.06667, 0.0, 150.0, 15.0) | ||
| end | ||
|
|
||
| def test_mini_split_heat_pump_ductless | ||
|
|
@@ -2157,23 +2166,6 @@ def test_custom_seasons | |
| assert_includes(end_dates, end_date) | ||
| end | ||
|
|
||
| def test_crankcase_heater_watts | ||
| args_hash = {} | ||
| args_hash['hpxml_path'] = @tmp_hpxml_path | ||
| hpxml, hpxml_bldg = _create_hpxml('base.xml') | ||
| hpxml_bldg.cooling_systems[0].crankcase_heater_watts = 40.0 | ||
| XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path) | ||
| model, _hpxml, hpxml_bldg = _test_measure(args_hash) | ||
|
|
||
| # Get HPXML values | ||
| cooling_system = hpxml_bldg.cooling_systems[0] | ||
| crankcase_heater_watts = cooling_system.crankcase_heater_watts | ||
|
|
||
| # Check cooling coil | ||
| clg_coil = model.getCoilCoolingDXSingleSpeeds[0] | ||
| assert_in_epsilon(crankcase_heater_watts, clg_coil.crankcaseHeaterCapacity, 0.01) | ||
| end | ||
|
|
||
| def test_ceiling_fan | ||
| args_hash = {} | ||
| args_hash['hpxml_path'] = File.absolute_path(File.join(@sample_files_path, 'base-lighting-ceiling-fans.xml')) | ||
|
|
@@ -2388,7 +2380,7 @@ def _check_onoff_thermostat_EMS(model, clg_or_htg_coil, c1_cap, c2_cap, c3_cap, | |
| return program_values | ||
| end | ||
|
|
||
| def _check_defrost_and_pan_heater(model, htg_coil, supp_capacity, supp_efficiency, backup_fuel, defrost_time_fraction, defrost_power, pan_heater_watts = 150.0, num_of_ems = 1) | ||
| def _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, clg_coil, supp_capacity, supp_efficiency, backup_fuel, defrost_time_fraction, defrost_power, pan_heater_watts = 150.0, crankcase_heater_watts = 30.0, num_of_ems = 1) | ||
| # Check Other equipment inputs | ||
| defrost_heat_load_oe = model.getOtherEquipments.select { |oe| oe.additionalProperties.getFeatureAsString('ObjectType').to_s == Constants::ObjectTypeHPDefrostHeatLoad } | ||
| assert_equal(num_of_ems, defrost_heat_load_oe.size) | ||
|
|
@@ -2407,13 +2399,19 @@ def _check_defrost_and_pan_heater(model, htg_coil, supp_capacity, supp_efficienc | |
| assert_in_epsilon(htg_coil.defrostTimePeriodFraction, defrost_time_fraction, 0.01) | ||
| assert_in_delta(htg_coil.resistiveDefrostHeaterCapacity.get, defrost_power, 1.0) | ||
|
|
||
| # Check EMS | ||
| # Check EMS defrost/pan heater | ||
| program_values = get_ems_values(model.getEnergyManagementSystemPrograms, "#{htg_coil.name} defrost program") | ||
| assert_in_epsilon(program_values['supp_capacity'].sum, supp_capacity, 0.01) | ||
| assert_in_epsilon(program_values['supp_efficiency'].sum, supp_efficiency, 0.01) | ||
| pan_heater_act_name = program_values.keys.find { |k| k.include? 'pan_heater_energy_act' } | ||
| assert_equal(pan_heater_watts, program_values[pan_heater_act_name][0]) | ||
| assert(!program_values.empty?) | ||
|
|
||
| # Check EMS crankcase heater | ||
| program_values = get_ems_values(model.getEnergyManagementSystemPrograms, "#{clg_coil.name} crankcase program") | ||
| crankcase_heater_act_name = program_values.keys.find { |k| k.include? 'crankcase_heater_energy_act' } | ||
| assert_equal(crankcase_heater_watts, program_values[crankcase_heater_act_name][0]) | ||
| assert(!program_values.empty?) | ||
| end | ||
|
|
||
| def _check_ghp_standard(model, heat_pump, clg_cop, htg_cop, soil_density, soil_surface_temp_amps, phase_shift_temp_amps) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the new "end use" for actuated other equipment objects.