Repository: NREL/OpenStudio (language: python)

Issue:
E+ 23.2.0: Wrap DistrictHeating:Steam
Enhancement Request
--------------
<!--- Provide a general summary of the feature you would like to see implemented -->

## Detailed Description
<!--- Provide a detailed description of the change or addition you are proposing. Include screenshot/schemas as appropriate -->

## Possible Implementation
<!--- Not mandatory, but if you can, suggest an idea for implementing the feature -->

E+ 23.2.0: Wrap DistrictHeating:Steam
Enhancement Request
--------------
<!--- Provide a general summary of the feature you would like to see implemented -->

## Detailed Description
<!--- Provide a detailed description of the change or addition you are proposing. Include screenshot/schemas as appropriate -->

## Possible Implementation
<!--- Not mandatory, but if you can, suggest an idea for implementing the feature -->



Discussion / hints:

Fix patch:
diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd
index e61ea1ba459..0bf4ca7e463 100644
--- a/resources/model/OpenStudio.idd
+++ b/resources/model/OpenStudio.idd
@@ -16642,14 +16642,19 @@ OS:DistrictCooling,
        \required-field
        \type object-list
        \object-list ConnectionNames
-  N1 ; \field Nominal Capacity
+  N1 , \field Nominal Capacity
        \units W
        \minimum 0.0
        \autosizable
        \required-field
+  A5 ; \field Capacity Fraction Schedule
+       \note Schedule values are multiplied by Nominal Capacity for current capacity
+       \type object-list
+       \object-list ScheduleNames
 
 OS:DistrictHeating,
-  A1, \field Handle
+       \memo Centralized source of hot water, such as a district heating system.
+  A1,  \field Handle
        \type handle
        \required-field
   A2 , \field Name
@@ -16663,11 +16668,41 @@ OS:DistrictHeating,
        \required-field
        \type object-list
        \object-list ConnectionNames
-  N1 ; \field Nominal Capacity
+  N1 , \field Nominal Capacity
        \units W
        \minimum 0.0
        \autosizable
        \required-field
+  A5 ; \field Capacity Fraction Schedule
+       \note Schedule values are multiplied by Nominal Capacity for current capacity
+       \type object-list
+       \object-list ScheduleNames
+
+OS:DistrictHeating:Steam,
+       \memo Centralized source of Steam, such as a district heating system.
+  A1,  \field Handle
+       \type handle
+       \required-field
+  A2 , \field Name
+       \required-field
+       \reference ConnectionObject
+  A3 , \field Steam Inlet Node Name
+       \required-field
+       \type object-list
+       \object-list ConnectionNames
+  A4 , \field Steam Outlet Node Name
+       \required-field
+       \type object-list
+       \object-list ConnectionNames
+  N1 , \field Nominal Capacity
+       \autosizable
+       \units W
+       \minimum 0.0
+       \required-field
+  A5 ; \field Capacity Fraction Schedule
+       \note Schedule values are multiplied by Nominal Capacity for current capacity
+       \type object-list
+       \object-list ScheduleNames
 
 OS:GroundHeatExchanger:Vertical,
         \extensible:2
diff --git a/src/energyplus/CMakeLists.txt b/src/energyplus/CMakeLists.txt
index c6430334ea3..2001f46c78e 100644
--- a/src/energyplus/CMakeLists.txt
+++ b/src/energyplus/CMakeLists.txt
@@ -145,6 +145,7 @@ set(${target_name}_src
   ForwardTranslator/ForwardTranslateDesignSpecificationOutdoorAir.cpp
   ForwardTranslator/ForwardTranslateDistrictCooling.cpp
   ForwardTranslator/ForwardTranslateDistrictHeating.cpp
+  ForwardTranslator/ForwardTranslateDistrictHeatingSteam.cpp
   ForwardTranslator/ForwardTranslateDuct.cpp
   ForwardTranslator/ForwardTranslateElectricEquipment.cpp
   ForwardTranslator/ForwardTranslateElectricEquipmentITEAirCooled.cpp
diff --git a/src/energyplus/ForwardTranslator.cpp b/src/energyplus/ForwardTranslator.cpp
index 0a102223adb..6241dff88d8 100644
--- a/src/energyplus/ForwardTranslator.cpp
+++ b/src/energyplus/ForwardTranslator.cpp
@@ -1506,6 +1506,11 @@ namespace energyplus {
         retVal = translateDistrictHeating(districtHeating);
         break;
       }
+      case openstudio::IddObjectType::OS_DistrictHeating_Steam: {
+        auto districtHeatingSteam = modelObject.cast<DistrictHeatingSteam>();
+        retVal = translateDistrictHeatingSteam(districtHeatingSteam);
+        break;
+      }
       case openstudio::IddObjectType::OS_Duct: {
         auto duct = modelObject.cast<Duct>();
         retVal = translateDuct(duct);
@@ -3495,8 +3500,9 @@ namespace energyplus {
       IddObjectType::OS_Curve_Triquadratic,
       IddObjectType::OS_Table_MultiVariableLookup,
       IddObjectType::OS_Table_Lookup,
-      IddObjectType::OS_DistrictCooling,
-      IddObjectType::OS_DistrictHeating,
+      // IddObjectType::OS_DistrictCooling,
+      // IddObjectType::OS_DistrictHeating,
+      // IddObjectType::OS_DistrictHeating_Steam,
       IddObjectType::OS_EvaporativeCooler_Direct_ResearchSpecial,
 
       IddObjectType::OS_Node,
diff --git a/src/energyplus/ForwardTranslator.hpp b/src/energyplus/ForwardTranslator.hpp
index ab7295603f9..ea4a61e2c0e 100644
--- a/src/energyplus/ForwardTranslator.hpp
+++ b/src/energyplus/ForwardTranslator.hpp
@@ -181,6 +181,7 @@ namespace model {
   class DesignSpecificationOutdoorAir;
   class DistrictCooling;
   class DistrictHeating;
+  class DistrictHeatingSteam;
   class Duct;
   class ElectricEquipment;
   class ElectricEquipmentITEAirCooled;
@@ -929,6 +930,8 @@ namespace energyplus {
 
     boost::optional<IdfObject> translateDistrictHeating(model::DistrictHeating& modelObject);
 
+    boost::optional<IdfObject> translateDistrictHeatingSteam(model::DistrictHeatingSteam& modelObject);
+
     boost::optional<IdfObject> translateDuct(model::Duct& modelObject);
 
     boost::optional<IdfObject> translateElectricEquipment(model::ElectricEquipment& modelObject);
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateDistrictCooling.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateDistrictCooling.cpp
index ce8c326b04b..01d331c43d0 100644
--- a/src/energyplus/ForwardTranslator/ForwardTranslateDistrictCooling.cpp
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateDistrictCooling.cpp
@@ -7,6 +7,8 @@
 #include "../../model/Model.hpp"
 #include "../../model/DistrictCooling.hpp"
 #include "../../model/DistrictCooling_Impl.hpp"
+#include "../../model/Schedule.hpp"
+#include "../../model/Schedule_Impl.hpp"
 #include "../../utilities/idf/IdfExtensibleGroup.hpp"
 #include "../../utilities/idf/Workspace.hpp"
 #include "../../utilities/idf/WorkspaceObjectOrder.hpp"
@@ -22,13 +24,10 @@ namespace energyplus {
 
   boost::optional<IdfObject> ForwardTranslator::translateDistrictCooling(DistrictCooling& modelObject) {
     OptionalString s;
-    OptionalDouble d;
     OptionalModelObject temp;
     boost::optional<double> value;
 
-    IdfObject idfObject(IddObjectType::DistrictCooling);
-
-    m_idfObjects.push_back(idfObject);
+    IdfObject idfObject = createRegisterAndNameIdfObject(IddObjectType::DistrictCooling, modelObject);
 
     ///////////////////////////////////////////////////////////////////////////
     // Field: Name ////////////////////////////////////////////////////////////
@@ -71,6 +70,20 @@ namespace energyplus {
     //
     ////////////////////////////////////////////////////////////////////////
 
+    ///////////////////////////////////////////////////////////////////////////
+    //Capacity Fraction Schedule Name ///////////////////////////////////////////////////
+    boost::optional<Schedule> capacityFractionSchedule = modelObject.capacityFractionSchedule();
+
+    if (capacityFractionSchedule) {
+      boost::optional<IdfObject> _capacityFractionSchedule = translateAndMapModelObject(capacityFractionSchedule.get());
+
+      if (_capacityFractionSchedule && _capacityFractionSchedule->name()) {
+        idfObject.setString(DistrictCoolingFields::CapacityFractionScheduleName, _capacityFractionSchedule->name().get());
+      }
+    }
+    //
+    ////////////////////////////////////////////////////////////////////////
+
     return boost::optional<IdfObject>(idfObject);
   }
 
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateDistrictHeating.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateDistrictHeating.cpp
index b4cc7f7cab3..5116a38ab12 100644
--- a/src/energyplus/ForwardTranslator/ForwardTranslateDistrictHeating.cpp
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateDistrictHeating.cpp
@@ -7,6 +7,8 @@
 #include "../../model/Model.hpp"
 #include "../../model/DistrictHeating.hpp"
 #include "../../model/DistrictHeating_Impl.hpp"
+#include "../../model/Schedule.hpp"
+#include "../../model/Schedule_Impl.hpp"
 #include "../../utilities/idf/IdfExtensibleGroup.hpp"
 #include "../../utilities/idf/Workspace.hpp"
 #include "../../utilities/idf/WorkspaceObjectOrder.hpp"
@@ -22,13 +24,10 @@ namespace energyplus {
 
   boost::optional<IdfObject> ForwardTranslator::translateDistrictHeating(DistrictHeating& modelObject) {
     OptionalString s;
-    OptionalDouble d;
     OptionalModelObject temp;
     boost::optional<double> value;
 
-    IdfObject idfObject(IddObjectType::DistrictHeating_Water);
-
-    m_idfObjects.push_back(idfObject);
+    IdfObject idfObject = createRegisterAndNameIdfObject(IddObjectType::DistrictHeating_Water, modelObject);
 
     ///////////////////////////////////////////////////////////////////////////
     // Field: Name ////////////////////////////////////////////////////////////
@@ -71,6 +70,19 @@ namespace energyplus {
     //
     ////////////////////////////////////////////////////////////////////////
 
+    ///////////////////////////////////////////////////////////////////////////
+    //Capacity Fraction Schedule Name ///////////////////////////////////////////////////
+    boost::optional<Schedule> capacityFractionSchedule = modelObject.capacityFractionSchedule();
+
+    if (capacityFractionSchedule) {
+      boost::optional<IdfObject> _capacityFractionSchedule = translateAndMapModelObject(capacityFractionSchedule.get());
+
+      if (_capacityFractionSchedule && _capacityFractionSchedule->name()) {
+        idfObject.setString(DistrictHeating_WaterFields::CapacityFractionScheduleName, _capacityFractionSchedule->name().get());
+      }
+    }
+    ////////////////////////////////////////////////////////////////////////
+
     return boost::optional<IdfObject>(idfObject);
   }
 
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateDistrictHeatingSteam.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateDistrictHeatingSteam.cpp
new file mode 100644
index 00000000000..3a37b166ff6
--- /dev/null
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateDistrictHeatingSteam.cpp
@@ -0,0 +1,92 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
+*  See also https://openstudio.net/license
+***********************************************************************************************************************/
+
+#include "../ForwardTranslator.hpp"
+#include "../../model/Model.hpp"
+#include "../../model/DistrictHeatingSteam.hpp"
+#include "../../model/DistrictHeatingSteam_Impl.hpp"
+#include "../../model/Schedule.hpp"
+#include "../../model/Schedule_Impl.hpp"
+#include "../../utilities/idf/IdfExtensibleGroup.hpp"
+#include "../../utilities/idf/Workspace.hpp"
+#include "../../utilities/idf/WorkspaceObjectOrder.hpp"
+#include "../../utilities/core/Logger.hpp"
+#include <utilities/idd/DistrictHeating_Steam_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::model;
+
+namespace openstudio {
+
+namespace energyplus {
+
+  boost::optional<IdfObject> ForwardTranslator::translateDistrictHeatingSteam(DistrictHeatingSteam& modelObject) {
+    OptionalString s;
+    OptionalModelObject temp;
+    boost::optional<double> value;
+
+    IdfObject idfObject = createRegisterAndNameIdfObject(IddObjectType::DistrictHeating_Steam, modelObject);
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Field: Name ////////////////////////////////////////////////////////////
+    s = modelObject.name();
+    if (s) {
+      idfObject.setName(*s);
+    }
+    ///////////////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Inlet Node Name ////////////////////////////////////////////////////
+    temp = modelObject.inletModelObject();
+    if (temp) {
+      s = temp->name();
+      if (s) {
+        idfObject.setString(openstudio::DistrictHeating_SteamFields::SteamInletNodeName, *s);
+      }
+    }
+    ///////////////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Outlet Node Name ///////////////////////////////////////////////////
+    temp = modelObject.outletModelObject();
+    if (temp) {
+      s = temp->name();
+      if (s) {
+        idfObject.setString(openstudio::DistrictHeating_SteamFields::SteamOutletNodeName, *s);
+      }
+    }
+    ///
+    ////////////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////////////
+    //Nominal Capacity ///////////////////////////////////////////////////
+    if (modelObject.isNominalCapacityAutosized()) {
+      idfObject.setString(DistrictHeating_SteamFields::NominalCapacity, "Autosize");
+    } else if ((value = modelObject.nominalCapacity())) {
+      idfObject.setDouble(DistrictHeating_SteamFields::NominalCapacity, value.get());
+    }
+    //
+    ////////////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////////////
+    //Capacity Fraction Schedule Name ///////////////////////////////////////////////////
+    boost::optional<Schedule> capacityFractionSchedule = modelObject.capacityFractionSchedule();
+
+    if (capacityFractionSchedule) {
+      boost::optional<IdfObject> _capacityFractionSchedule = translateAndMapModelObject(capacityFractionSchedule.get());
+
+      if (_capacityFractionSchedule && _capacityFractionSchedule->name()) {
+        idfObject.setString(DistrictHeating_SteamFields::CapacityFractionScheduleName, _capacityFractionSchedule->name().get());
+      }
+    }
+    //
+    ////////////////////////////////////////////////////////////////////////
+
+    return boost::optional<IdfObject>(idfObject);
+  }
+
+}  // namespace energyplus
+
+}  // namespace openstudio
diff --git a/src/energyplus/Test/DistrictCooling_GTest.cpp b/src/energyplus/Test/DistrictCooling_GTest.cpp
new file mode 100644
index 00000000000..a340686c887
--- /dev/null
+++ b/src/energyplus/Test/DistrictCooling_GTest.cpp
@@ -0,0 +1,52 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
+*  See also https://openstudio.net/license
+***********************************************************************************************************************/
+
+#include <gtest/gtest.h>
+#include "EnergyPlusFixture.hpp"
+
+#include "../ForwardTranslator.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/DistrictCooling.hpp"
+
+#include <utilities/idd/DistrictCooling_FieldEnums.hxx>
+
+#include <utilities/idd/IddEnums.hxx>
+#include "../../utilities/idf/IdfObject.hpp"
+#include "../../utilities/idf/IdfObject_Impl.hpp"
+
+#include "../../utilities/idf/WorkspaceObject.hpp"
+#include "../../utilities/idf/WorkspaceObject_Impl.hpp"
+
+using namespace openstudio::energyplus;
+using namespace openstudio::model;
+using namespace openstudio;
+
+TEST_F(EnergyPlusFixture, ForwardTranslator_DistrictCooling) {
+  Model m;
+
+  PlantLoop plant_loop(m);
+
+  DistrictCooling districtCooling(m);
+
+  EXPECT_TRUE(districtCooling.setNominalCapacity(1.0));
+  ScheduleConstant scheduleConstant(m);
+  EXPECT_TRUE(districtCooling.setCapacityFractionSchedule(scheduleConstant));
+
+  EXPECT_TRUE(plant_loop.addSupplyBranchForComponent(districtCooling));
+
+  ForwardTranslator ft;
+  Workspace w = ft.translateModel(m);
+
+  EXPECT_EQ(1u, w.getObjectsByType(IddObjectType::DistrictCooling).size());
+
+  IdfObject idf_dc = w.getObjectsByType(IddObjectType::DistrictCooling)[0];
+
+  EXPECT_EQ(districtCooling.nameString(), idf_dc.getString(DistrictCoolingFields::Name, false).get());
+  EXPECT_EQ(districtCooling.inletModelObject().get().nameString(), idf_dc.getString(DistrictCoolingFields::ChilledWaterInletNodeName, false).get());
+  EXPECT_EQ(districtCooling.outletModelObject().get().nameString(), idf_dc.getString(DistrictCoolingFields::ChilledWaterOutletNodeName, false).get());
+  EXPECT_EQ(1.0, idf_dc.getDouble(DistrictCoolingFields::NominalCapacity, false).get());
+  EXPECT_EQ(scheduleConstant.nameString(), idf_dc.getString(DistrictCoolingFields::CapacityFractionScheduleName, false).get());
+}
diff --git a/src/energyplus/Test/DistrictHeatingSteam_GTest.cpp b/src/energyplus/Test/DistrictHeatingSteam_GTest.cpp
new file mode 100644
index 00000000000..50ec46480a3
--- /dev/null
+++ b/src/energyplus/Test/DistrictHeatingSteam_GTest.cpp
@@ -0,0 +1,54 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
+*  See also https://openstudio.net/license
+***********************************************************************************************************************/
+
+#include <gtest/gtest.h>
+#include "EnergyPlusFixture.hpp"
+
+#include "../ForwardTranslator.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/DistrictHeatingSteam.hpp"
+
+#include <utilities/idd/DistrictHeating_Steam_FieldEnums.hxx>
+
+#include <utilities/idd/IddEnums.hxx>
+#include "../../utilities/idf/IdfObject.hpp"
+#include "../../utilities/idf/IdfObject_Impl.hpp"
+
+#include "../../utilities/idf/WorkspaceObject.hpp"
+#include "../../utilities/idf/WorkspaceObject_Impl.hpp"
+
+using namespace openstudio::energyplus;
+using namespace openstudio::model;
+using namespace openstudio;
+
+TEST_F(EnergyPlusFixture, ForwardTranslator_DistrictHeatingSteam) {
+  Model m;
+
+  PlantLoop plant_loop(m);
+
+  DistrictHeatingSteam districtHeatingSteam(m);
+
+  EXPECT_TRUE(districtHeatingSteam.setNominalCapacity(1.0));
+  ScheduleConstant scheduleConstant(m);
+  EXPECT_TRUE(districtHeatingSteam.setCapacityFractionSchedule(scheduleConstant));
+
+  EXPECT_TRUE(plant_loop.addSupplyBranchForComponent(districtHeatingSteam));
+
+  ForwardTranslator ft;
+  Workspace w = ft.translateModel(m);
+
+  EXPECT_EQ(1u, w.getObjectsByType(IddObjectType::DistrictHeating_Steam).size());
+
+  IdfObject idf_dhs = w.getObjectsByType(IddObjectType::DistrictHeating_Steam)[0];
+
+  EXPECT_EQ(districtHeatingSteam.nameString(), idf_dhs.getString(DistrictHeating_SteamFields::Name, false).get());
+  EXPECT_EQ(districtHeatingSteam.inletModelObject().get().nameString(),
+            idf_dhs.getString(DistrictHeating_SteamFields::SteamInletNodeName, false).get());
+  EXPECT_EQ(districtHeatingSteam.outletModelObject().get().nameString(),
+            idf_dhs.getString(DistrictHeating_SteamFields::SteamOutletNodeName, false).get());
+  EXPECT_EQ(1.0, idf_dhs.getDouble(DistrictHeating_SteamFields::NominalCapacity, false).get());
+  EXPECT_EQ(scheduleConstant.nameString(), idf_dhs.getString(DistrictHeating_SteamFields::CapacityFractionScheduleName, false).get());
+}
diff --git a/src/energyplus/Test/DistrictHeatingWater_GTest.cpp b/src/energyplus/Test/DistrictHeatingWater_GTest.cpp
new file mode 100644
index 00000000000..72be7364cd2
--- /dev/null
+++ b/src/energyplus/Test/DistrictHeatingWater_GTest.cpp
@@ -0,0 +1,54 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
+*  See also https://openstudio.net/license
+***********************************************************************************************************************/
+
+#include <gtest/gtest.h>
+#include "EnergyPlusFixture.hpp"
+
+#include "../ForwardTranslator.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/DistrictHeating.hpp"
+
+#include <utilities/idd/DistrictHeating_Water_FieldEnums.hxx>
+
+#include <utilities/idd/IddEnums.hxx>
+#include "../../utilities/idf/IdfObject.hpp"
+#include "../../utilities/idf/IdfObject_Impl.hpp"
+
+#include "../../utilities/idf/WorkspaceObject.hpp"
+#include "../../utilities/idf/WorkspaceObject_Impl.hpp"
+
+using namespace openstudio::energyplus;
+using namespace openstudio::model;
+using namespace openstudio;
+
+TEST_F(EnergyPlusFixture, ForwardTranslator_DistrictHeatingWater) {
+  Model m;
+
+  PlantLoop plant_loop(m);
+
+  DistrictHeating districtHeatingWater(m);
+
+  EXPECT_TRUE(districtHeatingWater.setNominalCapacity(1.0));
+  ScheduleConstant scheduleConstant(m);
+  EXPECT_TRUE(districtHeatingWater.setCapacityFractionSchedule(scheduleConstant));
+
+  EXPECT_TRUE(plant_loop.addSupplyBranchForComponent(districtHeatingWater));
+
+  ForwardTranslator ft;
+  Workspace w = ft.translateModel(m);
+
+  EXPECT_EQ(1u, w.getObjectsByType(IddObjectType::DistrictHeating_Water).size());
+
+  IdfObject idf_dhw = w.getObjectsByType(IddObjectType::DistrictHeating_Water)[0];
+
+  EXPECT_EQ(districtHeatingWater.nameString(), idf_dhw.getString(DistrictHeating_WaterFields::Name, false).get());
+  EXPECT_EQ(districtHeatingWater.inletModelObject().get().nameString(),
+            idf_dhw.getString(DistrictHeating_WaterFields::HotWaterInletNodeName, false).get());
+  EXPECT_EQ(districtHeatingWater.outletModelObject().get().nameString(),
+            idf_dhw.getString(DistrictHeating_WaterFields::HotWaterOutletNodeName, false).get());
+  EXPECT_EQ(1.0, idf_dhw.getDouble(DistrictHeating_WaterFields::NominalCapacity, false).get());
+  EXPECT_EQ(scheduleConstant.nameString(), idf_dhw.getString(DistrictHeating_WaterFields::CapacityFractionScheduleName, false).get());
+}
diff --git a/src/model/CMakeLists.txt b/src/model/CMakeLists.txt
index e9fa0111418..e5bb033f7a6 100644
--- a/src/model/CMakeLists.txt
+++ b/src/model/CMakeLists.txt
@@ -626,6 +626,9 @@ set(${target_name}_src
   DistrictHeating.hpp
   DistrictHeating_Impl.hpp
   DistrictHeating.cpp
+  DistrictHeatingSteam.hpp
+  DistrictHeatingSteam_Impl.hpp
+  DistrictHeatingSteam.cpp
   Duct.hpp
   Duct_Impl.hpp
   Duct.cpp
@@ -2051,6 +2054,7 @@ set(${target_name}_test_src
   test/DesignSpecificationZoneAirDistribution_GTest.cpp
   test/DistrictCooling_GTest.cpp
   test/DistrictHeating_GTest.cpp
+  test/DistrictHeatingSteam_GTest.cpp
   test/Duct_GTest.cpp
   test/ElectricEquipment_GTest.cpp
   test/ElectricEquipmentITEAirCooled_GTest.cpp
diff --git a/src/model/ConcreteModelObjects.hpp b/src/model/ConcreteModelObjects.hpp
index c61481f755b..ae3d7856797 100644
--- a/src/model/ConcreteModelObjects.hpp
+++ b/src/model/ConcreteModelObjects.hpp
@@ -194,6 +194,7 @@
 #include "DesignSpecificationZoneAirDistribution.hpp"
 #include "DistrictCooling.hpp"
 #include "DistrictHeating.hpp"
+#include "DistrictHeatingSteam.hpp"
 #include "Duct.hpp"
 #include "ElectricEquipment.hpp"
 #include "ElectricEquipmentDefinition.hpp"
@@ -745,6 +746,7 @@
 #include "DesignSpecificationZoneAirDistribution_Impl.hpp"
 #include "DistrictCooling_Impl.hpp"
 #include "DistrictHeating_Impl.hpp"
+#include "DistrictHeatingSteam_Impl.hpp"
 #include "Duct_Impl.hpp"
 #include "ElectricEquipment_Impl.hpp"
 #include "ElectricEquipmentDefinition_Impl.hpp"
diff --git a/src/model/DistrictCooling.cpp b/src/model/DistrictCooling.cpp
index 0331f32380e..899f3818134 100644
--- a/src/model/DistrictCooling.cpp
+++ b/src/model/DistrictCooling.cpp
@@ -7,6 +7,8 @@
 #include "DistrictCooling_Impl.hpp"
 #include "Node.hpp"
 #include "Node_Impl.hpp"
+#include "Schedule.hpp"
+#include "Schedule_Impl.hpp"
 
 #include "../utilities/core/Assert.hpp"
 #include "../utilities/data/DataEnums.hpp"
@@ -56,6 +58,10 @@ namespace model {
       return result;
     }
 
+    boost::optional<Schedule> DistrictCooling_Impl::capacityFractionSchedule() const {
+      return getObject<ModelObject>().getModelObjectTarget<Schedule>(OS_DistrictCoolingFields::CapacityFractionSchedule);
+    }
+
     bool DistrictCooling_Impl::setNominalCapacity(boost::optional<double> nominalCapacity) {
       bool result(false);
       if (nominalCapacity) {
@@ -87,6 +93,16 @@ namespace model {
       return false;
     }
 
+    bool DistrictCooling_Impl::setCapacityFractionSchedule(Schedule& schedule) {
+      bool result = setSchedule(OS_DistrictCoolingFields::CapacityFractionSchedule, "DistrictCooling", "Capacity Fraction", schedule);
+      return result;
+    }
+
+    void DistrictCooling_Impl::resetCapacityFractionSchedule() {
+      bool result = setString(OS_DistrictCoolingFields::CapacityFractionSchedule, "");
+      OS_ASSERT(result);
+    }
+
     boost::optional<double> DistrictCooling_Impl::autosizedNominalCapacity() const {
       return getAutosizedValue("Design Size Nominal Capacity", "W");
     }
@@ -139,6 +155,10 @@ namespace model {
     return getImpl<detail::DistrictCooling_Impl>()->isNominalCapacityAutosized();
   }
 
+  boost::optional<Schedule> DistrictCooling::capacityFractionSchedule() const {
+    return getImpl<detail::DistrictCooling_Impl>()->capacityFractionSchedule();
+  }
+
   bool DistrictCooling::setNominalCapacity(double nominalCapacity) {
     return getImpl<detail::DistrictCooling_Impl>()->setNominalCapacity(nominalCapacity);
   }
@@ -147,6 +167,14 @@ namespace model {
     getImpl<detail::DistrictCooling_Impl>()->autosizeNominalCapacity();
   }
 
+  bool DistrictCooling::setCapacityFractionSchedule(Schedule& schedule) {
+    return getImpl<detail::DistrictCooling_Impl>()->setCapacityFractionSchedule(schedule);
+  }
+
+  void DistrictCooling::resetCapacityFractionSchedule() {
+    getImpl<detail::DistrictCooling_Impl>()->resetCapacityFractionSchedule();
+  }
+
   /// @cond
 
   DistrictCooling::DistrictCooling(std::shared_ptr<detail::DistrictCooling_Impl> impl) : StraightComponent(std::move(impl)) {}
diff --git a/src/model/DistrictCooling.hpp b/src/model/DistrictCooling.hpp
index 58abcff26a5..0c6f2a1a593 100644
--- a/src/model/DistrictCooling.hpp
+++ b/src/model/DistrictCooling.hpp
@@ -13,6 +13,8 @@ namespace openstudio {
 
 namespace model {
 
+  class Schedule;
+
   namespace detail {
 
     class DistrictCooling_Impl;
@@ -53,6 +55,8 @@ namespace model {
 
     bool isNominalCapacityAutosized() const;
 
+    boost::optional<Schedule> capacityFractionSchedule() const;
+
     //@}
     /** @name Setters */
     //@{
@@ -61,6 +65,10 @@ namespace model {
 
     void autosizeNominalCapacity();
 
+    bool setCapacityFractionSchedule(Schedule& schedule);
+
+    void resetCapacityFractionSchedule();
+
     //@}
     /** @name Other */
     //@{
diff --git a/src/model/DistrictCooling_Impl.hpp b/src/model/DistrictCooling_Impl.hpp
index 064b30e7003..12338585b31 100644
--- a/src/model/DistrictCooling_Impl.hpp
+++ b/src/model/DistrictCooling_Impl.hpp
@@ -13,6 +13,8 @@ namespace openstudio {
 
 namespace model {
 
+  class Schedule;
+
   namespace detail {
 
     /** DistrictCooling_Impl is a StraightComponent_Impl that is the implementation class for DistrictCooling.*/
@@ -63,20 +65,26 @@ namespace model {
 
       boost::optional<double> autosizedNominalCapacity() const;
 
+      boost::optional<Schedule> capacityFractionSchedule() const;
+
       //@}
       /** @name Setters */
       //@{
 
+      bool setNominalCapacity(boost::optional<double> nominalCapacity);
+
+      void autosizeNominalCapacity();
+
       bool addToNode(Node& node) override;
 
+      bool setCapacityFractionSchedule(Schedule& schedule);
+
+      void resetCapacityFractionSchedule();
+
       //@}
       /** @name Other */
       //@{
 
-      bool setNominalCapacity(boost::optional<double> nominalCapacity);
-
-      void autosizeNominalCapacity();
-
       //@}
 
      protected:
diff --git a/src/model/DistrictHeating.cpp b/src/model/DistrictHeating.cpp
index 6e2ab1b8647..2bb3aee9517 100644
--- a/src/model/DistrictHeating.cpp
+++ b/src/model/DistrictHeating.cpp
@@ -7,6 +7,8 @@
 #include "DistrictHeating_Impl.hpp"
 #include "Node.hpp"
 #include "Node_Impl.hpp"
+#include "Schedule.hpp"
+#include "Schedule_Impl.hpp"
 
 #include "../utilities/core/Assert.hpp"
 #include "../utilities/data/DataEnums.hpp"
@@ -43,6 +45,17 @@ namespace model {
       return DistrictHeating::iddObjectType();
     }
 
+    std::vector<ScheduleTypeKey> DistrictHeating_Impl::getScheduleTypeKeys(const Schedule& schedule) const {
+      std::vector<ScheduleTypeKey> result;
+      UnsignedVector fieldIndices = getSourceIndices(schedule.handle());
+      UnsignedVector::const_iterator b(fieldIndices.begin());
+      UnsignedVector::const_iterator e(fieldIndices.end());
+      if (std::find(b, e, OS_DistrictHeatingFields::CapacityFractionSchedule) != e) {
+        result.push_back(ScheduleTypeKey("DistrictHeating", "Capacity Fraction Schedule"));
+      }
+      return result;
+    }
+
     boost::optional<double> DistrictHeating_Impl::nominalCapacity() const {
       return getDouble(OS_DistrictHeatingFields::NominalCapacity, true);
     }
@@ -56,6 +69,10 @@ namespace model {
       return result;
     }
 
+    boost::optional<Schedule> DistrictHeating_Impl::capacityFractionSchedule() const {
+      return getObject<ModelObject>().getModelObjectTarget<Schedule>(OS_DistrictHeatingFields::CapacityFractionSchedule);
+    }
+
     bool DistrictHeating_Impl::setNominalCapacity(boost::optional<double> nominalCapacity) {
       bool result(false);
       if (nominalCapacity) {
@@ -87,6 +104,16 @@ namespace model {
       return false;
     }
 
+    bool DistrictHeating_Impl::setCapacityFractionSchedule(Schedule& schedule) {
+      bool result = setSchedule(OS_DistrictHeatingFields::CapacityFractionSchedule, "DistrictHeating", "Capacity Fraction", schedule);
+      return result;
+    }
+
+    void DistrictHeating_Impl::resetCapacityFractionSchedule() {
+      bool result = setString(OS_DistrictHeatingFields::CapacityFractionSchedule, "");
+      OS_ASSERT(result);
+    }
+
     boost::optional<double> DistrictHeating_Impl::autosizedNominalCapacity() const {
       return getAutosizedValue("Design Size Nominal Capacity", "W");
     }
@@ -139,6 +166,10 @@ namespace model {
     return getImpl<detail::DistrictHeating_Impl>()->isNominalCapacityAutosized();
   }
 
+  boost::optional<Schedule> DistrictHeating::capacityFractionSchedule() const {
+    return getImpl<detail::DistrictHeating_Impl>()->capacityFractionSchedule();
+  }
+
   bool DistrictHeating::setNominalCapacity(double nominalCapacity) {
     return getImpl<detail::DistrictHeating_Impl>()->setNominalCapacity(nominalCapacity);
   }
@@ -147,6 +178,14 @@ namespace model {
     getImpl<detail::DistrictHeating_Impl>()->autosizeNominalCapacity();
   }
 
+  bool DistrictHeating::setCapacityFractionSchedule(Schedule& schedule) {
+    return getImpl<detail::DistrictHeating_Impl>()->setCapacityFractionSchedule(schedule);
+  }
+
+  void DistrictHeating::resetCapacityFractionSchedule() {
+    getImpl<detail::DistrictHeating_Impl>()->resetCapacityFractionSchedule();
+  }
+
   /// @cond
 
   DistrictHeating::DistrictHeating(std::shared_ptr<detail::DistrictHeating_Impl> impl) : StraightComponent(std::move(impl)) {}
diff --git a/src/model/DistrictHeating.hpp b/src/model/DistrictHeating.hpp
index 50bd63d894b..2f138310148 100644
--- a/src/model/DistrictHeating.hpp
+++ b/src/model/DistrictHeating.hpp
@@ -13,6 +13,8 @@ namespace openstudio {
 
 namespace model {
 
+  class Schedule;
+
   namespace detail {
 
     class DistrictHeating_Impl;
@@ -53,6 +55,8 @@ namespace model {
 
     bool isNominalCapacityAutosized() const;
 
+    boost::optional<Schedule> capacityFractionSchedule() const;
+
     //@}
     /** @name Setters */
     //@{
@@ -61,6 +65,10 @@ namespace model {
 
     void autosizeNominalCapacity();
 
+    bool setCapacityFractionSchedule(Schedule& schedule);
+
+    void resetCapacityFractionSchedule();
+
     //@}
     /** @name Other */
     //@{
diff --git a/src/model/DistrictHeatingSteam.cpp b/src/model/DistrictHeatingSteam.cpp
new file mode 100644
index 00000000000..331f7c97d43
--- /dev/null
+++ b/src/model/DistrictHeatingSteam.cpp
@@ -0,0 +1,200 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
+*  See also https://openstudio.net/license
+***********************************************************************************************************************/
+
+#include "DistrictHeatingSteam.hpp"
+#include "DistrictHeatingSteam_Impl.hpp"
+#include "Node.hpp"
+#include "Node_Impl.hpp"
+#include "Schedule.hpp"
+#include "Schedule_Impl.hpp"
+
+#include "../utilities/core/Assert.hpp"
+#include "../utilities/data/DataEnums.hpp"
+
+#include <utilities/idd/OS_DistrictHeating_Steam_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+
+namespace openstudio {
+namespace model {
+
+  namespace detail {
+
+    DistrictHeatingSteam_Impl::DistrictHeatingSteam_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle)
+      : StraightComponent_Impl(idfObject, model, keepHandle) {
+      OS_ASSERT(idfObject.iddObject().type() == DistrictHeatingSteam::iddObjectType());
+    }
+
+    DistrictHeatingSteam_Impl::DistrictHeatingSteam_Impl(const openstudio::detail::WorkspaceObject_Impl& other, Model_Impl* model, bool keepHandle)
+      : StraightComponent_Impl(other, model, keepHandle) {
+      OS_ASSERT(other.iddObject().type() == DistrictHeatingSteam::iddObjectType());
+    }
+
+    DistrictHeatingSteam_Impl::DistrictHeatingSteam_Impl(const DistrictHeatingSteam_Impl& other, Model_Impl* model, bool keepHandle)
+      : StraightComponent_Impl(other, model, keepHandle) {}
+
+    const std::vector<std::string>& DistrictHeatingSteam_Impl::outputVariableNames() const {
+      static const std::vector<std::string> result{
+        "District Heating Hot Water Rate",    "District Heating Hot Water Energy",   "District Heating Rate",
+        "District Heating Inlet Temperature", "District Heating Outlet Temperature", "District Heating Mass Flow Rate"};
+      return result;
+    }
+
+    IddObjectType DistrictHeatingSteam_Impl::iddObjectType() const {
+      return DistrictHeatingSteam::iddObjectType();
+    }
+
+    std::vector<ScheduleTypeKey> DistrictHeatingSteam_Impl::getScheduleTypeKeys(const Schedule& schedule) const {
+      std::vector<ScheduleTypeKey> result;
+      UnsignedVector fieldIndices = getSourceIndices(schedule.handle());
+      UnsignedVector::const_iterator b(fieldIndices.begin());
+      UnsignedVector::const_iterator e(fieldIndices.end());
+      if (std::find(b, e, OS_DistrictHeating_SteamFields::CapacityFractionSchedule) != e) {
+        result.push_back(ScheduleTypeKey("DistrictHeatingSteam", "Capacity Fraction Schedule"));
+      }
+      return result;
+    }
+
+    boost::optional<double> DistrictHeatingSteam_Impl::nominalCapacity() const {
+      return getDouble(OS_DistrictHeating_SteamFields::NominalCapacity, true);
+    }
+
+    bool DistrictHeatingSteam_Impl::isNominalCapacityAutosized() const {
+      bool result = false;
+      boost::optional<std::string> value = getString(OS_DistrictHeating_SteamFields::NominalCapacity, true);
+      if (value) {
+        result = openstudio::istringEqual(value.get(), "autosize");
+      }
+      return result;
+    }
+
+    boost::optional<Schedule> DistrictHeatingSteam_Impl::capacityFractionSchedule() const {
+      return getObject<ModelObject>().getModelObjectTarget<Schedule>(OS_DistrictHeating_SteamFields::CapacityFractionSchedule);
+    }
+
+    bool DistrictHeatingSteam_Impl::setNominalCapacity(boost::optional<double> nominalCapacity) {
+      bool result(false);
+      if (nominalCapacity) {
+        result = setDouble(OS_DistrictHeating_SteamFields::NominalCapacity, nominalCapacity.get());
+      }
+      return result;
+    }
+
+    void DistrictHeatingSteam_Impl::autosizeNominalCapacity() {
+      bool result = setString(OS_DistrictHeating_SteamFields::NominalCapacity, "autosize");
+      OS_ASSERT(result);
+    }
+
+    unsigned DistrictHeatingSteam_Impl::inletPort() const {
+      return OS_DistrictHeating_SteamFields::SteamInletNodeName;
+    }
+
+    unsigned DistrictHeatingSteam_Impl::outletPort() const {
+      return OS_DistrictHeating_SteamFields::SteamOutletNodeName;
+    }
+
+    bool DistrictHeatingSteam_Impl::addToNode(Node& node) {
+      if (boost::optional<PlantLoop> plant = node.plantLoop()) {
+        if (plant->supplyComponent(node.handle())) {
+          return StraightComponent_Impl::addToNode(node);
+        }
+      }
+
+      return false;
+    }
+
+    bool DistrictHeatingSteam_Impl::setCapacityFractionSchedule(Schedule& schedule) {
+      bool result = setSchedule(OS_DistrictHeating_SteamFields::CapacityFractionSchedule, "DistrictHeatingSteam", "Capacity Fraction", schedule);
+      return result;
+    }
+
+    void DistrictHeatingSteam_Impl::resetCapacityFractionSchedule() {
+      bool result = setString(OS_DistrictHeating_SteamFields::CapacityFractionSchedule, "");
+      OS_ASSERT(result);
+    }
+
+    boost::optional<double> DistrictHeatingSteam_Impl::autosizedNominalCapacity() const {
+      return getAutosizedValue("Design Size Nominal Capacity", "W");
+    }
+
+    void DistrictHeatingSteam_Impl::autosize() {
+      autosizeNominalCapacity();
+    }
+
+    void DistrictHeatingSteam_Impl::applySizingValues() {
+      boost::optional<double> val;
+      val = autosizedNominalCapacity();
+      if (val) {
+        setNominalCapacity(val.get());
+      }
+    }
+
+    ComponentType DistrictHeatingSteam_Impl::componentType() const {
+      return ComponentType::Heating;
+    }
+
+    std::vector<FuelType> DistrictHeatingSteam_Impl::coolingFuelTypes() const {
+      return {};
+    }
+
+    std::vector<FuelType> DistrictHeatingSteam_Impl::heatingFuelTypes() const {
+      return {FuelType::Steam};
+    }
+
+    std::vector<AppGFuelType> DistrictHeatingSteam_Impl::appGHeatingFuelTypes() const {
+      return {AppGFuelType::District};
+    }
+
+  }  // namespace detail
+
+  DistrictHeatingSteam::DistrictHeatingSteam(const Model& model) : StraightComponent(DistrictHeatingSteam::iddObjectType(), model) {
+    OS_ASSERT(getImpl<detail::DistrictHeatingSteam_Impl>());
+    autosizeNominalCapacity();
+  }
+
+  IddObjectType DistrictHeatingSteam::iddObjectType() {
+    IddObjectType result(IddObjectType::OS_DistrictHeating_Steam);
+    return result;
+  }
+
+  boost::optional<double> DistrictHeatingSteam::nominalCapacity() const {
+    return getImpl<detail::DistrictHeatingSteam_Impl>()->nominalCapacity();
+  }
+
+  bool DistrictHeatingSteam::isNominalCapacityAutosized() const {
+    return getImpl<detail::DistrictHeatingSteam_Impl>()->isNominalCapacityAutosized();
+  }
+
+  boost::optional<Schedule> DistrictHeatingSteam::capacityFractionSchedule() const {
+    return getImpl<detail::DistrictHeatingSteam_Impl>()->capacityFractionSchedule();
+  }
+
+  bool DistrictHeatingSteam::setNominalCapacity(double nominalCapacity) {
+    return getImpl<detail::DistrictHeatingSteam_Impl>()->setNominalCapacity(nominalCapacity);
+  }
+
+  void DistrictHeatingSteam::autosizeNominalCapacity() {
+    getImpl<detail::DistrictHeatingSteam_Impl>()->autosizeNominalCapacity();
+  }
+
+  bool DistrictHeatingSteam::setCapacityFractionSchedule(Schedule& schedule) {
+    return getImpl<detail::DistrictHeatingSteam_Impl>()->setCapacityFractionSchedule(schedule);
+  }
+
+  void DistrictHeatingSteam::resetCapacityFractionSchedule() {
+    getImpl<detail::DistrictHeatingSteam_Impl>()->resetCapacityFractionSchedule();
+  }
+
+  /// @cond
+
+  DistrictHeatingSteam::DistrictHeatingSteam(std::shared_ptr<detail::DistrictHeatingSteam_Impl> impl) : StraightComponent(std::move(impl)) {}
+  /// @endcond
+
+  boost::optional<double> DistrictHeatingSteam::autosizedNominalCapacity() const {
+    return getImpl<detail::DistrictHeatingSteam_Impl>()->autosizedNominalCapacity();
+  }
+
+}  // namespace model
+
+}  // namespace openstudio
diff --git a/src/model/DistrictHeatingSteam.hpp b/src/model/DistrictHeatingSteam.hpp
new file mode 100644
index 00000000000..0a296d5ba28
--- /dev/null
+++ b/src/model/DistrictHeatingSteam.hpp
@@ -0,0 +1,106 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
+*  See also https://openstudio.net/license
+***********************************************************************************************************************/
+
+#ifndef MODEL_DISTRICTHEATINGSTEAM_HPP
+#define MODEL_DISTRICTHEATINGSTEAM_HPP
+
+#include "ModelAPI.hpp"
+#include "StraightComponent.hpp"
+
+namespace openstudio {
+
+namespace model {
+
+  class Schedule;
+
+  namespace detail {
+
+    class DistrictHeatingSteam_Impl;
+
+  }  // namespace detail
+
+  /** DistrictHeatingSteam is a StraightComponent that wraps the OpenStudio IDD object 'OS:DistrictHeatingSteam'. */
+
+  class MODEL_API DistrictHeatingSteam : public StraightComponent
+  {
+
+   public:
+    /** @name Constructors and Destructors */
+    //@{
+
+    explicit DistrictHeatingSteam(const Model& model);
+
+    virtual ~DistrictHeatingSteam() = default;
+    // Default the copy and move operators because the virtual dtor is explicit
+    DistrictHeatingSteam(const DistrictHeatingSteam& other) = default;
+    DistrictHeatingSteam(DistrictHeatingSteam&& other) = default;
+    DistrictHeatingSteam& operator=(const DistrictHeatingSteam&) = default;
+    DistrictHeatingSteam& operator=(DistrictHeatingSteam&&) = default;
+
+    //@}
+
+    //@}
+    /** @name Static Methods */
+    //@{
+
+    static IddObjectType iddObjectType();
+
+    //@}
+    /** @name Getters */
+    //@{
+
+    boost::optional<double> nominalCapacity() const;
+
+    bool isNominalCapacityAutosized() const;
+
+    boost::optional<Schedule> capacityFractionSchedule() const;
+
+    //@}
+    /** @name Setters */
+    //@{
+
+    bool setNominalCapacity(double nominalCapacity);
+
+    void autosizeNominalCapacity();
+
+    bool setCapacityFractionSchedule(Schedule& schedule);
+
+    void resetCapacityFractionSchedule();
+
+    //@}
+    /** @name Other */
+    //@{
+
+    //@}
+
+    boost::optional<double> autosizedNominalCapacity() const;
+
+   protected:
+    /// @cond
+    using ImplType = detail::DistrictHeatingSteam_Impl;
+
+    explicit DistrictHeatingSteam(std::shared_ptr<detail::DistrictHeatingSteam_Impl> impl);
+
+    friend class detail::DistrictHeatingSteam_Impl;
+    friend class Model;
+    friend class IdfObject;
+    friend class openstudio::detail::IdfObject_Impl;
+
+    /// @endcond
+
+   private:
+    REGISTER_LOGGER("openstudio.model.DistrictHeatingSteam");
+  };
+
+  /** \relates DistrictHeatingSteam*/
+  using OptionalDistrictHeatingSteam = boost::optional<DistrictHeatingSteam>;
+
+  /** \relates DistrictHeatingSteam*/
+  using DistrictHeatingSteamVector = std::vector<DistrictHeatingSteam>;
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_DISTRICTHEATINGSTEAM_HPP
diff --git a/src/model/DistrictHeatingSteam_Impl.hpp b/src/model/DistrictHeatingSteam_Impl.hpp
new file mode 100644
index 00000000000..28d21eea5ec
--- /dev/null
+++ b/src/model/DistrictHeatingSteam_Impl.hpp
@@ -0,0 +1,102 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
+*  See also https://openstudio.net/license
+***********************************************************************************************************************/
+
+#ifndef MODEL_DISTRICTHEATINGSTEAM_IMPL_HPP
+#define MODEL_DISTRICTHEATINGSTEAM_IMPL_HPP
+
+#include "ModelAPI.hpp"
+#include "StraightComponent_Impl.hpp"
+
+namespace openstudio {
+
+namespace model {
+
+  class Schedule;
+
+  namespace detail {
+
+    /** DistrictHeatingSteam_Impl is a StraightComponent_Impl that is the implementation class for DistrictHeatingSteam.*/
+
+    class MODEL_API DistrictHeatingSteam_Impl : public StraightComponent_Impl
+    {
+
+     public:
+      /** @name Constructors and Destructors */
+      //@{
+
+      DistrictHeatingSteam_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle);
+
+      DistrictHeatingSteam_Impl(const openstudio::detail::WorkspaceObject_Impl& other, Model_Impl* model, bool keepHandle);
+
+      DistrictHeatingSteam_Impl(const DistrictHeatingSteam_Impl& other, Model_Impl* model, bool keepHandle);
+
+      virtual ~DistrictHeatingSteam_Impl() = default;
+
+      //@}
+      /** @name Virtual Methods */
+      //@{
+
+      virtual const std::vector<std::string>& outputVariableNames() const override;
+
+      virtual IddObjectType iddObjectType() const override;
+
+      virtual unsigned inletPort() const override;
+
+      virtual unsigned outletPort() const override;
+      virtual void autosize() override;
+
+      virtual void applySizingValues() override;
+
+      virtual ComponentType componentType() const override;
+      virtual std::vector<FuelType> coolingFuelTypes() const override;
+      virtual std::vector<FuelType> heatingFuelTypes() const override;
+      virtual std::vector<AppGFuelType> appGHeatingFuelTypes() const override;
+
+      virtual std::vector<ScheduleTypeKey> getScheduleTypeKeys(const Schedule& schedule) const override;
+
+      //@}
+      /** @name Getters */
+      //@{
+
+      boost::optional<double> nominalCapacity() const;
+
+      bool isNominalCapacityAutosized() const;
+
+      boost::optional<double> autosizedNominalCapacity() const;
+
+      boost::optional<Schedule> capacityFractionSchedule() const;
+
+      //@}
+      /** @name Setters */
+      //@{
+
+      bool setNominalCapacity(boost::optional<double> nominalCapacity);
+
+      void autosizeNominalCapacity();
+
+      bool addToNode(Node& node) override;
+
+      bool setCapacityFractionSchedule(Schedule& schedule);
+
+      void resetCapacityFractionSchedule();
+
+      //@}
+      /** @name Other */
+      //@{
+
+      //@}
+
+     protected:
+     private:
+      REGISTER_LOGGER("openstudio.model.DistrictHeatingSteam");
+    };
+
+  }  // namespace detail
+
+}  // namespace model
+
+}  // namespace openstudio
+
+#endif  // MODEL_DISTRICTHEATINGSTEAM_IMPL_HPP
diff --git a/src/model/DistrictHeating_Impl.hpp b/src/model/DistrictHeating_Impl.hpp
index 5f37514f566..079e5fe0c83 100644
--- a/src/model/DistrictHeating_Impl.hpp
+++ b/src/model/DistrictHeating_Impl.hpp
@@ -13,6 +13,8 @@ namespace openstudio {
 
 namespace model {
 
+  class Schedule;
+
   namespace detail {
 
     /** DistrictHeating_Impl is a StraightComponent_Impl that is the implementation class for DistrictHeating.*/
@@ -52,6 +54,8 @@ namespace model {
       virtual std::vector<FuelType> heatingFuelTypes() const override;
       virtual std::vector<AppGFuelType> appGHeatingFuelTypes() const override;
 
+      virtual std::vector<ScheduleTypeKey> getScheduleTypeKeys(const Schedule& schedule) const override;
+
       //@}
       /** @name Getters */
       //@{
@@ -62,6 +66,8 @@ namespace model {
 
       boost::optional<double> autosizedNominalCapacity() const;
 
+      boost::optional<Schedule> capacityFractionSchedule() const;
+
       //@}
       /** @name Setters */
       //@{
@@ -72,6 +78,10 @@ namespace model {
 
       bool addToNode(Node& node) override;
 
+      bool setCapacityFractionSchedule(Schedule& schedule);
+
+      void resetCapacityFractionSchedule();
+
       //@}
       /** @name Other */
       //@{
diff --git a/src/model/Model.cpp b/src/model/Model.cpp
index 18caded3bf1..ac9478fab06 100644
--- a/src/model/Model.cpp
+++ b/src/model/Model.cpp
@@ -4025,6 +4025,7 @@ namespace model {
     REGISTER_CONSTRUCTOR(DesignSpecificationZoneAirDistribution);
     REGISTER_CONSTRUCTOR(DistrictCooling);
     REGISTER_CONSTRUCTOR(DistrictHeating);
+    REGISTER_CONSTRUCTOR(DistrictHeatingSteam);
     REGISTER_CONSTRUCTOR(Duct);
     REGISTER_CONSTRUCTOR(ElectricEquipment);
     REGISTER_CONSTRUCTOR(ElectricEquipmentDefinition);
@@ -4596,6 +4597,7 @@ namespace model {
     REGISTER_COPYCONSTRUCTORS(DesignSpecificationZoneAirDistribution);
     REGISTER_COPYCONSTRUCTORS(DistrictCooling);
     REGISTER_COPYCONSTRUCTORS(DistrictHeating);
+    REGISTER_COPYCONSTRUCTORS(DistrictHeatingSteam);
     REGISTER_COPYCONSTRUCTORS(Duct);
     REGISTER_COPYCONSTRUCTORS(ElectricEquipment);
     REGISTER_COPYCONSTRUCTORS(ElectricEquipmentDefinition);
diff --git a/src/model/ModelStraightComponent.i b/src/model/ModelStraightComponent.i
index 88a9e3ba1a9..0cac744900a 100644
--- a/src/model/ModelStraightComponent.i
+++ b/src/model/ModelStraightComponent.i
@@ -148,6 +148,7 @@ MODELOBJECT_TEMPLATES(CoolingTowerTwoSpeed);
 MODELOBJECT_TEMPLATES(CoolingTowerVariableSpeed);
 MODELOBJECT_TEMPLATES(DistrictCooling);
 MODELOBJECT_TEMPLATES(DistrictHeating);
+MODELOBJECT_TEMPLATES(DistrictHeatingSteam);
 MODELOBJECT_TEMPLATES(Duct);
 MODELOBJECT_TEMPLATES(EvaporativeCoolerDirectResearchSpecial);
 MODELOBJECT_TEMPLATES(EvaporativeCoolerIndirectResearchSpecial);
@@ -234,6 +235,7 @@ SWIG_MODELOBJECT(CoolingTowerTwoSpeed,1);
 SWIG_MODELOBJECT(CoolingTowerVariableSpeed,1);
 SWIG_MODELOBJECT(DistrictCooling,1);
 SWIG_MODELOBJECT(DistrictHeating,1);
+SWIG_MODELOBJECT(DistrictHeatingSteam,1);
 SWIG_MODELOBJECT(Duct,1);
 SWIG_MODELOBJECT(EvaporativeCoolerDirectResearchSpecial,1);
 SWIG_MODELOBJECT(EvaporativeCoolerIndirectResearchSpecial,1);
diff --git a/src/model/ScheduleTypeRegistry.cpp b/src/model/ScheduleTypeRegistry.cpp
index 13c1ccba746..18ca483cfed 100644
--- a/src/model/ScheduleTypeRegistry.cpp
+++ b/src/model/ScheduleTypeRegistry.cpp
@@ -236,6 +236,9 @@ namespace model {
       {"DefaultScheduleSet", "Steam Equipment", "steamEquipmentSchedule", true, "", 0.0, 1.0},
       {"DefaultScheduleSet", "Other Equipment", "otherEquipmentSchedule", true, "", OptionalDouble(), OptionalDouble()},
       {"DesignSpecificationOutdoorAir", "Outdoor Air Flow Rate", "outdoorAirFlowRateFractionSchedule", true, "", 0.0, 1.0},
+      {"DistrictCooling", "Capacity Fraction", "capacityFractionSchedule", true, "Dimensionless", 0.0, OptionalDouble()},
+      {"DistrictHeating", "Capacity Fraction", "capacityFractionSchedule", true, "Dimensionless", 0.0, OptionalDouble()},
+      {"DistrictHeatingSteam", "Capacity Fraction", "capacityFractionSchedule", true, "Dimensionless", 0.0, OptionalDouble()},
       {"ElectricEquipment", "Electric Equipment", "schedule", true, "", 0.0, 1.0},
       {"ElectricEquipmentITEAirCooled", "Design Power Input", "designPowerInputSchedule", true, "", 0.0, 1.0},
       {"ElectricEquipmentITEAirCooled", "CPU Loading", "cPULoadingSchedule", true, "", 0.0, 1.0},
diff --git a/src/utilities/data/DataEnums.hpp b/src/utilities/data/DataEnums.hpp
index dbd7f1e3e74..bad3a878cbc 100644
--- a/src/utilities/data/DataEnums.hpp
+++ b/src/utilities/data/DataEnums.hpp
@@ -295,9 +295,9 @@ inline UTILITIES_API AppGFuelType convertFuelTypeToAppG(FuelType fuelType) {
     return AppGFuelType::Electric;
   } else if ((fuelType == FuelType::Gas) || (fuelType == FuelType::Gasoline) || (fuelType == FuelType::Diesel) || (fuelType == FuelType::Coal)
              || (fuelType == FuelType::FuelOil_1) || (fuelType == FuelType::FuelOil_2) || (fuelType == FuelType::Propane)
-             || (fuelType == FuelType::Steam) || (fuelType == FuelType::OtherFuel_1) || (fuelType == FuelType::OtherFuel_2)) {
+             || (fuelType == FuelType::OtherFuel_1) || (fuelType == FuelType::OtherFuel_2)) {
     return AppGFuelType::Fuel;
-  } else if ((fuelType == FuelType::DistrictCooling) || (fuelType == FuelType::DistrictHeating)) {
+  } else if ((fuelType == FuelType::DistrictCooling) || (fuelType == FuelType::DistrictHeating) || (fuelType == FuelType::Steam)) {
     return AppGFuelType::District;
   }
 


Test patch:
diff --git a/src/model/test/DistrictCooling_GTest.cpp b/src/model/test/DistrictCooling_GTest.cpp
index ca7a73c8c12..36cf53022c1 100644
--- a/src/model/test/DistrictCooling_GTest.cpp
+++ b/src/model/test/DistrictCooling_GTest.cpp
@@ -12,6 +12,10 @@
 #include "../Node.hpp"
 #include "../Node_Impl.hpp"
 #include "../AirLoopHVACZoneSplitter.hpp"
+#include "../Schedule.hpp"
+#include "../Schedule_Impl.hpp"
+#include "../ScheduleConstant.hpp"
+#include "../ScheduleConstant_Impl.hpp"
 
 using namespace openstudio;
 using namespace openstudio::model;
@@ -23,11 +27,28 @@ TEST_F(ModelFixture, DistrictCooling_DistrictCooling) {
   ASSERT_EXIT(
     {
       Model m;
-      DistrictCooling testObject(m);
+      DistrictCooling districtCooling(m);
 
       exit(0);
     },
     ::testing::ExitedWithCode(0), "");
+
+  Model m;
+  DistrictCooling districtCooling(m);
+
+  EXPECT_FALSE(districtCooling.nominalCapacity());
+  EXPECT_TRUE(districtCooling.isNominalCapacityAutosized());
+  EXPECT_FALSE(districtCooling.capacityFractionSchedule());
+
+  ScheduleConstant scheduleConstant(m);
+  scheduleConstant.setValue(0.5);
+  EXPECT_TRUE(districtCooling.setCapacityFractionSchedule(scheduleConstant));
+
+  ASSERT_TRUE(districtCooling.capacityFractionSchedule());
+  EXPECT_EQ(scheduleConstant, districtCooling.capacityFractionSchedule().get());
+
+  districtCooling.resetCapacityFractionSchedule();
+  EXPECT_FALSE(districtCooling.capacityFractionSchedule());
 }
 
 //test connecting the object to a loop and get the inlet node and the outlet node
@@ -38,29 +59,29 @@ TEST_F(ModelFixture, DistrictCooling_connections) {
   PlantLoop plantLoop(m);
 
   //make a DistrictCooling object
-  DistrictCooling testObject(m);
+  DistrictCooling districtCooling(m);
 
   //get the supply outlet node of the plant loop
   Node plantOutletNode = plantLoop.supplyOutletNode();
 
   //hook the DistrictCooling object to the supply outlet node
-  ASSERT_TRUE(testObject.addToNode(plantOutletNode));
+  ASSERT_TRUE(districtCooling.addToNode(plantOutletNode));
 
   //it should now be on a loop and have inlet and outlet objects
-  ASSERT_TRUE(testObject.loop());
-  ASSERT_TRUE(testObject.inletModelObject());
-  ASSERT_TRUE(testObject.outletModelObject());
+  ASSERT_TRUE(districtCooling.loop());
+  ASSERT_TRUE(districtCooling.inletModelObject());
+  ASSERT_TRUE(districtCooling.outletModelObject());
 
   //it should be removable from the loop
-  ASSERT_TRUE(testObject.isRemovable());
+  ASSERT_TRUE(districtCooling.isRemovable());
 
   //now, disconnect the object
-  testObject.disconnect();
+  districtCooling.disconnect();
 
   //it should no longer have a loop or inlet/outlet objects
-  ASSERT_FALSE(testObject.loop());
-  ASSERT_FALSE(testObject.inletModelObject());
-  ASSERT_FALSE(testObject.outletModelObject());
+  ASSERT_FALSE(districtCooling.loop());
+  ASSERT_FALSE(districtCooling.inletModelObject());
+  ASSERT_FALSE(districtCooling.outletModelObject());
 
   //make an airloop
   AirLoopHVAC airLoop(m);
@@ -69,41 +90,45 @@ TEST_F(ModelFixture, DistrictCooling_connections) {
   Node airOutletNode = airLoop.supplyOutletNode();
 
   //it should not connect to an airloop
-  ASSERT_FALSE(testObject.addToNode(airOutletNode));
+  ASSERT_FALSE(districtCooling.addToNode(airOutletNode));
 }
 
 //test setting and getting the nominal capacity
 TEST_F(ModelFixture, DistrictCooling_NominalCapacity) {
   Model m;
-  DistrictCooling testObject(m);
+  DistrictCooling districtCooling(m);
 
   //test setting and getting the field with a double
   double testValue(1);
-  testObject.setNominalCapacity(testValue);
-  auto capacity = testObject.nominalCapacity();
+  districtCooling.setNominalCapacity(testValue);
+  auto capacity = districtCooling.nominalCapacity();
   ASSERT_TRUE(capacity);
   ASSERT_EQ(1, capacity.get());
+
+  EXPECT_FALSE(districtCooling.isNominalCapacityAutosized());
+  districtCooling.autosizeNominalCapacity();
+  EXPECT_TRUE(districtCooling.isNominalCapacityAutosized());
 }
 
 //test cloning the object
 TEST_F(ModelFixture, DistrictCooling_Clone) {
   Model m;
   //make an object to clone, and edit some property to make sure the clone worked
-  DistrictCooling testObject(m);
+  DistrictCooling districtCooling(m);
 
-  testObject.setNominalCapacity(1234);
+  districtCooling.setNominalCapacity(1234);
 
   //clone into the same model
-  auto testObjectClone = testObject.clone(m).cast<DistrictCooling>();
-  auto capacity = testObjectClone.nominalCapacity();
+  auto districtCoolingClone = districtCooling.clone(m).cast<DistrictCooling>();
+  auto capacity = districtCoolingClone.nominalCapacity();
   ASSERT_TRUE(capacity);
   ASSERT_EQ(1234, capacity.get());
 
   //clone into another model
   Model m2;
-  auto testObjectClone2 = testObject.clone(m2).cast<DistrictCooling>();
+  auto districtCoolingClone2 = districtCooling.clone(m2).cast<DistrictCooling>();
 
-  capacity = testObjectClone2.nominalCapacity();
+  capacity = districtCoolingClone2.nominalCapacity();
   ASSERT_TRUE(capacity);
   ASSERT_EQ(1234, capacity.get());
 }
diff --git a/src/model/test/DistrictHeatingSteam_GTest.cpp b/src/model/test/DistrictHeatingSteam_GTest.cpp
new file mode 100644
index 00000000000..0eb828a91a8
--- /dev/null
+++ b/src/model/test/DistrictHeatingSteam_GTest.cpp
@@ -0,0 +1,176 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
+*  See also https://openstudio.net/license
+***********************************************************************************************************************/
+
+#include <gtest/gtest.h>
+#include "ModelFixture.hpp"
+#include "../DistrictHeatingSteam.hpp"
+#include "../DistrictHeatingSteam_Impl.hpp"
+#include "../AirLoopHVAC.hpp"
+#include "../PlantLoop.hpp"
+#include "../Node.hpp"
+#include "../Node_Impl.hpp"
+#include "../AirLoopHVACZoneSplitter.hpp"
+#include "../Schedule.hpp"
+#include "../Schedule_Impl.hpp"
+#include "../ScheduleConstant.hpp"
+#include "../ScheduleConstant_Impl.hpp"
+
+using namespace openstudio;
+using namespace openstudio::model;
+
+//test construction of the object
+TEST_F(ModelFixture, DistrictHeatingSteam_DistrictHeatingSteam) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  ASSERT_EXIT(
+    {
+      Model m;
+      DistrictHeatingSteam districtHeatingSteam(m);
+
+      exit(0);
+    },
+    ::testing::ExitedWithCode(0), "");
+
+  Model m;
+  DistrictHeatingSteam districtHeatingSteam(m);
+
+  EXPECT_FALSE(districtHeatingSteam.nominalCapacity());
+  EXPECT_TRUE(districtHeatingSteam.isNominalCapacityAutosized());
+  EXPECT_FALSE(districtHeatingSteam.capacityFractionSchedule());
+
+  ScheduleConstant scheduleConstant(m);
+  scheduleConstant.setValue(0.5);
+  EXPECT_TRUE(districtHeatingSteam.setCapacityFractionSchedule(scheduleConstant));
+
+  ASSERT_TRUE(districtHeatingSteam.capacityFractionSchedule());
+  EXPECT_EQ(scheduleConstant, districtHeatingSteam.capacityFractionSchedule().get());
+
+  districtHeatingSteam.resetCapacityFractionSchedule();
+  EXPECT_FALSE(districtHeatingSteam.capacityFractionSchedule());
+}
+
+//test connecting the object to a loop and get the inlet node and the outlet node
+TEST_F(ModelFixture, DistrictHeatingSteam_connections) {
+  Model m;
+
+  //make a plant loop
+  PlantLoop plantLoop(m);
+
+  //make a districtHeatingSteam object
+  DistrictHeatingSteam districtHeatingSteam(m);
+
+  //get the supply outlet node of the plant loop
+  Node plantOutletNode = plantLoop.supplyOutletNode();
+
+  //hook the districtHeatingSteam object to the supply outlet node
+  ASSERT_TRUE(districtHeatingSteam.addToNode(plantOutletNode));
+
+  //it should now be on a loop and have inlet and outlet objects
+  ASSERT_TRUE(districtHeatingSteam.loop());
+  ASSERT_TRUE(districtHeatingSteam.inletModelObject());
+  ASSERT_TRUE(districtHeatingSteam.outletModelObject());
+
+  //it should be removable from the loop
+  ASSERT_TRUE(districtHeatingSteam.isRemovable());
+
+  //now, disconnect the object
+  districtHeatingSteam.disconnect();
+
+  //it should no longer have a loop or inlet/outlet objects
+  ASSERT_FALSE(districtHeatingSteam.loop());
+  ASSERT_FALSE(districtHeatingSteam.inletModelObject());
+  ASSERT_FALSE(districtHeatingSteam.outletModelObject());
+
+  //make an airloop
+  AirLoopHVAC airLoop(m);
+
+  //get the supply outlet node of the airloop
+  Node airOutletNode = airLoop.supplyOutletNode();
+
+  //it should not connect to an airloop
+  ASSERT_FALSE(districtHeatingSteam.addToNode(airOutletNode));
+}
+
+//test setting and getting the nominal capacity
+TEST_F(ModelFixture, DistrictHeatingSteam_NominalCapacity) {
+
+  Model m;
+  DistrictHeatingSteam districtHeatingSteam(m);
+
+  //test setting and getting the field with a double
+  double testValue(1);
+
+  districtHeatingSteam.setNominalCapacity(testValue);
+
+  auto capacity = districtHeatingSteam.nominalCapacity();
+  ASSERT_TRUE(capacity);
+  ASSERT_EQ(1, capacity.get());
+
+  EXPECT_FALSE(districtHeatingSteam.isNominalCapacityAutosized());
+  districtHeatingSteam.autosizeNominalCapacity();
+  EXPECT_TRUE(districtHeatingSteam.isNominalCapacityAutosized());
+}
+
+//test cloning the object
+TEST_F(ModelFixture, DistrictHeatingSteam_Clone) {
+
+  Model m;
+
+  //make an object to clone, and edit some property to make sure the clone worked
+
+  DistrictHeatingSteam districtHeatingSteam(m);
+
+  districtHeatingSteam.setNominalCapacity(1234);
+
+  //clone into the same model
+
+  auto districtHeatingClone = districtHeatingSteam.clone(m).cast<DistrictHeatingSteam>();
+
+  auto capacity = districtHeatingClone.nominalCapacity();
+  ASSERT_TRUE(capacity);
+  ASSERT_EQ(1234, capacity.get());
+
+  //clone into another model
+
+  Model m2;
+
+  auto districtHeatingClone2 = districtHeatingSteam.clone(m2).cast<DistrictHeatingSteam>();
+
+  capacity = districtHeatingClone2.nominalCapacity();
+  ASSERT_TRUE(capacity);
+  ASSERT_EQ(1234, capacity.get());
+}
+
+TEST_F(ModelFixture, DistrictHeatingSteam_addToNode) {
+  Model m;
+  DistrictHeatingSteam testObject(m);
+
+  AirLoopHVAC airLoop(m);
+
+  Node supplyOutletNode = airLoop.supplyOutletNode();
+
+  EXPECT_FALSE(testObject.addToNode(supplyOutletNode));
+  EXPECT_EQ((unsigned)2, airLoop.supplyComponents().size());
+
+  Node inletNode = airLoop.zoneSplitter().lastOutletModelObject()->cast<Node>();
+
+  EXPECT_FALSE(testObject.addToNode(inletNode));
+  EXPECT_EQ((unsigned)5, airLoop.demandComponents().size());
+
+  PlantLoop plantLoop(m);
+  supplyOutletNode = plantLoop.supplyOutletNode();
+  EXPECT_TRUE(testObject.addToNode(supplyOutletNode));
+  EXPECT_EQ((unsigned)7, plantLoop.supplyComponents().size());
+
+  Node demandOutletNode = plantLoop.demandOutletNode();
+  EXPECT_FALSE(testObject.addToNode(demandOutletNode));
+  EXPECT_EQ((unsigned)5, plantLoop.demandComponents().size());
+
+  auto testObjectClone = testObject.clone(m).cast<DistrictHeatingSteam>();
+  supplyOutletNode = plantLoop.supplyOutletNode();
+
+  EXPECT_TRUE(testObjectClone.addToNode(supplyOutletNode));
+  EXPECT_EQ((unsigned)9, plantLoop.supplyComponents().size());
+}
diff --git a/src/model/test/DistrictHeating_GTest.cpp b/src/model/test/DistrictHeating_GTest.cpp
index 0a8097c85c2..179c7a9ccb2 100644
--- a/src/model/test/DistrictHeating_GTest.cpp
+++ b/src/model/test/DistrictHeating_GTest.cpp
@@ -12,6 +12,10 @@
 #include "../Node.hpp"
 #include "../Node_Impl.hpp"
 #include "../AirLoopHVACZoneSplitter.hpp"
+#include "../Schedule.hpp"
+#include "../Schedule_Impl.hpp"
+#include "../ScheduleConstant.hpp"
+#include "../ScheduleConstant_Impl.hpp"
 
 using namespace openstudio;
 using namespace openstudio::model;
@@ -28,6 +32,23 @@ TEST_F(ModelFixture, DistrictHeating_DistrictHeating) {
       exit(0);
     },
     ::testing::ExitedWithCode(0), "");
+
+  Model m;
+  DistrictHeating districtHeating(m);
+
+  EXPECT_FALSE(districtHeating.nominalCapacity());
+  EXPECT_TRUE(districtHeating.isNominalCapacityAutosized());
+  EXPECT_FALSE(districtHeating.capacityFractionSchedule());
+
+  ScheduleConstant scheduleConstant(m);
+  scheduleConstant.setValue(0.5);
+  EXPECT_TRUE(districtHeating.setCapacityFractionSchedule(scheduleConstant));
+
+  ASSERT_TRUE(districtHeating.capacityFractionSchedule());
+  EXPECT_EQ(scheduleConstant, districtHeating.capacityFractionSchedule().get());
+
+  districtHeating.resetCapacityFractionSchedule();
+  EXPECT_FALSE(districtHeating.capacityFractionSchedule());
 }
 
 //test connecting the object to a loop and get the inlet node and the outlet node
@@ -87,7 +108,9 @@ TEST_F(ModelFixture, DistrictHeating_NominalCapacity) {
   ASSERT_TRUE(capacity);
   ASSERT_EQ(1, capacity.get());
 
-  //test setting and getting the field with a quantity
+  EXPECT_FALSE(districtHeating.isNominalCapacityAutosized());
+  districtHeating.autosizeNominalCapacity();
+  EXPECT_TRUE(districtHeating.isNominalCapacityAutosized());
 }
 
 //test cloning the object