Repository: NREL/OpenStudio (language: python)

Issue:
CoilHeatingDXMultiSpeed .containingHVACComponent
Issue overview
--------------
The AirLoopHVACUnitarySystem object can accept a CoilHeatingDXMultiSpeed object, but the .containingHVACComponent method does not return the AirLoopHVACUnitarySystem for CoilHeatingDXMultiSpeed objects

## Current Behavior
.containingHVACComponent returns nil

## Expected Behavior
.containingHVACComponent returns the AirLoopHVACUnitarySystem object

## Steps to Reproduce
Example model on NREL's sharepoint: 
https://nrel.sharepoint.com/:u:/s/NRELBuildings/EZ9GOFR2Wy9NhVomACRrwUYBGrPwjs8h2p-7-hAmZkcZ9A?e=4M3KIo
_(let me know if I should upload it elsewhere)_
```
require 'openstudio'

osm_path = File.dirname(__FILE__) + '/multispeed_hps.osm'
translator = OpenStudio::OSVersion::VersionTranslator.new
model = translator.loadModel(osm_path).get

model.getAirLoopHVACUnitarySystems.each do |sys|
  puts sys
end

puts "################################################3"

model.getCoilHeatingDXMultiSpeeds.each do |coil|
  puts coil
  airloop = coil.airLoopHVAC.is_initialized
  hvac_comp = coil.containingHVACComponent.is_initialized
  zone_hvac_comp = coil.containingZoneHVACComponent.is_initialized
  puts ''
  puts "airloop? #{airloop}"
  puts "hvac_comp? #{hvac_comp}"
  puts "zone_hvac_comp? #{zone_hvac_comp}"
end
```

## Possible Solution
Support the .containingHVACComponent method for CoilHeatingDXMultiSpeed objects. 

## Details

### Environment

Some additional details about your environment for this issue (if relevant):
 - Platform (Operating system, version): Windows
 - Version of OpenStudio (if using an intermediate build, include SHA): OS 3.4

### [Context](url)
I'm trying to access the supplemental coil on the paired AirLoopHVACUnitarySystem object for CoilHeatingDXMultiSpeed object.  This is for the ComStock EUSS project.  It is not time sensitive; I've already implemented and tested a workaround by looping through AirLoopHVACUnitarySystem objects and matching the heating coil.



Discussion / hints:

Fix patch:
diff --git a/src/model/CoilCoolingDXMultiSpeed.cpp b/src/model/CoilCoolingDXMultiSpeed.cpp
index 898170eadb3..5391635556a 100644
--- a/src/model/CoilCoolingDXMultiSpeed.cpp
+++ b/src/model/CoilCoolingDXMultiSpeed.cpp
@@ -35,6 +35,8 @@
 #include "Schedule_Impl.hpp"
 #include "CoilCoolingDXMultiSpeedStageData.hpp"
 #include "CoilCoolingDXMultiSpeedStageData_Impl.hpp"
+#include "AirLoopHVACUnitarySystem.hpp"
+#include "AirLoopHVACUnitarySystem_Impl.hpp"
 #include "AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed.hpp"
 #include "AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed_Impl.hpp"
 #include "ScheduleTypeLimits.hpp"
@@ -429,6 +431,19 @@ namespace model {
     }
 
     boost::optional<HVACComponent> CoilCoolingDXMultiSpeed_Impl::containingHVACComponent() const {
+      // AirLoopHVACUnitarySystem
+      {
+        auto systems = this->model().getConcreteModelObjects<AirLoopHVACUnitarySystem>();
+
+        for (auto const& system : systems) {
+          if (auto coolingCoil = system.coolingCoil()) {
+            if (coolingCoil->handle() == this->handle()) {
+              return system;
+            }
+          }
+        }
+      }
+
       // AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed
       {
         auto systems = this->model().getConcreteModelObjects<AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed>();
diff --git a/src/model/CoilHeatingDXMultiSpeed.cpp b/src/model/CoilHeatingDXMultiSpeed.cpp
index f24412e0c62..9d50b89640f 100644
--- a/src/model/CoilHeatingDXMultiSpeed.cpp
+++ b/src/model/CoilHeatingDXMultiSpeed.cpp
@@ -37,6 +37,8 @@
 #include "Curve_Impl.hpp"
 #include "CoilHeatingDXMultiSpeedStageData.hpp"
 #include "CoilHeatingDXMultiSpeedStageData_Impl.hpp"
+#include "AirLoopHVACUnitarySystem.hpp"
+#include "AirLoopHVACUnitarySystem_Impl.hpp"
 #include "AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed.hpp"
 #include "AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed_Impl.hpp"
 #include "ScheduleTypeLimits.hpp"
@@ -469,6 +471,19 @@ namespace model {
     }
 
     boost::optional<HVACComponent> CoilHeatingDXMultiSpeed_Impl::containingHVACComponent() const {
+      // AirLoopHVACUnitarySystem
+      {
+        auto systems = this->model().getConcreteModelObjects<AirLoopHVACUnitarySystem>();
+
+        for (auto const& system : systems) {
+          if (auto heatingCoil = system.heatingCoil()) {
+            if (heatingCoil->handle() == this->handle()) {
+              return system;
+            }
+          }
+        }
+      }
+
       // AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed
       {
         auto systems = this->model().getConcreteModelObjects<AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed>();


Test patch:
diff --git a/src/model/test/AirLoopHVACUnitarySystem_GTest.cpp b/src/model/test/AirLoopHVACUnitarySystem_GTest.cpp
index efd83914181..a0bef78fc67 100644
--- a/src/model/test/AirLoopHVACUnitarySystem_GTest.cpp
+++ b/src/model/test/AirLoopHVACUnitarySystem_GTest.cpp
@@ -68,6 +68,10 @@
 #include "../CurveBiquadratic.hpp"
 #include "../AirLoopHVAC.hpp"
 #include "../AirLoopHVAC_Impl.hpp"
+#include "../CoilHeatingDXVariableSpeed.hpp"
+#include "../CoilHeatingDXMultiSpeed.hpp"
+#include "../CoilCoolingDXVariableSpeed.hpp"
+#include "../CoilCoolingDXMultiSpeed.hpp"
 
 #include <utilities/idd/IddEnums.hxx>
 
@@ -551,6 +555,36 @@ TEST_F(ModelFixture, AirLoopHVACUnitarySystem_containingHVACComponent) {
   component = coilHeatingGas.containingHVACComponent();
   ASSERT_TRUE(component);
   EXPECT_EQ(*component, testObject);
+
+  CoilHeatingDXVariableSpeed coilHeatingDXVariableSpeed(m);
+  CoilCoolingDXVariableSpeed coilCoolingDXVariableSpeed(m);
+
+  EXPECT_TRUE(testObject.setSupplyFan(fanOnOff));
+  EXPECT_TRUE(testObject.setCoolingCoil(coilCoolingDXVariableSpeed));
+  EXPECT_TRUE(testObject.setHeatingCoil(coilHeatingDXVariableSpeed));
+  EXPECT_TRUE(testObject.setSupplementalHeatingCoil(coilHeatingWaterSupp));
+
+  component = coilHeatingDXVariableSpeed.containingHVACComponent();
+  ASSERT_TRUE(component);
+  EXPECT_EQ(*component, testObject);
+  component = coilCoolingDXVariableSpeed.containingHVACComponent();
+  ASSERT_TRUE(component);
+  EXPECT_EQ(*component, testObject);
+
+  CoilHeatingDXMultiSpeed coilHeatingDXMultiSpeed(m);
+  CoilCoolingDXMultiSpeed coilCoolingDXMultiSpeed(m);
+
+  EXPECT_TRUE(testObject.setSupplyFan(fanOnOff));
+  EXPECT_TRUE(testObject.setCoolingCoil(coilCoolingDXMultiSpeed));
+  EXPECT_TRUE(testObject.setHeatingCoil(coilHeatingDXMultiSpeed));
+  EXPECT_TRUE(testObject.setSupplementalHeatingCoil(coilHeatingWaterSupp));
+
+  component = coilHeatingDXMultiSpeed.containingHVACComponent();
+  ASSERT_TRUE(component);
+  EXPECT_EQ(*component, testObject);
+  component = coilCoolingDXMultiSpeed.containingHVACComponent();
+  ASSERT_TRUE(component);
+  EXPECT_EQ(*component, testObject);
 }
 
 TEST_F(ModelFixture, AirLoopHVACUnitarySystem_ControlType) {