Repository: NREL/OpenStudio (language: python)

Issue:
Wrap phase change material properties
Enhancement Request
--------------
Wrap [MaterialProperty:PhaseChange](https://bigladdersoftware.com/epx/docs/9-6/input-output-reference/group-surface-construction-elements.html#materialpropertyphasechange) and [MaterialProperty:PhaseChangeHysteresis](https://bigladdersoftware.com/epx/docs/9-6/input-output-reference/group-surface-construction-elements.html#materialpropertyphasechangehysteresis) objects.

## Possible Implementation
Probably very similar to [OS:MaterialProperty:MoisturePenetrationDepth:Settings](https://github.com/NREL/OpenStudio/blob/f3fba80d69e8fd6f0d9352951ab967c0bacda39a/src/model/MaterialPropertyMoisturePenetrationDepthSettings.cpp)
Wrap phase change material properties
Enhancement Request
--------------
Wrap [MaterialProperty:PhaseChange](https://bigladdersoftware.com/epx/docs/9-6/input-output-reference/group-surface-construction-elements.html#materialpropertyphasechange) and [MaterialProperty:PhaseChangeHysteresis](https://bigladdersoftware.com/epx/docs/9-6/input-output-reference/group-surface-construction-elements.html#materialpropertyphasechangehysteresis) objects.

## Possible Implementation
Probably very similar to [OS:MaterialProperty:MoisturePenetrationDepth:Settings](https://github.com/NREL/OpenStudio/blob/f3fba80d69e8fd6f0d9352951ab967c0bacda39a/src/model/MaterialPropertyMoisturePenetrationDepthSettings.cpp)


Discussion / hints:
[Here](https://github.com/NREL/OpenStudio/pull/2828) is the original PR for `OS:MaterialProperty:MoisturePenetrationDepth:Settings`.
[Here](https://github.com/NREL/OpenStudio/pull/2828) is the original PR for `OS:MaterialProperty:MoisturePenetrationDepth:Settings`.

Fix patch:
diff --git a/developer/ruby/SubProjectClassGenerators/TranslatorGenerator.rb b/developer/ruby/SubProjectClassGenerators/TranslatorGenerator.rb
index 604c22c4967..391a9b54537 100644
--- a/developer/ruby/SubProjectClassGenerators/TranslatorGenerator.rb
+++ b/developer/ruby/SubProjectClassGenerators/TranslatorGenerator.rb
@@ -418,8 +418,7 @@ def generateForwardTranslateFunction()
     end # End loop on nonextensibleFields
 
     # Assign result and return
-    result << "  result = IdfObject;\n"
-    result << "  return result;\n"
+    result << "  return idfObject;\n"
 
     # Close method
     result << "} // End of translate function\n"
diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd
index 26e69b1d6b9..8bfc81cf7eb 100644
--- a/resources/model/OpenStudio.idd
+++ b/resources/model/OpenStudio.idd
@@ -2066,6 +2066,7 @@ OS:Material,
        \type alpha
        \required-field
        \reference MaterialNames
+       \reference MaterialWithPropertyNames
   A3, \field Roughness
        \type choice
        \required-field
@@ -2166,6 +2167,7 @@ OS:Material:NoMass,
        \type alpha
        \required-field
        \reference MaterialNames
+       \reference MaterialWithPropertyNames
   A3, \field Roughness
        \type choice
        \required-field
@@ -3196,7 +3198,7 @@ OS:MaterialProperty:MoisturePenetrationDepth:Settings,
   A2,  \field Material Name
        \required-field
        \type object-list
-       \object-list MaterialNames
+       \object-list MaterialWithPropertyNames
        \note Material Name that the moisture properties will be added to.
        \note Additional material properties required to perform the EMPD model.
        \note Effective Mean Penetration Depth (EMPD)
@@ -3252,6 +3254,135 @@ OS:MaterialProperty:MoisturePenetrationDepth:Settings,
        \note resistance to water vapor diffusion in stagnant air
        \note (see Water Vapor Diffusion Resistance Factor above).
 
+OS:MaterialProperty:PhaseChange,
+       \memo Additional properties for temperature dependent thermal conductivity
+       \memo and enthalpy for Phase Change Materials (PCM)
+       \memo HeatBalanceAlgorithm = CondFD(ConductionFiniteDifference) solution algorithm only.
+       \memo Constructions with this should use the detailed CondFD process.
+       \memo Has no effect with other HeatBalanceAlgorithm solution algorithms
+       \extensible:2
+       \max-fields 35
+  A1,  \field Handle
+       \type handle
+       \required-field
+  A2,  \field Material Name
+       \required-field
+       \type object-list
+       \object-list MaterialWithPropertyNames
+       \note Regular Material Name to which the additional properties will be added.
+       \note this the material name for the basic material properties.
+  N1,  \field Temperature Coefficient for Thermal Conductivity
+       \note The base temperature is 20C.
+       \note This is the thermal conductivity change per degree excursion from 20C.
+       \note This variable conductivity function is overridden by the VariableThermalConductivity object, if present.
+       \units W/m-K2
+       \type real
+       \default 0.0
+  N2,  \field Temperature
+       \required-field
+       \note for Temperature-enthalpy function
+       \units C
+       \type real
+       \begin-extensible
+  N3;  \field Enthalpy
+       \required-field
+       \note for Temperature-enthalpy function corresponding to temperature 1
+       \units J/kg
+
+OS:MaterialProperty:PhaseChangeHysteresis,
+       \memo Additional properties for temperature dependent thermal conductivity
+       \memo and enthalpy for Phase Change Materials (PCM) with separate melting and freezing curves.
+       \memo HeatBalanceAlgorithm = CondFD (ConductionFiniteDifference) solution algorithm only.
+       \memo Constructions with this should use the detailed CondFD process.
+       \memo Has no effect with other HeatBalanceAlgorithm solution algorithms.
+  A1,  \field Handle
+       \type handle
+       \required-field
+  A2,  \field Material Name
+       \required-field
+       \type object-list
+       \object-list MaterialWithPropertyNames
+       \note Regular Material Name to which the additional properties will be added.
+       \note this the material name for the basic material properties.
+  N1,  \field Latent Heat during the Entire Phase Change Process
+       \note The total latent heat absorbed or rejected during the transition from solid to liquid, or back
+       \required-field
+       \units J/kg
+       \type real
+       \minimum> 0
+  N2,  \field Liquid State Thermal Conductivity
+       \note The thermal conductivity used by this material when the material is fully liquid
+       \required-field
+       \units W/m-K
+       \type real
+       \minimum> 0
+  N3,  \field Liquid State Density
+       \note The density used by this material when the material is fully liquid
+       \required-field
+       \units kg/m3
+       \type real
+       \minimum> 0
+  N4,  \field Liquid State Specific Heat
+       \note The constant specific heat used for the fully melted (liquid) state
+       \required-field
+       \units J/kg-K
+       \type real
+       \minimum> 0
+  N5,  \field High Temperature Difference of Melting Curve
+       \note The total melting range of the material is the sum of low and high temperature difference of melting curve.
+       \required-field
+       \units deltaC
+       \type real
+       \minimum> 0
+  N6,  \field Peak Melting Temperature
+       \note The temperature at which the melting curve peaks
+       \required-field
+       \units C
+       \type real
+       \minimum> 0
+  N7,  \field Low Temperature Difference of Melting Curve
+       \note The total melting range of the material is the sum of low and high temperature difference of melting curve.
+       \required-field
+       \units deltaC
+       \type real
+       \minimum> 0
+  N8,  \field Solid State Thermal Conductivity
+       \note The thermal conductivity used by this material when the material is fully solid
+       \required-field
+       \units W/m-K
+       \type real
+       \minimum> 0
+  N9,  \field Solid State Density
+       \note The density used by this material when the material is fully solid
+       \required-field
+       \units kg/m3
+       \type real
+       \minimum> 0
+  N10, \field Solid State Specific Heat
+       \note The constant specific heat used for the fully frozen (crystallized) state
+       \required-field
+       \units J/kg-K
+       \type real
+       \minimum> 0
+  N11, \field High Temperature Difference of Freezing Curve
+       \note The total freezing range of the material is the sum of low and high temperature difference of freezing curve.
+       \required-field
+       \units deltaC
+       \type real
+       \minimum> 0
+  N12, \field Peak Freezing Temperature
+       \note The temperature at which the freezing curve peaks
+       \required-field
+       \units C
+       \type real
+       \minimum> 0
+  N13; \field Low Temperature Difference of Freezing Curve
+       \note The total freezing range of the material is the sum of low and high temperature difference of freezing curve.
+       \required-field
+       \units deltaC
+       \type real
+       \minimum> 0
+
 \group OpenStudio Constructions
 
 OS:Construction,
diff --git a/src/energyplus/CMakeLists.txt b/src/energyplus/CMakeLists.txt
index 5cc169ab01e..64d9c284a8c 100644
--- a/src/energyplus/CMakeLists.txt
+++ b/src/energyplus/CMakeLists.txt
@@ -239,6 +239,8 @@ set(${target_name}_src
   ForwardTranslator/ForwardTranslateLuminaire.cpp
   ForwardTranslator/ForwardTranslateMaterialPropertyGlazingSpectralData.cpp
   ForwardTranslator/ForwardTranslateMaterialPropertyMoisturePenetrationDepthSettings.cpp
+  ForwardTranslator/ForwardTranslateMaterialPropertyPhaseChange.cpp
+  ForwardTranslator/ForwardTranslateMaterialPropertyPhaseChangeHysteresis.cpp
   ForwardTranslator/ForwardTranslateMasslessOpaqueMaterial.cpp
   ForwardTranslator/ForwardTranslateMeterCustom.cpp
   ForwardTranslator/ForwardTranslateMeterCustomDecrement.cpp
@@ -646,9 +648,7 @@ set(${target_name}_test_src
   Test/AvailabilityManagerNightCycle_GTest.cpp
   Test/AvailabilityManagerHybridVentilation_GTest.cpp
   Test/Building_GTest.cpp
-
   Test/CentralHeatPumpSystem_GTest.cpp
-
   Test/CoilCoolingDX_GTest.cpp
   Test/CoilCoolingDXCurveFitPerformance_GTest.cpp
   Test/CoilCoolingDXCurveFitOperatingMode_GTest.cpp
@@ -680,6 +680,7 @@ set(${target_name}_test_src
   Test/ElectricLoadCenterStorageLiIonNMCBattery_GTest.cpp
   Test/ElectricLoadCenterTransformer_GTest.cpp
   Test/EMS_GTest.cpp
+  Test/EnvironmentalImpactFactors_GTest.cpp
   Test/EvaporativeCoolerDirectResearchSpecial_GTest.cpp
   Test/ExteriorLights_GTest.cpp
   Test/ExteriorFuelEquipment_GTest.cpp
@@ -690,6 +691,7 @@ set(${target_name}_test_src
   Test/FanVariableVolume_GTest.cpp
   Test/FanSystemModel_GTest.cpp
   Test/FuelCell_GTest.cpp
+  Test/FuelFactors_GTest.cpp
   Test/GasEquipment_GTest.cpp
   Test/GeneratorMicroTurbine_GTest.cpp
   Test/GeneratorWindTurbine_GTest.cpp
@@ -705,14 +707,15 @@ set(${target_name}_test_src
   Test/LifeCycleCostParameters_GTest.cpp
   Test/Lights_GTest.cpp
   Test/Luminaire_GTest.cpp
+  Test/MaterialPropertyMoisturePenetrationDepthSettings_GTest.cpp
+  Test/MaterialPropertyPhaseChange_GTest.cpp
+  Test/MaterialPropertyPhaseChangeHysteresis_GTest.cpp
   Test/Meter_GTest.cpp
   Test/OutputControlFiles_GTest.cpp
   Test/OutputDebuggingData_GTest.cpp
   Test/OutputDiagnostics_GTest.cpp
   Test/OutputJSON_GTest.cpp
   Test/OutputEnvironmentalImpactFactors_GTest.cpp
-  Test/EnvironmentalImpactFactors_GTest.cpp
-  Test/FuelFactors_GTest.cpp
   Test/OutputTableSummaryReports_GTest.cpp
   Test/People_GTest.cpp
   Test/PhotovoltaicPerformanceSandia_GTest.cpp
diff --git a/src/energyplus/ForwardTranslator.cpp b/src/energyplus/ForwardTranslator.cpp
index 527521a7321..760664f1545 100644
--- a/src/energyplus/ForwardTranslator.cpp
+++ b/src/energyplus/ForwardTranslator.cpp
@@ -2161,6 +2161,16 @@ namespace energyplus {
         retVal = translateMaterialPropertyMoisturePenetrationDepthSettings(empd);
         break;
       }
+      case openstudio::IddObjectType::OS_MaterialProperty_PhaseChange: {
+        model::MaterialPropertyPhaseChange phaseChange = modelObject.cast<MaterialPropertyPhaseChange>();
+        retVal = translateMaterialPropertyPhaseChange(phaseChange);
+        break;
+      }
+      case openstudio::IddObjectType::OS_MaterialProperty_PhaseChangeHysteresis: {
+        model::MaterialPropertyPhaseChangeHysteresis phaseChangeHysteresis = modelObject.cast<MaterialPropertyPhaseChangeHysteresis>();
+        retVal = translateMaterialPropertyPhaseChangeHysteresis(phaseChangeHysteresis);
+        break;
+      }
       case openstudio::IddObjectType::OS_Material_RoofVegetation: {
         model::RoofVegetation material = modelObject.cast<RoofVegetation>();
         retVal = translateRoofVegetation(material);
@@ -3530,7 +3540,6 @@ namespace energyplus {
   void ForwardTranslator::translateConstructions(const model::Model& model) {
     std::vector<IddObjectType> iddObjectTypes;
     iddObjectTypes.push_back(IddObjectType::OS_MaterialProperty_GlazingSpectralData);
-    iddObjectTypes.push_back(IddObjectType::OS_MaterialProperty_MoisturePenetrationDepth_Settings);
     iddObjectTypes.push_back(IddObjectType::OS_Material);
     iddObjectTypes.push_back(IddObjectType::OS_Material_AirGap);
     iddObjectTypes.push_back(IddObjectType::OS_Material_AirWall);
@@ -3565,11 +3574,14 @@ namespace energyplus {
     iddObjectTypes.push_back(IddObjectType::OS_DefaultScheduleSet);
 
     // Translated by the object it references directly
-    //iddObjectTypes.push_back(IddObjectType::OS_SurfaceControl_MovableInsulation);           // Surface Only
-    //iddObjectTypes.push_back(IddObjectType::OS_SurfaceProperty_OtherSideCoefficients);      // Surface, SubSurface,
-    //iddObjectTypes.push_back(IddObjectType::OS_SurfaceProperty_OtherSideConditionsModel);   // Surface, SubSurface,
-    //iddObjectTypes.push_back(IddObjectType::OS_SurfaceProperty_ExposedFoundationPerimeter); // Surface Only
-    //iddObjectTypes.push_back(IddObjectType::OS_SurfaceProperty_ConvectionCoefficients);     // Surface, SubSurface, or InternalMass
+    //iddObjectTypes.push_back(IddObjectType::OS_MaterialProperty_MoisturePenetrationDepth_Settings); // Material Only
+    //iddObjectTypes.push_back(IddObjectType::OS_MaterialProperty_PhaseChange);                       // Material Only
+    //iddObjectTypes.push_back(IddObjectType::OS_MaterialProperty_PhaseChangeHysteresis);             // Material Only
+    //iddObjectTypes.push_back(IddObjectType::OS_SurfaceControl_MovableInsulation);                   // Surface Only
+    //iddObjectTypes.push_back(IddObjectType::OS_SurfaceProperty_OtherSideCoefficients);              // Surface, SubSurface,
+    //iddObjectTypes.push_back(IddObjectType::OS_SurfaceProperty_OtherSideConditionsModel);           // Surface, SubSurface,
+    //iddObjectTypes.push_back(IddObjectType::OS_SurfaceProperty_ExposedFoundationPerimeter);         // Surface Only
+    //iddObjectTypes.push_back(IddObjectType::OS_SurfaceProperty_ConvectionCoefficients);             // Surface, SubSurface, or InternalMass
 
     for (const IddObjectType& iddObjectType : iddObjectTypes) {
 
diff --git a/src/energyplus/ForwardTranslator.hpp b/src/energyplus/ForwardTranslator.hpp
index 8d9a91877dc..1f29c5710f7 100644
--- a/src/energyplus/ForwardTranslator.hpp
+++ b/src/energyplus/ForwardTranslator.hpp
@@ -296,6 +296,8 @@ namespace model {
   class Luminaire;
   class MaterialPropertyGlazingSpectralData;
   class MaterialPropertyMoisturePenetrationDepthSettings;
+  class MaterialPropertyPhaseChange;
+  class MaterialPropertyPhaseChangeHysteresis;
   class MasslessOpaqueMaterial;
   class MeterCustom;
   class MeterCustomDecrement;
@@ -1114,6 +1116,10 @@ namespace energyplus {
     boost::optional<IdfObject>
       translateMaterialPropertyMoisturePenetrationDepthSettings(model::MaterialPropertyMoisturePenetrationDepthSettings& modelObject);
 
+    boost::optional<IdfObject> translateMaterialPropertyPhaseChange(model::MaterialPropertyPhaseChange& modelObject);
+
+    boost::optional<IdfObject> translateMaterialPropertyPhaseChangeHysteresis(model::MaterialPropertyPhaseChangeHysteresis& modelObject);
+
     boost::optional<IdfObject> translateMasslessOpaqueMaterial(model::MasslessOpaqueMaterial& modelObject);
 
     boost::optional<IdfObject> translateMeterCustom(model::MeterCustom& modelObject);
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateMasslessOpaqueMaterial.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateMasslessOpaqueMaterial.cpp
index 5af11ec4260..38376288f12 100644
--- a/src/energyplus/ForwardTranslator/ForwardTranslateMasslessOpaqueMaterial.cpp
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateMasslessOpaqueMaterial.cpp
@@ -32,6 +32,12 @@
 #include "../../model/Model.hpp"
 #include "../../model/MasslessOpaqueMaterial.hpp"
 #include "../../model/MasslessOpaqueMaterial_Impl.hpp"
+#include "../../model/MaterialPropertyMoisturePenetrationDepthSettings.hpp"
+#include "../../model/MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp"
+#include "../../model/MaterialPropertyPhaseChange.hpp"
+#include "../../model/MaterialPropertyPhaseChange_Impl.hpp"
+#include "../../model/MaterialPropertyPhaseChangeHysteresis.hpp"
+#include "../../model/MaterialPropertyPhaseChangeHysteresis_Impl.hpp"
 
 #include <utilities/idd/Material_NoMass_FieldEnums.hxx>
 #include "../../utilities/idd/IddEnums.hpp"
@@ -71,6 +77,21 @@ namespace energyplus {
       idfObject.setDouble(openstudio::Material_NoMassFields::VisibleAbsorptance, *d);
     }
 
+    // Call the translation of these objects, which has two advantages:
+    // * will not translate them if they are orphaned (=not referencing a material), and,
+    // * makes the order of these objects in the IDF deterministic
+    if (boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> _empd = modelObject.materialPropertyMoisturePenetrationDepthSettings()) {
+      translateAndMapModelObject(_empd.get());
+    }
+
+    if (boost::optional<MaterialPropertyPhaseChange> _phaseChange = modelObject.materialPropertyPhaseChange()) {
+      translateAndMapModelObject(_phaseChange.get());
+    }
+
+    if (boost::optional<MaterialPropertyPhaseChangeHysteresis> _phaseChangeHysteresis = modelObject.materialPropertyPhaseChangeHysteresis()) {
+      translateAndMapModelObject(_phaseChangeHysteresis.get());
+    }
+
     return boost::optional<IdfObject>(idfObject);
   }
 
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateMaterialPropertyMoisturePenetrationDepthSettings.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateMaterialPropertyMoisturePenetrationDepthSettings.cpp
index 3e47ef7d430..6ab4f25806f 100644
--- a/src/energyplus/ForwardTranslator/ForwardTranslateMaterialPropertyMoisturePenetrationDepthSettings.cpp
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateMaterialPropertyMoisturePenetrationDepthSettings.cpp
@@ -32,6 +32,8 @@
 #include "../../model/Model.hpp"
 #include "../../model/MaterialPropertyMoisturePenetrationDepthSettings.hpp"
 #include "../../model/MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp"
+#include "../../model/Material.hpp"
+#include "../../model/Material_Impl.hpp"
 
 #include <utilities/idd/MaterialProperty_MoisturePenetrationDepth_Settings_FieldEnums.hxx>
 #include "../../utilities/idd/IddEnums.hpp"
@@ -47,11 +49,9 @@ namespace energyplus {
 
   boost::optional<IdfObject>
     ForwardTranslator::translateMaterialPropertyMoisturePenetrationDepthSettings(MaterialPropertyMoisturePenetrationDepthSettings& modelObject) {
-    IdfObject idfObject(openstudio::IddObjectType::MaterialProperty_MoisturePenetrationDepth_Settings);
+    IdfObject idfObject = createAndRegisterIdfObject(openstudio::IddObjectType::MaterialProperty_MoisturePenetrationDepth_Settings, modelObject);
 
-    m_idfObjects.push_back(idfObject);
-
-    idfObject.setString(MaterialProperty_MoisturePenetrationDepth_SettingsFields::Name, modelObject.materialName());
+    idfObject.setString(MaterialProperty_MoisturePenetrationDepth_SettingsFields::Name, modelObject.material().nameString());
 
     idfObject.setDouble(MaterialProperty_MoisturePenetrationDepth_SettingsFields::WaterVaporDiffusionResistanceFactor,
                         modelObject.waterVaporDiffusionResistanceFactor());
@@ -87,7 +87,7 @@ namespace energyplus {
     idfObject.setDouble(MaterialProperty_MoisturePenetrationDepth_SettingsFields::CoatingLayerWaterVaporDiffusionResistanceFactor,
                         modelObject.coatingLayerWaterVaporDiffusionResistanceFactor());
 
-    return boost::optional<IdfObject>(idfObject);
+    return idfObject;
   }
 
 }  // namespace energyplus
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateMaterialPropertyPhaseChange.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateMaterialPropertyPhaseChange.cpp
new file mode 100644
index 00000000000..4d3ef88bc7b
--- /dev/null
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateMaterialPropertyPhaseChange.cpp
@@ -0,0 +1,79 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include "../ForwardTranslator.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/MaterialPropertyPhaseChange.hpp"
+#include "../../model/MaterialPropertyPhaseChange_Impl.hpp"
+#include "../../model/Material.hpp"
+#include "../../model/Material_Impl.hpp"
+
+#include "../../utilities/idf/IdfExtensibleGroup.hpp"
+
+#include <utilities/idd/MaterialProperty_PhaseChange_FieldEnums.hxx>
+#include "../../utilities/idd/IddEnums.hpp"
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::model;
+
+using namespace std;
+
+namespace openstudio {
+
+namespace energyplus {
+
+  boost::optional<IdfObject> ForwardTranslator::translateMaterialPropertyPhaseChange(MaterialPropertyPhaseChange& modelObject) {
+    if (modelObject.temperatureEnthalpys().size() < 4) {
+      LOG(Warn, modelObject.briefDescription() << " cannot be translated as it has less than 4 temperature-enthalpy pairs.");
+      return boost::none;
+    }
+
+    IdfObject idfObject = createAndRegisterIdfObject(openstudio::IddObjectType::MaterialProperty_PhaseChange, modelObject);
+
+    idfObject.setString(MaterialProperty_PhaseChangeFields::Name, modelObject.material().nameString());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeFields::TemperatureCoefficientforThermalConductivity,
+                        modelObject.temperatureCoefficientforThermalConductivity());
+
+    std::vector<TemperatureEnthalpy> temperatureEnthalpys = modelObject.temperatureEnthalpys();
+    if (!temperatureEnthalpys.empty()) {
+      for (const TemperatureEnthalpy& temperatureEnthalpy : temperatureEnthalpys) {
+        auto eg = idfObject.pushExtensibleGroup();
+        eg.setDouble(MaterialProperty_PhaseChangeExtensibleFields::Temperature, temperatureEnthalpy.temperature());
+        eg.setDouble(MaterialProperty_PhaseChangeExtensibleFields::Enthalpy, temperatureEnthalpy.enthalpy());
+      }
+    }
+
+    return idfObject;
+  }
+
+}  // namespace energyplus
+
+}  // namespace openstudio
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateMaterialPropertyPhaseChangeHysteresis.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateMaterialPropertyPhaseChangeHysteresis.cpp
new file mode 100644
index 00000000000..4f17a14467e
--- /dev/null
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateMaterialPropertyPhaseChangeHysteresis.cpp
@@ -0,0 +1,91 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include "../ForwardTranslator.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/MaterialPropertyPhaseChangeHysteresis.hpp"
+#include "../../model/MaterialPropertyPhaseChangeHysteresis_Impl.hpp"
+#include "../../model/Material.hpp"
+#include "../../model/Material_Impl.hpp"
+
+#include <utilities/idd/MaterialProperty_PhaseChangeHysteresis_FieldEnums.hxx>
+#include "../../utilities/idd/IddEnums.hpp"
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::model;
+
+using namespace std;
+
+namespace openstudio {
+
+namespace energyplus {
+
+  boost::optional<IdfObject> ForwardTranslator::translateMaterialPropertyPhaseChangeHysteresis(MaterialPropertyPhaseChangeHysteresis& modelObject) {
+    IdfObject idfObject = createAndRegisterIdfObject(openstudio::IddObjectType::MaterialProperty_PhaseChangeHysteresis, modelObject);
+
+    idfObject.setString(MaterialProperty_PhaseChangeHysteresisFields::Name, modelObject.material().nameString());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeHysteresisFields::LatentHeatduringtheEntirePhaseChangeProcess,
+                        modelObject.latentHeatduringtheEntirePhaseChangeProcess());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeHysteresisFields::LiquidStateThermalConductivity, modelObject.liquidStateThermalConductivity());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeHysteresisFields::LiquidStateDensity, modelObject.liquidStateDensity());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeHysteresisFields::LiquidStateSpecificHeat, modelObject.liquidStateSpecificHeat());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeHysteresisFields::HighTemperatureDifferenceofMeltingCurve,
+                        modelObject.highTemperatureDifferenceofMeltingCurve());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeHysteresisFields::PeakMeltingTemperature, modelObject.peakMeltingTemperature());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeHysteresisFields::LowTemperatureDifferenceofMeltingCurve,
+                        modelObject.lowTemperatureDifferenceofMeltingCurve());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeHysteresisFields::SolidStateThermalConductivity, modelObject.solidStateThermalConductivity());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeHysteresisFields::SolidStateDensity, modelObject.solidStateDensity());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeHysteresisFields::SolidStateSpecificHeat, modelObject.solidStateSpecificHeat());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeHysteresisFields::HighTemperatureDifferenceofFreezingCurve,
+                        modelObject.highTemperatureDifferenceofFreezingCurve());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeHysteresisFields::PeakFreezingTemperature, modelObject.peakFreezingTemperature());
+
+    idfObject.setDouble(MaterialProperty_PhaseChangeHysteresisFields::LowTemperatureDifferenceofFreezingCurve,
+                        modelObject.lowTemperatureDifferenceofFreezingCurve());
+
+    return idfObject;
+  }
+
+}  // namespace energyplus
+
+}  // namespace openstudio
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateStandardOpaqueMaterial.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateStandardOpaqueMaterial.cpp
index c362c04ac04..599066c53df 100644
--- a/src/energyplus/ForwardTranslator/ForwardTranslateStandardOpaqueMaterial.cpp
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateStandardOpaqueMaterial.cpp
@@ -31,6 +31,12 @@
 
 #include "../../model/StandardOpaqueMaterial.hpp"
 #include "../../model/StandardOpaqueMaterial_Impl.hpp"
+#include "../../model/MaterialPropertyMoisturePenetrationDepthSettings.hpp"
+#include "../../model/MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp"
+#include "../../model/MaterialPropertyPhaseChange.hpp"
+#include "../../model/MaterialPropertyPhaseChange_Impl.hpp"
+#include "../../model/MaterialPropertyPhaseChangeHysteresis.hpp"
+#include "../../model/MaterialPropertyPhaseChangeHysteresis_Impl.hpp"
 
 #include <utilities/idd/Material_FieldEnums.hxx>
 #include "../../utilities/idd/IddEnums.hpp"
@@ -76,6 +82,21 @@ namespace energyplus {
       idfObject.setDouble(openstudio::MaterialFields::VisibleAbsorptance, *d);
     }
 
+    // Call the translation of these objects, which has two advantages:
+    // * will not translate them if they are orphaned (=not referencing a material), and,
+    // * makes the order of these objects in the IDF deterministic
+    if (boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> _empd = modelObject.materialPropertyMoisturePenetrationDepthSettings()) {
+      translateAndMapModelObject(_empd.get());
+    }
+
+    if (boost::optional<MaterialPropertyPhaseChange> _phaseChange = modelObject.materialPropertyPhaseChange()) {
+      translateAndMapModelObject(_phaseChange.get());
+    }
+
+    if (boost::optional<MaterialPropertyPhaseChangeHysteresis> _phaseChangeHysteresis = modelObject.materialPropertyPhaseChangeHysteresis()) {
+      translateAndMapModelObject(_phaseChangeHysteresis.get());
+    }
+
     return boost::optional<IdfObject>(idfObject);
   }
 
diff --git a/src/energyplus/Test/AirTerminalDualDuctVAV_GTest.cpp b/src/energyplus/Test/AirTerminalDualDuctVAV_GTest.cpp
index e5a80487ea1..d9dd2013e2f 100644
--- a/src/energyplus/Test/AirTerminalDualDuctVAV_GTest.cpp
+++ b/src/energyplus/Test/AirTerminalDualDuctVAV_GTest.cpp
@@ -41,6 +41,7 @@
 #include "../../model/Node.hpp"
 #include "../../model/DesignSpecificationOutdoorAir.hpp"
 
+#include <utilities/idd/IddObject.hpp>
 #include <utilities/idd/AirTerminal_DualDuct_VAV_FieldEnums.hxx>
 #include <utilities/idd/IddEnums.hxx>
 
@@ -98,4 +99,4 @@ TEST_F(EnergyPlusFixture, ForwardTranslator_AirTerminalDualDuctVAV) {
   EXPECT_TRUE(woTurndownSchedule);
   EXPECT_EQ(woTurndownSchedule->iddObject().type(), IddObjectType::Schedule_Constant);
   EXPECT_EQ("Always On Discrete", woTurndownSchedule->nameString());
-}
\ No newline at end of file
+}
diff --git a/src/energyplus/Test/AirTerminalSingleDuctVAVNoReheat_GTest.cpp b/src/energyplus/Test/AirTerminalSingleDuctVAVNoReheat_GTest.cpp
index 17775958b34..9c1288377d7 100644
--- a/src/energyplus/Test/AirTerminalSingleDuctVAVNoReheat_GTest.cpp
+++ b/src/energyplus/Test/AirTerminalSingleDuctVAVNoReheat_GTest.cpp
@@ -41,6 +41,7 @@
 #include "../../model/Node.hpp"
 #include "../../model/DesignSpecificationOutdoorAir.hpp"
 
+#include <utilities/idd/IddObject.hpp>
 #include <utilities/idd/AirTerminal_SingleDuct_VAV_NoReheat_FieldEnums.hxx>
 #include <utilities/idd/IddEnums.hxx>
 
diff --git a/src/energyplus/Test/AirTerminalSingleDuctVAVReheat_GTest.cpp b/src/energyplus/Test/AirTerminalSingleDuctVAVReheat_GTest.cpp
index 7d8f6289bbd..beed59b87d7 100644
--- a/src/energyplus/Test/AirTerminalSingleDuctVAVReheat_GTest.cpp
+++ b/src/energyplus/Test/AirTerminalSingleDuctVAVReheat_GTest.cpp
@@ -42,6 +42,7 @@
 #include "../../model/Node.hpp"
 #include "../../model/DesignSpecificationOutdoorAir.hpp"
 
+#include <utilities/idd/IddObject.hpp>
 #include <utilities/idd/AirTerminal_SingleDuct_VAV_Reheat_FieldEnums.hxx>
 #include <utilities/idd/IddEnums.hxx>
 
diff --git a/src/energyplus/Test/MaterialPropertyMoisturePenetrationDepthSettings_GTest.cpp b/src/energyplus/Test/MaterialPropertyMoisturePenetrationDepthSettings_GTest.cpp
new file mode 100644
index 00000000000..eeeb6b6aab0
--- /dev/null
+++ b/src/energyplus/Test/MaterialPropertyMoisturePenetrationDepthSettings_GTest.cpp
@@ -0,0 +1,81 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include <gtest/gtest.h>
+#include "EnergyPlusFixture.hpp"
+
+#include "../ForwardTranslator.hpp"
+#include "../ReverseTranslator.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/MaterialPropertyMoisturePenetrationDepthSettings.hpp"
+#include "../../model/MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp"
+#include "../../model/StandardOpaqueMaterial.hpp"
+#include "../../model/StandardOpaqueMaterial_Impl.hpp"
+
+#include "../../utilities/idf/IdfFile.hpp"
+#include "../../utilities/idf/Workspace.hpp"
+#include "../../utilities/idf/IdfObject.hpp"
+#include "../../utilities/idf/WorkspaceObject.hpp"
+
+#include <utilities/idd/MaterialProperty_MoisturePenetrationDepth_Settings_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::energyplus;
+using namespace openstudio::model;
+using namespace openstudio;
+
+TEST_F(EnergyPlusFixture, ForwardTranslator_MaterialPropertyMoisturePenetrationDepthSettings) {
+
+  ForwardTranslator ft;
+
+  Model model;
+  StandardOpaqueMaterial material(model);
+  boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> optempd =
+    material.createMaterialPropertyMoisturePenetrationDepthSettings(8.9, 0.0069, 0.9066, 0.0404, 22.1121, 0.005, 140);  // drywall
+
+  Workspace workspace = ft.translateModel(model);
+
+  WorkspaceObjectVector idfObjs = workspace.getObjectsByType(IddObjectType::MaterialProperty_MoisturePenetrationDepth_Settings);
+  ASSERT_EQ(1u, idfObjs.size());
+
+  WorkspaceObject idf_matProp(idfObjs[0]);
+
+  EXPECT_EQ("Material 1", idf_matProp.getString(MaterialProperty_MoisturePenetrationDepth_SettingsFields::Name).get());
+  EXPECT_EQ(8.9, idf_matProp.getDouble(MaterialProperty_MoisturePenetrationDepth_SettingsFields::WaterVaporDiffusionResistanceFactor).get());
+  EXPECT_EQ(0.0069, idf_matProp.getDouble(MaterialProperty_MoisturePenetrationDepth_SettingsFields::MoistureEquationCoefficienta).get());
+  EXPECT_EQ(0.9066, idf_matProp.getDouble(MaterialProperty_MoisturePenetrationDepth_SettingsFields::MoistureEquationCoefficientb).get());
+  EXPECT_EQ(0.0404, idf_matProp.getDouble(MaterialProperty_MoisturePenetrationDepth_SettingsFields::MoistureEquationCoefficientc).get());
+  EXPECT_EQ(22.1121, idf_matProp.getDouble(MaterialProperty_MoisturePenetrationDepth_SettingsFields::MoistureEquationCoefficientd).get());
+  EXPECT_EQ("Autocalculate", idf_matProp.getString(MaterialProperty_MoisturePenetrationDepth_SettingsFields::SurfaceLayerPenetrationDepth).get());
+  EXPECT_EQ("Autocalculate", idf_matProp.getString(MaterialProperty_MoisturePenetrationDepth_SettingsFields::DeepLayerPenetrationDepth).get());
+  EXPECT_EQ(0.005, idf_matProp.getDouble(MaterialProperty_MoisturePenetrationDepth_SettingsFields::CoatingLayerThickness).get());
+  EXPECT_EQ(140,
+            idf_matProp.getDouble(MaterialProperty_MoisturePenetrationDepth_SettingsFields::CoatingLayerWaterVaporDiffusionResistanceFactor).get());
+}
diff --git a/src/energyplus/Test/MaterialPropertyPhaseChangeHysteresis_GTest.cpp b/src/energyplus/Test/MaterialPropertyPhaseChangeHysteresis_GTest.cpp
new file mode 100644
index 00000000000..4db6f13a5a3
--- /dev/null
+++ b/src/energyplus/Test/MaterialPropertyPhaseChangeHysteresis_GTest.cpp
@@ -0,0 +1,110 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include <gtest/gtest.h>
+#include "EnergyPlusFixture.hpp"
+
+#include "../ForwardTranslator.hpp"
+#include "../ReverseTranslator.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/MaterialPropertyPhaseChangeHysteresis.hpp"
+#include "../../model/MaterialPropertyPhaseChangeHysteresis_Impl.hpp"
+#include "../../model/StandardOpaqueMaterial.hpp"
+#include "../../model/StandardOpaqueMaterial_Impl.hpp"
+
+#include "../../utilities/idf/IdfFile.hpp"
+#include "../../utilities/idf/Workspace.hpp"
+#include "../../utilities/idf/IdfObject.hpp"
+#include "../../utilities/idf/WorkspaceObject.hpp"
+
+#include <utilities/idd/MaterialProperty_PhaseChangeHysteresis_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::energyplus;
+using namespace openstudio::model;
+using namespace openstudio;
+
+TEST_F(EnergyPlusFixture, ForwardTranslator_MaterialPropertyPhaseChangeHysteresis) {
+
+  ForwardTranslator ft;
+
+  Model model;
+  StandardOpaqueMaterial material(model);
+  boost::optional<MaterialPropertyPhaseChangeHysteresis> optphaseChangeHysteresis = material.createMaterialPropertyPhaseChangeHysteresis();
+  auto phaseChangeHysteresis = optphaseChangeHysteresis.get();
+
+  phaseChangeHysteresis.setLatentHeatduringtheEntirePhaseChangeProcess(11000);
+  phaseChangeHysteresis.setLiquidStateThermalConductivity(2.5);
+  phaseChangeHysteresis.setLiquidStateDensity(2300.0);
+  phaseChangeHysteresis.setLiquidStateSpecificHeat(2100.0);
+  phaseChangeHysteresis.setHighTemperatureDifferenceofMeltingCurve(1.5);
+  phaseChangeHysteresis.setPeakMeltingTemperature(24.0);
+  phaseChangeHysteresis.setLowTemperatureDifferenceofMeltingCurve(1.1);
+  phaseChangeHysteresis.setSolidStateThermalConductivity(1.9);
+  phaseChangeHysteresis.setSolidStateDensity(2400.0);
+  phaseChangeHysteresis.setSolidStateSpecificHeat(2010.0);
+  phaseChangeHysteresis.setHighTemperatureDifferenceofFreezingCurve(1.2);
+  phaseChangeHysteresis.setPeakFreezingTemperature(21.0);
+  phaseChangeHysteresis.setLowTemperatureDifferenceofFreezingCurve(1.05);
+
+  Workspace workspace = ft.translateModel(model);
+
+  WorkspaceObjectVector idfObjs = workspace.getObjectsByType(IddObjectType::MaterialProperty_PhaseChangeHysteresis);
+  ASSERT_EQ(1u, idfObjs.size());
+
+  WorkspaceObject idf_matProp(idfObjs[0]);
+
+  EXPECT_EQ(material.nameString(), idf_matProp.getString(MaterialProperty_PhaseChangeHysteresisFields::Name).get());
+  EXPECT_EQ(phaseChangeHysteresis.latentHeatduringtheEntirePhaseChangeProcess(),
+            idf_matProp.getDouble(MaterialProperty_PhaseChangeHysteresisFields::LatentHeatduringtheEntirePhaseChangeProcess).get());
+  EXPECT_EQ(phaseChangeHysteresis.liquidStateThermalConductivity(),
+            idf_matProp.getDouble(MaterialProperty_PhaseChangeHysteresisFields::LiquidStateThermalConductivity).get());
+  EXPECT_EQ(phaseChangeHysteresis.liquidStateDensity(),
+            idf_matProp.getDouble(MaterialProperty_PhaseChangeHysteresisFields::LiquidStateDensity).get());
+  EXPECT_EQ(phaseChangeHysteresis.liquidStateSpecificHeat(),
+            idf_matProp.getDouble(MaterialProperty_PhaseChangeHysteresisFields::LiquidStateSpecificHeat).get());
+  EXPECT_EQ(phaseChangeHysteresis.highTemperatureDifferenceofMeltingCurve(),
+            idf_matProp.getDouble(MaterialProperty_PhaseChangeHysteresisFields::HighTemperatureDifferenceofMeltingCurve).get());
+  EXPECT_EQ(phaseChangeHysteresis.peakMeltingTemperature(),
+            idf_matProp.getDouble(MaterialProperty_PhaseChangeHysteresisFields::PeakMeltingTemperature).get());
+  EXPECT_EQ(phaseChangeHysteresis.lowTemperatureDifferenceofMeltingCurve(),
+            idf_matProp.getDouble(MaterialProperty_PhaseChangeHysteresisFields::LowTemperatureDifferenceofMeltingCurve).get());
+  EXPECT_EQ(phaseChangeHysteresis.solidStateThermalConductivity(),
+            idf_matProp.getDouble(MaterialProperty_PhaseChangeHysteresisFields::SolidStateThermalConductivity).get());
+  EXPECT_EQ(phaseChangeHysteresis.solidStateDensity(), idf_matProp.getDouble(MaterialProperty_PhaseChangeHysteresisFields::SolidStateDensity).get());
+  EXPECT_EQ(phaseChangeHysteresis.solidStateSpecificHeat(),
+            idf_matProp.getDouble(MaterialProperty_PhaseChangeHysteresisFields::SolidStateSpecificHeat).get());
+  EXPECT_EQ(phaseChangeHysteresis.highTemperatureDifferenceofFreezingCurve(),
+            idf_matProp.getDouble(MaterialProperty_PhaseChangeHysteresisFields::HighTemperatureDifferenceofFreezingCurve).get());
+  EXPECT_EQ(phaseChangeHysteresis.peakFreezingTemperature(),
+            idf_matProp.getDouble(MaterialProperty_PhaseChangeHysteresisFields::PeakFreezingTemperature).get());
+  EXPECT_EQ(phaseChangeHysteresis.lowTemperatureDifferenceofFreezingCurve(),
+            idf_matProp.getDouble(MaterialProperty_PhaseChangeHysteresisFields::LowTemperatureDifferenceofFreezingCurve).get());
+}
diff --git a/src/energyplus/Test/MaterialPropertyPhaseChange_GTest.cpp b/src/energyplus/Test/MaterialPropertyPhaseChange_GTest.cpp
new file mode 100644
index 00000000000..e5370501309
--- /dev/null
+++ b/src/energyplus/Test/MaterialPropertyPhaseChange_GTest.cpp
@@ -0,0 +1,117 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include <gtest/gtest.h>
+#include "EnergyPlusFixture.hpp"
+
+#include "../ForwardTranslator.hpp"
+#include "../ReverseTranslator.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/MaterialPropertyPhaseChange.hpp"
+#include "../../model/MaterialPropertyPhaseChange_Impl.hpp"
+#include "../../model/StandardOpaqueMaterial.hpp"
+#include "../../model/StandardOpaqueMaterial_Impl.hpp"
+
+#include "../../utilities/idf/IdfFile.hpp"
+#include "../../utilities/idf/Workspace.hpp"
+#include "../../utilities/idf/IdfObject.hpp"
+#include "../../utilities/idf/WorkspaceObject.hpp"
+#include "../../utilities/idf/IdfExtensibleGroup.hpp"
+
+#include <utilities/idd/MaterialProperty_PhaseChange_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+#include <vector>
+
+using namespace openstudio::energyplus;
+using namespace openstudio::model;
+using namespace openstudio;
+
+TEST_F(EnergyPlusFixture, ForwardTranslator_MaterialPropertyPhaseChange) {
+
+  ForwardTranslator ft;
+
+  Model model;
+  StandardOpaqueMaterial material(model);
+  boost::optional<MaterialPropertyPhaseChange> optphaseChange = material.createMaterialPropertyPhaseChange();
+  auto phaseChange = optphaseChange.get();
+
+  EXPECT_TRUE(phaseChange.setTemperatureCoefficientforThermalConductivity(14.7));
+
+  phaseChange.removeAllTemperatureEnthalpys();
+  std::vector<TemperatureEnthalpy> temperatureEnthalpies{
+    {-20, 0.4},
+    {24.1, 19260},
+    {24.1, 31000},
+    {58, 69000},
+  };
+
+  EXPECT_TRUE(phaseChange.addTemperatureEnthalpys(temperatureEnthalpies));
+
+  Workspace workspace = ft.translateModel(model);
+
+  WorkspaceObjectVector idfObjs = workspace.getObjectsByType(IddObjectType::MaterialProperty_PhaseChange);
+  ASSERT_EQ(1u, idfObjs.size());
+
+  WorkspaceObject idf_matProp(idfObjs[0]);
+
+  EXPECT_EQ("Material 1", idf_matProp.getString(MaterialProperty_PhaseChangeFields::Name).get());
+  EXPECT_EQ(phaseChange.temperatureCoefficientforThermalConductivity(),
+            idf_matProp.getDouble(MaterialProperty_PhaseChangeFields::TemperatureCoefficientforThermalConductivity).get());
+  ASSERT_EQ(temperatureEnthalpies.size(), idf_matProp.numExtensibleGroups());
+  auto egs = idf_matProp.extensibleGroups();
+  for (size_t i = 0; const auto& temperatureEnthalpy : temperatureEnthalpies) {
+    auto eg = egs[i];
+    EXPECT_EQ(temperatureEnthalpy.temperature(), eg.getDouble(MaterialProperty_PhaseChangeExtensibleFields::Temperature).get());
+    EXPECT_EQ(temperatureEnthalpy.enthalpy(), eg.getDouble(MaterialProperty_PhaseChangeExtensibleFields::Enthalpy).get());
+    ++i;
+  }
+}
+
+TEST_F(EnergyPlusFixture, ForwardTranslator_MaterialPropertyPhaseChange_NotEnoughTemperatureEnthalpyPairs) {
+
+  ForwardTranslator ft;
+
+  Model model;
+  StandardOpaqueMaterial material(model);
+  std::vector<TemperatureEnthalpy> temperatureEnthalpys;
+  TemperatureEnthalpy temperatureEnthalpy1(-20, 0.1);
+  temperatureEnthalpys.push_back(temperatureEnthalpy1);
+  TemperatureEnthalpy temperatureEnthalpy2(22, 18260);
+  temperatureEnthalpys.push_back(temperatureEnthalpy2);
+  boost::optional<MaterialPropertyPhaseChange> optphaseChange = material.createMaterialPropertyPhaseChange(temperatureEnthalpys);
+
+  Workspace workspace = ft.translateModel(model);
+
+  WorkspaceObjectVector idfObjs = workspace.getObjectsByType(IddObjectType::MaterialProperty_PhaseChange);
+  ASSERT_EQ(0u, idfObjs.size());
+  ASSERT_EQ(1, ft.warnings().size());
+  EXPECT_EQ("Object of type 'OS:MaterialProperty:PhaseChange' cannot be translated as it has less than 4 temperature-enthalpy pairs.",
+            ft.warnings().front().logMessage());
+}
diff --git a/src/energyplus/Test/ZoneHVACUnitHeater_GTest.cpp b/src/energyplus/Test/ZoneHVACUnitHeater_GTest.cpp
index 6cd407f0919..1d7857946e7 100644
--- a/src/energyplus/Test/ZoneHVACUnitHeater_GTest.cpp
+++ b/src/energyplus/Test/ZoneHVACUnitHeater_GTest.cpp
@@ -47,6 +47,7 @@
 #include "../../model/Schedule.hpp"
 #include "../../model/PlantLoop.hpp"
 
+#include <utilities/idd/IddObject.hpp>
 #include <utilities/idd/IddEnums.hxx>
 #include <utilities/idd/ZoneHVAC_UnitHeater_FieldEnums.hxx>
 #include <utilities/idd/Fan_OnOff_FieldEnums.hxx>
diff --git a/src/model/CMakeLists.txt b/src/model/CMakeLists.txt
index f0e535399a4..3c096362f16 100644
--- a/src/model/CMakeLists.txt
+++ b/src/model/CMakeLists.txt
@@ -1001,6 +1001,12 @@ set(${target_name}_src
   MaterialPropertyMoisturePenetrationDepthSettings.hpp
   MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp
   MaterialPropertyMoisturePenetrationDepthSettings.cpp
+  MaterialPropertyPhaseChange.hpp
+  MaterialPropertyPhaseChange_Impl.hpp
+  MaterialPropertyPhaseChange.cpp
+  MaterialPropertyPhaseChangeHysteresis.hpp
+  MaterialPropertyPhaseChangeHysteresis_Impl.hpp
+  MaterialPropertyPhaseChangeHysteresis.cpp
   MeterCustom.hpp
   MeterCustom_Impl.hpp
   MeterCustom.cpp
@@ -2075,6 +2081,8 @@ set(${target_name}_test_src
   test/Material_GTest.cpp
   test/MaterialPropertyGlazingSpectralData_GTest.cpp
   test/MaterialPropertyMoisturePenetrationDepthSettings_GTest.cpp
+  test/MaterialPropertyPhaseChange_GTest.cpp
+  test/MaterialPropertyPhaseChangeHysteresis_GTest.cpp
   test/MeterCustom_GTest.cpp
   test/MeterCustomDecrement_GTest.cpp
   test/ModelFixture.cpp
diff --git a/src/model/ConcreteModelObjects.hpp b/src/model/ConcreteModelObjects.hpp
index 5680af5803a..d23fba0bb8f 100644
--- a/src/model/ConcreteModelObjects.hpp
+++ b/src/model/ConcreteModelObjects.hpp
@@ -330,6 +330,8 @@
 #include "LuminaireDefinition.hpp"
 #include "MaterialPropertyGlazingSpectralData.hpp"
 #include "MaterialPropertyMoisturePenetrationDepthSettings.hpp"
+#include "MaterialPropertyPhaseChange.hpp"
+#include "MaterialPropertyPhaseChangeHysteresis.hpp"
 #include "MasslessOpaqueMaterial.hpp"
 #include "MeterCustom.hpp"
 #include "MeterCustomDecrement.hpp"
@@ -857,6 +859,8 @@
 #include "LuminaireDefinition_Impl.hpp"
 #include "MaterialPropertyGlazingSpectralData_Impl.hpp"
 #include "MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp"
+#include "MaterialPropertyPhaseChange_Impl.hpp"
+#include "MaterialPropertyPhaseChangeHysteresis_Impl.hpp"
 #include "MasslessOpaqueMaterial_Impl.hpp"
 #include "MeterCustom_Impl.hpp"
 #include "MeterCustomDecrement_Impl.hpp"
diff --git a/src/model/MasslessOpaqueMaterial.cpp b/src/model/MasslessOpaqueMaterial.cpp
index abff56a37ea..5fe00250215 100644
--- a/src/model/MasslessOpaqueMaterial.cpp
+++ b/src/model/MasslessOpaqueMaterial.cpp
@@ -29,6 +29,14 @@
 
 #include "MasslessOpaqueMaterial.hpp"
 #include "MasslessOpaqueMaterial_Impl.hpp"
+#include "StandardsInformationMaterial.hpp"
+#include "StandardsInformationMaterial_Impl.hpp"
+#include "MaterialPropertyMoisturePenetrationDepthSettings.hpp"
+#include "MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp"
+#include "MaterialPropertyPhaseChange.hpp"
+#include "MaterialPropertyPhaseChange_Impl.hpp"
+#include "MaterialPropertyPhaseChangeHysteresis.hpp"
+#include "MaterialPropertyPhaseChangeHysteresis_Impl.hpp"
 
 #include <utilities/idd/IddFactory.hxx>
 
@@ -58,6 +66,24 @@ namespace model {
     MasslessOpaqueMaterial_Impl::MasslessOpaqueMaterial_Impl(const MasslessOpaqueMaterial_Impl& other, Model_Impl* model, bool keepHandle)
       : OpaqueMaterial_Impl(other, model, keepHandle) {}
 
+    std::vector<ModelObject> MasslessOpaqueMaterial_Impl::children() const {
+      std::vector<ModelObject> results(castVector<ModelObject>(getObject<Material>().getModelObjectSources<StandardsInformationMaterial>()));
+
+      if (boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> empd = this->materialPropertyMoisturePenetrationDepthSettings()) {
+        results.push_back(empd.get());
+      }
+
+      if (boost::optional<MaterialPropertyPhaseChange> phaseChange = this->materialPropertyPhaseChange()) {
+        results.push_back(phaseChange.get());
+      }
+
+      if (boost::optional<MaterialPropertyPhaseChangeHysteresis> phaseChangeHysteresis = this->materialPropertyPhaseChangeHysteresis()) {
+        results.push_back(phaseChangeHysteresis.get());
+      }
+
+      return results;
+    }
+
     std::string MasslessOpaqueMaterial_Impl::roughness() const {
       boost::optional<std::string> value = getString(OS_Material_NoMassFields::Roughness, true);
       OS_ASSERT(value);
@@ -257,6 +283,124 @@ namespace model {
       return MasslessOpaqueMaterial::roughnessValues();
     }
 
+    boost::optional<MaterialPropertyMoisturePenetrationDepthSettings>
+      MasslessOpaqueMaterial_Impl::createMaterialPropertyMoisturePenetrationDepthSettings(
+        double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA, double moistureEquationCoefficientB,
+        double moistureEquationCoefficientC, double moistureEquationCoefficientD, double coatingLayerThickness,
+        double coatingLayerWaterVaporDiffusionResistanceFactor) {
+      MasslessOpaqueMaterial thisMaterial = getObject<MasslessOpaqueMaterial>();
+      std::vector<MaterialPropertyMoisturePenetrationDepthSettings> empds =
+        thisMaterial.getModelObjectSources<MaterialPropertyMoisturePenetrationDepthSettings>(
+          MaterialPropertyMoisturePenetrationDepthSettings::iddObjectType());
+      if (!empds.empty()) {
+        return boost::none;
+      }
+
+      MaterialPropertyMoisturePenetrationDepthSettings empd(thisMaterial, waterVaporDiffusionResistanceFactor, moistureEquationCoefficientA,
+                                                            moistureEquationCoefficientB, moistureEquationCoefficientC, moistureEquationCoefficientD,
+                                                            coatingLayerThickness, coatingLayerWaterVaporDiffusionResistanceFactor);
+      return empd;
+    }
+
+    boost::optional<MaterialPropertyMoisturePenetrationDepthSettings>
+      MasslessOpaqueMaterial_Impl::materialPropertyMoisturePenetrationDepthSettings() const {
+      std::vector<MaterialPropertyMoisturePenetrationDepthSettings> empds =
+        getObject<ModelObject>().getModelObjectSources<MaterialPropertyMoisturePenetrationDepthSettings>(
+          MaterialPropertyMoisturePenetrationDepthSettings::iddObjectType());
+      if (empds.empty()) {
+        // no error
+      } else if (empds.size() == 1) {
+        return empds[0];
+      } else {
+        // error
+      }
+      return boost::none;
+    }
+
+    void MasslessOpaqueMaterial_Impl::resetMaterialPropertyMoisturePenetrationDepthSettings() {
+      boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> empd = this->materialPropertyMoisturePenetrationDepthSettings();
+      if (empd) {
+        empd->remove();
+      }
+    }
+
+    boost::optional<MaterialPropertyPhaseChange> MasslessOpaqueMaterial_Impl::createMaterialPropertyPhaseChange() {
+      MasslessOpaqueMaterial thisMaterial = getObject<MasslessOpaqueMaterial>();
+      std::vector<MaterialPropertyPhaseChange> phaseChanges =
+        thisMaterial.getModelObjectSources<MaterialPropertyPhaseChange>(MaterialPropertyPhaseChange::iddObjectType());
+      if (!phaseChanges.empty()) {
+        return boost::none;
+      }
+
+      MaterialPropertyPhaseChange phaseChange(thisMaterial);
+      return phaseChange;
+    }
+
+    boost::optional<MaterialPropertyPhaseChange>
+      MasslessOpaqueMaterial_Impl::createMaterialPropertyPhaseChange(const std::vector<TemperatureEnthalpy>& temperatureEnthalpys) {
+      MasslessOpaqueMaterial thisMaterial = getObject<MasslessOpaqueMaterial>();
+      std::vector<MaterialPropertyPhaseChange> phaseChanges =
+        thisMaterial.getModelObjectSources<MaterialPropertyPhaseChange>(MaterialPropertyPhaseChange::iddObjectType());
+      if (!phaseChanges.empty()) {
+        return boost::none;
+      }
+
+      MaterialPropertyPhaseChange phaseChange(thisMaterial, temperatureEnthalpys);
+      return phaseChange;
+    }
+
+    boost::optional<MaterialPropertyPhaseChange> MasslessOpaqueMaterial_Impl::materialPropertyPhaseChange() const {
+      std::vector<MaterialPropertyPhaseChange> phaseChanges =
+        getObject<ModelObject>().getModelObjectSources<MaterialPropertyPhaseChange>(MaterialPropertyPhaseChange::iddObjectType());
+      if (phaseChanges.empty()) {
+        // no error
+      } else if (phaseChanges.size() == 1) {
+        return phaseChanges[0];
+      } else {
+        // error
+      }
+      return boost::none;
+    }
+
+    void MasslessOpaqueMaterial_Impl::resetMaterialPropertyPhaseChange() {
+      boost::optional<MaterialPropertyPhaseChange> phaseChange = this->materialPropertyPhaseChange();
+      if (phaseChange) {
+        phaseChange->remove();
+      }
+    }
+
+    boost::optional<MaterialPropertyPhaseChangeHysteresis> MasslessOpaqueMaterial_Impl::createMaterialPropertyPhaseChangeHysteresis() {
+      MasslessOpaqueMaterial thisMaterial = getObject<MasslessOpaqueMaterial>();
+      std::vector<MaterialPropertyPhaseChangeHysteresis> phaseChangeHysteresiss =
+        thisMaterial.getModelObjectSources<MaterialPropertyPhaseChangeHysteresis>(MaterialPropertyPhaseChangeHysteresis::iddObjectType());
+      if (!phaseChangeHysteresiss.empty()) {
+        return boost::none;
+      }
+
+      MaterialPropertyPhaseChangeHysteresis phaseChangeHysteresis(thisMaterial);
+      return phaseChangeHysteresis;
+    }
+
+    boost::optional<MaterialPropertyPhaseChangeHysteresis> MasslessOpaqueMaterial_Impl::materialPropertyPhaseChangeHysteresis() const {
+      std::vector<MaterialPropertyPhaseChangeHysteresis> phaseChangeHysteresiss =
+        getObject<ModelObject>().getModelObjectSources<MaterialPropertyPhaseChangeHysteresis>(MaterialPropertyPhaseChangeHysteresis::iddObjectType());
+      if (phaseChangeHysteresiss.empty()) {
+        // no error
+      } else if (phaseChangeHysteresiss.size() == 1) {
+        return phaseChangeHysteresiss[0];
+      } else {
+        // error
+      }
+      return boost::none;
+    }
+
+    void MasslessOpaqueMaterial_Impl::resetMaterialPropertyPhaseChangeHysteresis() {
+      boost::optional<MaterialPropertyPhaseChangeHysteresis> phaseChangeHysteresis = this->materialPropertyPhaseChangeHysteresis();
+      if (phaseChangeHysteresis) {
+        phaseChangeHysteresis->remove();
+      }
+    }
+
   }  // namespace detail
 
   MasslessOpaqueMaterial::MasslessOpaqueMaterial(const Model& model, const std::string& roughness, double thermalResistance)
@@ -348,6 +492,52 @@ namespace model {
     getImpl<detail::MasslessOpaqueMaterial_Impl>()->resetVisibleAbsorptance();
   }
 
+  boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> MasslessOpaqueMaterial::createMaterialPropertyMoisturePenetrationDepthSettings(
+    double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA, double moistureEquationCoefficientB,
+    double moistureEquationCoefficientC, double moistureEquationCoefficientD, double coatingLayerThickness,
+    double coatingLayerWaterVaporDiffusionResistanceFactor) {
+    return getImpl<detail::MasslessOpaqueMaterial_Impl>()->createMaterialPropertyMoisturePenetrationDepthSettings(
+      waterVaporDiffusionResistanceFactor, moistureEquationCoefficientA, moistureEquationCoefficientB, moistureEquationCoefficientC,
+      moistureEquationCoefficientD, coatingLayerThickness, coatingLayerWaterVaporDiffusionResistanceFactor);
+  }
+
+  boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> MasslessOpaqueMaterial::materialPropertyMoisturePenetrationDepthSettings() const {
+    return getImpl<detail::MasslessOpaqueMaterial_Impl>()->materialPropertyMoisturePenetrationDepthSettings();
+  }
+
+  void MasslessOpaqueMaterial::resetMaterialPropertyMoisturePenetrationDepthSettings() {
+    getImpl<detail::MasslessOpaqueMaterial_Impl>()->resetMaterialPropertyMoisturePenetrationDepthSettings();
+  }
+
+  boost::optional<MaterialPropertyPhaseChange> MasslessOpaqueMaterial::createMaterialPropertyPhaseChange() {
+    return getImpl<detail::MasslessOpaqueMaterial_Impl>()->createMaterialPropertyPhaseChange();
+  }
+
+  boost::optional<MaterialPropertyPhaseChange>
+    MasslessOpaqueMaterial::createMaterialPropertyPhaseChange(const std::vector<TemperatureEnthalpy>& temperatureEnthalpys) {
+    return getImpl<detail::MasslessOpaqueMaterial_Impl>()->createMaterialPropertyPhaseChange(temperatureEnthalpys);
+  }
+
+  boost::optional<MaterialPropertyPhaseChange> MasslessOpaqueMaterial::materialPropertyPhaseChange() const {
+    return getImpl<detail::MasslessOpaqueMaterial_Impl>()->materialPropertyPhaseChange();
+  }
+
+  void MasslessOpaqueMaterial::resetMaterialPropertyPhaseChange() {
+    getImpl<detail::MasslessOpaqueMaterial_Impl>()->resetMaterialPropertyPhaseChange();
+  }
+
+  boost::optional<MaterialPropertyPhaseChangeHysteresis> MasslessOpaqueMaterial::createMaterialPropertyPhaseChangeHysteresis() {
+    return getImpl<detail::MasslessOpaqueMaterial_Impl>()->createMaterialPropertyPhaseChangeHysteresis();
+  }
+
+  boost::optional<MaterialPropertyPhaseChangeHysteresis> MasslessOpaqueMaterial::materialPropertyPhaseChangeHysteresis() const {
+    return getImpl<detail::MasslessOpaqueMaterial_Impl>()->materialPropertyPhaseChangeHysteresis();
+  }
+
+  void MasslessOpaqueMaterial::resetMaterialPropertyPhaseChangeHysteresis() {
+    getImpl<detail::MasslessOpaqueMaterial_Impl>()->resetMaterialPropertyPhaseChangeHysteresis();
+  }
+
   /// @cond
   MasslessOpaqueMaterial::MasslessOpaqueMaterial(std::shared_ptr<detail::MasslessOpaqueMaterial_Impl> impl) : OpaqueMaterial(std::move(impl)) {}
   /// @endcond
diff --git a/src/model/MasslessOpaqueMaterial.hpp b/src/model/MasslessOpaqueMaterial.hpp
index c0c3d48d729..d363457c153 100644
--- a/src/model/MasslessOpaqueMaterial.hpp
+++ b/src/model/MasslessOpaqueMaterial.hpp
@@ -33,10 +33,21 @@
 #include "ModelAPI.hpp"
 #include "OpaqueMaterial.hpp"
 
+#include "MaterialPropertyMoisturePenetrationDepthSettings.hpp"
+#include "MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp"
+#include "MaterialPropertyPhaseChange.hpp"
+#include "MaterialPropertyPhaseChange_Impl.hpp"
+#include "MaterialPropertyPhaseChangeHysteresis.hpp"
+#include "MaterialPropertyPhaseChangeHysteresis_Impl.hpp"
+
 namespace openstudio {
 
 namespace model {
 
+  class MaterialPropertyMoisturePenetrationDepthSettings;
+  class MaterialPropertyPhaseChange;
+  class MaterialPropertyPhaseChangeHysteresis;
+
   namespace detail {
 
     class MasslessOpaqueMaterial_Impl;
@@ -99,6 +110,38 @@ namespace model {
 
     void resetVisibleAbsorptance();
 
+    // if material property moisture penetration depth settings already exists, do nothing and return nil; creates the material property moisture penetration depth settings if it does not already exist and return it
+    boost::optional<MaterialPropertyMoisturePenetrationDepthSettings>
+      createMaterialPropertyMoisturePenetrationDepthSettings(double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA,
+                                                             double moistureEquationCoefficientB, double moistureEquationCoefficientC,
+                                                             double moistureEquationCoefficientD, double coatingLayerThickness,
+                                                             double coatingLayerWaterVaporDiffusionResistanceFactor);
+
+    // returns the material property moisture penetration depth settings if set
+    boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> materialPropertyMoisturePenetrationDepthSettings() const;
+
+    // resets the material property moisture penetration depth settings
+    void resetMaterialPropertyMoisturePenetrationDepthSettings();
+
+    // if material property phase change already exists, do nothing and return nil; creates the material property phase change if it does not already exist and return it
+    boost::optional<MaterialPropertyPhaseChange> createMaterialPropertyPhaseChange();
+    boost::optional<MaterialPropertyPhaseChange> createMaterialPropertyPhaseChange(const std::vector<TemperatureEnthalpy>& temperatureEnthalpys);
+
+    // returns the material property phase change if set
+    boost::optional<MaterialPropertyPhaseChange> materialPropertyPhaseChange() const;
+
+    // resets the material property phase change
+    void resetMaterialPropertyPhaseChange();
+
+    // if material property phase change hysteresis already exists, do nothing and return nil; creates the material property phase change hysteresis if it does not already exist and return it
+    boost::optional<MaterialPropertyPhaseChangeHysteresis> createMaterialPropertyPhaseChangeHysteresis();
+
+    // returns the material property phase change hysteresis if set
+    boost::optional<MaterialPropertyPhaseChangeHysteresis> materialPropertyPhaseChangeHysteresis() const;
+
+    // resets the material property phase change hysteresis
+    void resetMaterialPropertyPhaseChangeHysteresis();
+
     //@}
     /** @name Other */
     //@{
diff --git a/src/model/MasslessOpaqueMaterial_Impl.hpp b/src/model/MasslessOpaqueMaterial_Impl.hpp
index e6be8060b9a..fbc82cac470 100644
--- a/src/model/MasslessOpaqueMaterial_Impl.hpp
+++ b/src/model/MasslessOpaqueMaterial_Impl.hpp
@@ -67,6 +67,9 @@ namespace model {
       /** @name Getters */
       //@{
 
+      // return any children objects in the hierarchy
+      virtual std::vector<ModelObject> children() const override;
+
       std::string roughness() const;
 
       /** The conductivitiy of the material in W/m*K. */
@@ -144,6 +147,38 @@ namespace model {
 
       void resetVisibleAbsorptance();
 
+      // if material property moisture penetration depth settings already exists, do nothing and return nil; creates the material property moisture penetration depth settings if it does not already exist and return it;
+      boost::optional<MaterialPropertyMoisturePenetrationDepthSettings>
+        createMaterialPropertyMoisturePenetrationDepthSettings(double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA,
+                                                               double moistureEquationCoefficientB, double moistureEquationCoefficientC,
+                                                               double moistureEquationCoefficientD, double coatingLayerThickness,
+                                                               double coatingLayerWaterVaporDiffusionResistanceFactor);
+
+      // returns the material property moisture penetration depth settings if set
+      boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> materialPropertyMoisturePenetrationDepthSettings() const;
+
+      // resets the material property moisture penetration depth settings
+      void resetMaterialPropertyMoisturePenetrationDepthSettings();
+
+      // if material property phase change already exists, do nothing and return nil; creates the material property phase change if it does not already exist and return it;
+      boost::optional<MaterialPropertyPhaseChange> createMaterialPropertyPhaseChange();
+      boost::optional<MaterialPropertyPhaseChange> createMaterialPropertyPhaseChange(const std::vector<TemperatureEnthalpy>& temperatureEnthalpys);
+
+      // returns the material property phase change if set
+      boost::optional<MaterialPropertyPhaseChange> materialPropertyPhaseChange() const;
+
+      // resets the material property phase change
+      void resetMaterialPropertyPhaseChange();
+
+      // if material property phase change hysteresis already exists, do nothing and return nil; creates the material property phase change hysteresis if it does not already exist and return it
+      boost::optional<MaterialPropertyPhaseChangeHysteresis> createMaterialPropertyPhaseChangeHysteresis();
+
+      // returns the material property phase change hysteresis if set
+      boost::optional<MaterialPropertyPhaseChangeHysteresis> materialPropertyPhaseChangeHysteresis() const;
+
+      // resets the material property phase change hysteresis
+      void resetMaterialPropertyPhaseChangeHysteresis();
+
       //@}
       /** @name Other */
       //@{
diff --git a/src/model/Material.cpp b/src/model/Material.cpp
index 6ecca59ae16..e793a93515d 100644
--- a/src/model/Material.cpp
+++ b/src/model/Material.cpp
@@ -34,8 +34,6 @@
 
 #include "Model.hpp"
 #include "Model_Impl.hpp"
-#include "MaterialPropertyMoisturePenetrationDepthSettings.hpp"
-#include "MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp"
 
 #include "../utilities/core/Assert.hpp"
 
@@ -55,10 +53,6 @@ namespace model {
     std::vector<ModelObject> Material_Impl::children() const {
       std::vector<ModelObject> results(castVector<ModelObject>(getObject<Material>().getModelObjectSources<StandardsInformationMaterial>()));
 
-      if (boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> empd = this->materialPropertyMoisturePenetrationDepthSettings()) {
-        results.push_back(empd.get());
-      }
-
       return results;
     }
 
@@ -92,45 +86,6 @@ namespace model {
       return StandardsInformationMaterial(getObject<Material>());
     }
 
-    boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> Material_Impl::createMaterialPropertyMoisturePenetrationDepthSettings(
-      double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA, double moistureEquationCoefficientB,
-      double moistureEquationCoefficientC, double moistureEquationCoefficientD, double coatingLayerThickness,
-      double coatingLayerWaterVaporDiffusionResistanceFactor) {
-      Material thisMaterial = getObject<Material>();
-      std::vector<MaterialPropertyMoisturePenetrationDepthSettings> empds =
-        thisMaterial.getModelObjectSources<MaterialPropertyMoisturePenetrationDepthSettings>(
-          MaterialPropertyMoisturePenetrationDepthSettings::iddObjectType());
-      if (!empds.empty()) {
-        return boost::none;
-      }
-
-      MaterialPropertyMoisturePenetrationDepthSettings empd(thisMaterial, waterVaporDiffusionResistanceFactor, moistureEquationCoefficientA,
-                                                            moistureEquationCoefficientB, moistureEquationCoefficientC, moistureEquationCoefficientD,
-                                                            coatingLayerThickness, coatingLayerWaterVaporDiffusionResistanceFactor);
-      return empd;
-    }
-
-    boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> Material_Impl::materialPropertyMoisturePenetrationDepthSettings() const {
-      std::vector<MaterialPropertyMoisturePenetrationDepthSettings> empds =
-        getObject<ModelObject>().getModelObjectSources<MaterialPropertyMoisturePenetrationDepthSettings>(
-          MaterialPropertyMoisturePenetrationDepthSettings::iddObjectType());
-      if (empds.empty()) {
-        // no error
-      } else if (empds.size() == 1) {
-        return empds[0];
-      } else {
-        // error
-      }
-      return boost::none;
-    }
-
-    void Material_Impl::resetMaterialPropertyMoisturePenetrationDepthSettings() {
-      boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> empd = this->materialPropertyMoisturePenetrationDepthSettings();
-      if (empd) {
-        empd->remove();
-      }
-    }
-
   }  // namespace detail
 
   Material::Material(IddObjectType type, const Model& model) : ResourceObject(type, model) {
@@ -161,24 +116,6 @@ namespace model {
     return getImpl<detail::Material_Impl>()->standardsInformation();
   }
 
-  boost::optional<MaterialPropertyMoisturePenetrationDepthSettings>
-    Material::createMaterialPropertyMoisturePenetrationDepthSettings(double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA,
-                                                                     double moistureEquationCoefficientB, double moistureEquationCoefficientC,
-                                                                     double moistureEquationCoefficientD, double coatingLayerThickness,
-                                                                     double coatingLayerWaterVaporDiffusionResistanceFactor) {
-    return getImpl<detail::Material_Impl>()->createMaterialPropertyMoisturePenetrationDepthSettings(
-      waterVaporDiffusionResistanceFactor, moistureEquationCoefficientA, moistureEquationCoefficientB, moistureEquationCoefficientC,
-      moistureEquationCoefficientD, coatingLayerThickness, coatingLayerWaterVaporDiffusionResistanceFactor);
-  }
-
-  boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> Material::materialPropertyMoisturePenetrationDepthSettings() const {
-    return getImpl<detail::Material_Impl>()->materialPropertyMoisturePenetrationDepthSettings();
-  }
-
-  void Material::resetMaterialPropertyMoisturePenetrationDepthSettings() {
-    getImpl<detail::Material_Impl>()->resetMaterialPropertyMoisturePenetrationDepthSettings();
-  }
-
   /// @cond
   Material::Material(std::shared_ptr<detail::Material_Impl> impl) : ResourceObject(std::move(impl)) {}
   /// @endcond
diff --git a/src/model/Material.hpp b/src/model/Material.hpp
index 4ed5366772b..f5b6e0c253a 100644
--- a/src/model/Material.hpp
+++ b/src/model/Material.hpp
@@ -33,14 +33,10 @@
 #include "ModelAPI.hpp"
 #include "ResourceObject.hpp"
 
-#include "MaterialPropertyMoisturePenetrationDepthSettings.hpp"
-#include "MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp"
-
 namespace openstudio {
 namespace model {
 
   class StandardsInformationMaterial;
-  class MaterialPropertyMoisturePenetrationDepthSettings;
 
   namespace detail {
     class Material_Impl;
@@ -82,19 +78,6 @@ namespace model {
     // Set thickness to value (m). For some materials, false is always returned.
     bool setThickness(double value);
 
-    // if material property moisture penetration depth settings already exists, do nothing and return nil; creates the material property moisture penetration depth settings if it does not already exist and return it
-    boost::optional<MaterialPropertyMoisturePenetrationDepthSettings>
-      createMaterialPropertyMoisturePenetrationDepthSettings(double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA,
-                                                             double moistureEquationCoefficientB, double moistureEquationCoefficientC,
-                                                             double moistureEquationCoefficientD, double coatingLayerThickness,
-                                                             double coatingLayerWaterVaporDiffusionResistanceFactor);
-
-    // returns the material property moisture penetration depth settings if set
-    boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> materialPropertyMoisturePenetrationDepthSettings() const;
-
-    // resets the material property moisture penetration depth settings
-    void resetMaterialPropertyMoisturePenetrationDepthSettings();
-
     //@}
    protected:
     /// @cond
diff --git a/src/model/MaterialPropertyMoisturePenetrationDepthSettings.cpp b/src/model/MaterialPropertyMoisturePenetrationDepthSettings.cpp
index 508046297b3..a064f7c1052 100644
--- a/src/model/MaterialPropertyMoisturePenetrationDepthSettings.cpp
+++ b/src/model/MaterialPropertyMoisturePenetrationDepthSettings.cpp
@@ -30,6 +30,10 @@
 #include <vector>
 #include "Material.hpp"
 #include "Material_Impl.hpp"
+#include "StandardOpaqueMaterial.hpp"
+#include "StandardOpaqueMaterial_Impl.hpp"
+#include "MasslessOpaqueMaterial.hpp"
+#include "MasslessOpaqueMaterial_Impl.hpp"
 #include "MaterialPropertyMoisturePenetrationDepthSettings.hpp"
 #include "MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp"
 #include "ModelExtensibleGroup.hpp"
@@ -78,6 +82,13 @@ namespace model {
       return material.get().name().get();
     }
 
+    Material MaterialPropertyMoisturePenetrationDepthSettings_Impl::material() const {
+      boost::optional<Material> material =
+        getObject<ModelObject>().getModelObjectTarget<Material>(OS_MaterialProperty_MoisturePenetrationDepth_SettingsFields::MaterialName);
+      OS_ASSERT(material);
+      return material.get();
+    }
+
     double MaterialPropertyMoisturePenetrationDepthSettings_Impl::waterVaporDiffusionResistanceFactor() const {
       boost::optional<double> value = getDouble(OS_MaterialProperty_MoisturePenetrationDepth_SettingsFields::WaterVaporDiffusionResistanceFactor);
       OS_ASSERT(value);
@@ -257,8 +268,50 @@ namespace model {
   }  // namespace detail
 
   MaterialPropertyMoisturePenetrationDepthSettings::MaterialPropertyMoisturePenetrationDepthSettings(
-    Material& material, double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA, double moistureEquationCoefficientB,
-    double moistureEquationCoefficientC, double moistureEquationCoefficientD, double coatingLayerThickness,
+    StandardOpaqueMaterial& material, double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA,
+    double moistureEquationCoefficientB, double moistureEquationCoefficientC, double moistureEquationCoefficientD, double coatingLayerThickness,
+    double coatingLayerWaterVaporDiffusionResistanceFactor)
+    : ModelObject(MaterialPropertyMoisturePenetrationDepthSettings::iddObjectType(), material.model()) {
+    OS_ASSERT(getImpl<detail::MaterialPropertyMoisturePenetrationDepthSettings_Impl>());
+
+    if (material.materialPropertyMoisturePenetrationDepthSettings()) {
+      LOG_AND_THROW("Material '" << material.nameString() << "' already has an associated MaterialPropertyMoisturePenetrationDepthSettings object");
+    }
+
+    bool ok = true;
+    OS_ASSERT(ok);
+
+    ok = setPointer(OS_MaterialProperty_MoisturePenetrationDepth_SettingsFields::MaterialName, material.handle());
+    OS_ASSERT(ok);
+
+    ok = setWaterVaporDiffusionResistanceFactor(waterVaporDiffusionResistanceFactor);
+    OS_ASSERT(ok);
+
+    ok = setMoistureEquationCoefficientA(moistureEquationCoefficientA);
+    OS_ASSERT(ok);
+
+    ok = setMoistureEquationCoefficientB(moistureEquationCoefficientB);
+    OS_ASSERT(ok);
+
+    ok = setMoistureEquationCoefficientC(moistureEquationCoefficientC);
+    OS_ASSERT(ok);
+
+    ok = setMoistureEquationCoefficientD(moistureEquationCoefficientD);
+    OS_ASSERT(ok);
+
+    autocalculateSurfaceLayerPenetrationDepth();
+    autocalculateDeepLayerPenetrationDepth();
+
+    ok = setCoatingLayerThickness(coatingLayerThickness);
+    OS_ASSERT(ok);
+
+    ok = setCoatingLayerWaterVaporDiffusionResistanceFactor(coatingLayerWaterVaporDiffusionResistanceFactor);
+    OS_ASSERT(ok);
+  }
+
+  MaterialPropertyMoisturePenetrationDepthSettings::MaterialPropertyMoisturePenetrationDepthSettings(
+    MasslessOpaqueMaterial& material, double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA,
+    double moistureEquationCoefficientB, double moistureEquationCoefficientC, double moistureEquationCoefficientD, double coatingLayerThickness,
     double coatingLayerWaterVaporDiffusionResistanceFactor)
     : ModelObject(MaterialPropertyMoisturePenetrationDepthSettings::iddObjectType(), material.model()) {
     OS_ASSERT(getImpl<detail::MaterialPropertyMoisturePenetrationDepthSettings_Impl>());
@@ -306,6 +359,10 @@ namespace model {
     return getImpl<detail::MaterialPropertyMoisturePenetrationDepthSettings_Impl>()->materialName();
   }
 
+  Material MaterialPropertyMoisturePenetrationDepthSettings::material() const {
+    return getImpl<detail::MaterialPropertyMoisturePenetrationDepthSettings_Impl>()->material();
+  }
+
   double MaterialPropertyMoisturePenetrationDepthSettings::waterVaporDiffusionResistanceFactor() const {
     return getImpl<detail::MaterialPropertyMoisturePenetrationDepthSettings_Impl>()->waterVaporDiffusionResistanceFactor();
   }
diff --git a/src/model/MaterialPropertyMoisturePenetrationDepthSettings.hpp b/src/model/MaterialPropertyMoisturePenetrationDepthSettings.hpp
index 2c290a11103..2a851af0d24 100644
--- a/src/model/MaterialPropertyMoisturePenetrationDepthSettings.hpp
+++ b/src/model/MaterialPropertyMoisturePenetrationDepthSettings.hpp
@@ -38,6 +38,8 @@ namespace openstudio {
 namespace model {
 
   class Material;
+  class StandardOpaqueMaterial;
+  class MasslessOpaqueMaterial;
 
   namespace detail {
 
@@ -52,7 +54,12 @@ namespace model {
     /** @name Constructors and Destructors */
     //@{
 
-    explicit MaterialPropertyMoisturePenetrationDepthSettings(Material& material, double waterVaporDiffusionResistanceFactor,
+    explicit MaterialPropertyMoisturePenetrationDepthSettings(StandardOpaqueMaterial& material, double waterVaporDiffusionResistanceFactor,
+                                                              double moistureEquationCoefficientA, double moistureEquationCoefficientB,
+                                                              double moistureEquationCoefficientC, double moistureEquationCoefficientD,
+                                                              double coatingLayerThickness, double coatingLayerWaterVaporDiffusionResistanceFactor);
+
+    explicit MaterialPropertyMoisturePenetrationDepthSettings(MasslessOpaqueMaterial& material, double waterVaporDiffusionResistanceFactor,
                                                               double moistureEquationCoefficientA, double moistureEquationCoefficientB,
                                                               double moistureEquationCoefficientC, double moistureEquationCoefficientD,
                                                               double coatingLayerThickness, double coatingLayerWaterVaporDiffusionResistanceFactor);
@@ -68,6 +75,8 @@ namespace model {
 
     std::string materialName() const;
 
+    Material material() const;
+
     double waterVaporDiffusionResistanceFactor() const;
 
     double moistureEquationCoefficientA() const;
diff --git a/src/model/MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp b/src/model/MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp
index 659ceaf33e8..aa1edb90db6 100644
--- a/src/model/MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp
+++ b/src/model/MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp
@@ -37,6 +37,8 @@
 namespace openstudio {
 namespace model {
 
+  class Material;
+
   namespace detail {
 
     /** MaterialPropertyMoisturePenetrationDepthSettings_Impl is a ModelObject_Impl that is the implementation class for MaterialPropertyMoisturePenetrationDepthSettings.*/
@@ -71,6 +73,8 @@ namespace model {
 
       std::string materialName() const;
 
+      Material material() const;
+
       double waterVaporDiffusionResistanceFactor() const;
 
       double moistureEquationCoefficientA() const;
diff --git a/src/model/MaterialPropertyPhaseChange.cpp b/src/model/MaterialPropertyPhaseChange.cpp
new file mode 100644
index 00000000000..33fbdf8d58b
--- /dev/null
+++ b/src/model/MaterialPropertyPhaseChange.cpp
@@ -0,0 +1,369 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include <vector>
+#include "Material.hpp"
+#include "Material_Impl.hpp"
+#include "StandardOpaqueMaterial.hpp"
+#include "StandardOpaqueMaterial_Impl.hpp"
+#include "MasslessOpaqueMaterial.hpp"
+#include "MasslessOpaqueMaterial_Impl.hpp"
+#include "MaterialPropertyPhaseChange.hpp"
+#include "MaterialPropertyPhaseChange_Impl.hpp"
+#include "ModelExtensibleGroup.hpp"
+#include "Model.hpp"
+#include "Model_Impl.hpp"
+
+#include <utilities/idd/IddEnums.hxx>
+#include <utilities/idd/OS_MaterialProperty_PhaseChange_FieldEnums.hxx>
+
+#include "../utilities/core/Assert.hpp"
+
+namespace openstudio {
+namespace model {
+
+  TemperatureEnthalpy::TemperatureEnthalpy(double temperature, double enthalpy) : m_temperature(temperature), m_enthalpy(enthalpy) {}
+
+  double TemperatureEnthalpy::temperature() const {
+    return m_temperature;
+  }
+
+  double TemperatureEnthalpy::enthalpy() const {
+    return m_enthalpy;
+  }
+
+  std::ostream& operator<<(std::ostream& out, const openstudio::model::TemperatureEnthalpy& temperatureEnthalpy) {
+    out << "temperature=" << temperatureEnthalpy.temperature() << ", enthalpy=" << temperatureEnthalpy.enthalpy();
+    return out;
+  }
+
+  namespace detail {
+
+    MaterialPropertyPhaseChange_Impl::MaterialPropertyPhaseChange_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle)
+      : ModelObject_Impl(idfObject, model, keepHandle) {
+      OS_ASSERT(idfObject.iddObject().type() == MaterialPropertyPhaseChange::iddObjectType());
+    }
+
+    MaterialPropertyPhaseChange_Impl::MaterialPropertyPhaseChange_Impl(const openstudio::detail::WorkspaceObject_Impl& other, Model_Impl* model,
+                                                                       bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {
+      OS_ASSERT(other.iddObject().type() == MaterialPropertyPhaseChange::iddObjectType());
+    }
+
+    MaterialPropertyPhaseChange_Impl::MaterialPropertyPhaseChange_Impl(const MaterialPropertyPhaseChange_Impl& other, Model_Impl* model,
+                                                                       bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {}
+
+    const std::vector<std::string>& MaterialPropertyPhaseChange_Impl::outputVariableNames() const {
+      static const std::vector<std::string> result;
+      return result;
+    }
+
+    IddObjectType MaterialPropertyPhaseChange_Impl::iddObjectType() const {
+      return MaterialPropertyPhaseChange::iddObjectType();
+    }
+
+    std::string MaterialPropertyPhaseChange_Impl::materialName() const {
+      boost::optional<Material> material =
+        getObject<ModelObject>().getModelObjectTarget<Material>(OS_MaterialProperty_PhaseChangeFields::MaterialName);
+      OS_ASSERT(material);
+      return material.get().name().get();
+    }
+
+    Material MaterialPropertyPhaseChange_Impl::material() const {
+      boost::optional<Material> material =
+        getObject<ModelObject>().getModelObjectTarget<Material>(OS_MaterialProperty_PhaseChangeFields::MaterialName);
+      OS_ASSERT(material);
+      return material.get();
+    }
+
+    double MaterialPropertyPhaseChange_Impl::temperatureCoefficientforThermalConductivity() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeFields::TemperatureCoefficientforThermalConductivity, true);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    bool MaterialPropertyPhaseChange_Impl::isTemperatureCoefficientforThermalConductivityDefaulted() const {
+      return isEmpty(OS_MaterialProperty_PhaseChangeFields::TemperatureCoefficientforThermalConductivity);
+    }
+
+    std::vector<TemperatureEnthalpy> MaterialPropertyPhaseChange_Impl::temperatureEnthalpys() const {
+      std::vector<TemperatureEnthalpy> result;
+
+      std::vector<IdfExtensibleGroup> groups = extensibleGroups();
+
+      for (const auto& group : groups) {
+        boost::optional<double> temperature =
+          group.cast<WorkspaceExtensibleGroup>().getDouble(OS_MaterialProperty_PhaseChangeExtensibleFields::Temperature);
+        boost::optional<double> enthalpy =
+          group.cast<WorkspaceExtensibleGroup>().getDouble(OS_MaterialProperty_PhaseChangeExtensibleFields::Enthalpy);
+
+        if (temperature && enthalpy) {
+          TemperatureEnthalpy temperatureEnthalpy(temperature.get(), enthalpy.get());
+          result.push_back(temperatureEnthalpy);
+        }
+      }
+
+      return result;
+    }
+
+    unsigned int MaterialPropertyPhaseChange_Impl::numberofTemperatureEnthalpys() const {
+      return numExtensibleGroups();
+    }
+
+    bool MaterialPropertyPhaseChange_Impl::setTemperatureCoefficientforThermalConductivity(double temperatureCoefficientforThermalConductivity) {
+      bool result =
+        setDouble(OS_MaterialProperty_PhaseChangeFields::TemperatureCoefficientforThermalConductivity, temperatureCoefficientforThermalConductivity);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    void MaterialPropertyPhaseChange_Impl::resetTemperatureCoefficientforThermalConductivity() {
+      bool result = setString(OS_MaterialProperty_PhaseChangeFields::TemperatureCoefficientforThermalConductivity, "");
+      OS_ASSERT(result);
+    }
+
+    bool MaterialPropertyPhaseChange_Impl::addTemperatureEnthalpy(const TemperatureEnthalpy& temperatureEnthalpy) {
+      bool result;
+
+      unsigned int num = numberofTemperatureEnthalpys();
+      // Max number of temperature-enthalpys is 16
+      if (num >= 16) {
+        LOG(Warn, briefDescription() << " already has 16 temperature-enthalpys which is the limit");
+        result = false;
+      } else {
+        // Push an extensible group
+        WorkspaceExtensibleGroup eg = getObject<ModelObject>().pushExtensibleGroup().cast<WorkspaceExtensibleGroup>();
+        bool temperature = eg.setDouble(OS_MaterialProperty_PhaseChangeExtensibleFields::Temperature, temperatureEnthalpy.temperature());
+        bool enthalpy = eg.setDouble(OS_MaterialProperty_PhaseChangeExtensibleFields::Enthalpy, temperatureEnthalpy.enthalpy());
+        if (temperature && enthalpy) {
+          result = true;
+        } else {
+          // Something went wrong
+          // So erase the new extensible group
+          getObject<ModelObject>().eraseExtensibleGroup(eg.groupIndex());
+          result = false;
+        }
+        result = true;
+      }
+      return result;
+    }
+
+    bool MaterialPropertyPhaseChange_Impl::addTemperatureEnthalpy(double temperature, double enthalpy) {
+      // Make a temperature-enthalpy, and then call the above function
+      TemperatureEnthalpy temperatureEnthalpy(temperature, enthalpy);
+      return addTemperatureEnthalpy(temperatureEnthalpy);
+    }
+
+    bool MaterialPropertyPhaseChange_Impl::addTemperatureEnthalpys(const std::vector<TemperatureEnthalpy>& temperatureEnthalpys) {
+      unsigned int num = numberofTemperatureEnthalpys();
+      if ((num + temperatureEnthalpys.size()) > 16) {
+        LOG(Warn, briefDescription() << " would have more than the 16 maximum temperature-enthalpys");
+        return false;
+      } else {
+        for (const TemperatureEnthalpy& temperatureEnthalpy : temperatureEnthalpys) {
+          addTemperatureEnthalpy(temperatureEnthalpy);
+        }
+        return true;
+      }
+    }
+
+    bool MaterialPropertyPhaseChange_Impl::removeTemperatureEnthalpy(unsigned groupIndex) {
+      bool result;
+
+      unsigned int num = numberofTemperatureEnthalpys();
+      if (groupIndex < num) {
+        getObject<ModelObject>().eraseExtensibleGroup(groupIndex);
+        result = true;
+      } else {
+        result = false;
+      }
+      return result;
+    }
+
+    void MaterialPropertyPhaseChange_Impl::removeAllTemperatureEnthalpys() {
+      getObject<ModelObject>().clearExtensibleGroups();
+    }
+
+  }  // namespace detail
+
+  MaterialPropertyPhaseChange::MaterialPropertyPhaseChange(StandardOpaqueMaterial& material)
+    : ModelObject(MaterialPropertyPhaseChange::iddObjectType(), material.model()) {
+    OS_ASSERT(getImpl<detail::MaterialPropertyPhaseChange_Impl>());
+
+    if (material.materialPropertyPhaseChange()) {
+      LOG_AND_THROW("Material '" << material.nameString() << "' already has an associated MaterialPropertyPhaseChange object");
+    }
+
+    bool ok = true;
+    OS_ASSERT(ok);
+
+    ok = setPointer(OS_MaterialProperty_PhaseChangeFields::MaterialName, material.handle());
+    OS_ASSERT(ok);
+
+    // These from CondFD1ZonePurchAirAutoSizeWithPCM.idf for E1 - 3 / 4 IN PLASTER OR GYP BOARD.
+    // They should be modified by user!
+    ok = addTemperatureEnthalpy(-20, 0.1);
+    OS_ASSERT(ok);
+    ok = addTemperatureEnthalpy(22, 18260);
+    OS_ASSERT(ok);
+    ok = addTemperatureEnthalpy(22.1, 32000);
+    OS_ASSERT(ok);
+    ok = addTemperatureEnthalpy(60, 71000);
+    OS_ASSERT(ok);
+  }
+
+  MaterialPropertyPhaseChange::MaterialPropertyPhaseChange(MasslessOpaqueMaterial& material)
+    : ModelObject(MaterialPropertyPhaseChange::iddObjectType(), material.model()) {
+    OS_ASSERT(getImpl<detail::MaterialPropertyPhaseChange_Impl>());
+
+    if (material.materialPropertyPhaseChange()) {
+      LOG_AND_THROW("Material '" << material.nameString() << "' already has an associated MaterialPropertyPhaseChange object");
+    }
+
+    bool ok = true;
+    OS_ASSERT(ok);
+
+    ok = setPointer(OS_MaterialProperty_PhaseChangeFields::MaterialName, material.handle());
+    OS_ASSERT(ok);
+
+    // These from CondFD1ZonePurchAirAutoSizeWithPCM.idf for E1 - 3 / 4 IN PLASTER OR GYP BOARD.
+    // They should be modified by user!
+    ok = addTemperatureEnthalpy(-20, 0.1);
+    OS_ASSERT(ok);
+    ok = addTemperatureEnthalpy(22, 18260);
+    OS_ASSERT(ok);
+    ok = addTemperatureEnthalpy(22.1, 32000);
+    OS_ASSERT(ok);
+    ok = addTemperatureEnthalpy(60, 71000);
+    OS_ASSERT(ok);
+  }
+
+  MaterialPropertyPhaseChange::MaterialPropertyPhaseChange(StandardOpaqueMaterial& material,
+                                                           const std::vector<TemperatureEnthalpy>& temperatureEnthalpys)
+    : ModelObject(MaterialPropertyPhaseChange::iddObjectType(), material.model()) {
+    OS_ASSERT(getImpl<detail::MaterialPropertyPhaseChange_Impl>());
+
+    if (material.materialPropertyPhaseChange()) {
+      LOG_AND_THROW("Material '" << material.nameString() << "' already has an associated MaterialPropertyPhaseChange object");
+    }
+
+    bool ok = true;
+    OS_ASSERT(ok);
+
+    ok = setPointer(OS_MaterialProperty_PhaseChangeFields::MaterialName, material.handle());
+    OS_ASSERT(ok);
+
+    ok = addTemperatureEnthalpys(temperatureEnthalpys);
+    OS_ASSERT(ok);
+  }
+
+  MaterialPropertyPhaseChange::MaterialPropertyPhaseChange(MasslessOpaqueMaterial& material,
+                                                           const std::vector<TemperatureEnthalpy>& temperatureEnthalpys)
+    : ModelObject(MaterialPropertyPhaseChange::iddObjectType(), material.model()) {
+    OS_ASSERT(getImpl<detail::MaterialPropertyPhaseChange_Impl>());
+
+    if (material.materialPropertyPhaseChange()) {
+      LOG_AND_THROW("Material '" << material.nameString() << "' already has an associated MaterialPropertyPhaseChange object");
+    }
+
+    bool ok = true;
+    OS_ASSERT(ok);
+
+    ok = setPointer(OS_MaterialProperty_PhaseChangeFields::MaterialName, material.handle());
+    OS_ASSERT(ok);
+
+    ok = addTemperatureEnthalpys(temperatureEnthalpys);
+    OS_ASSERT(ok);
+  }
+
+  IddObjectType MaterialPropertyPhaseChange::iddObjectType() {
+    return IddObjectType(IddObjectType::OS_MaterialProperty_PhaseChange);
+  }
+
+  std::string MaterialPropertyPhaseChange::materialName() const {
+    return getImpl<detail::MaterialPropertyPhaseChange_Impl>()->materialName();
+  }
+
+  Material MaterialPropertyPhaseChange::material() const {
+    return getImpl<detail::MaterialPropertyPhaseChange_Impl>()->material();
+  }
+
+  double MaterialPropertyPhaseChange::temperatureCoefficientforThermalConductivity() const {
+    return getImpl<detail::MaterialPropertyPhaseChange_Impl>()->temperatureCoefficientforThermalConductivity();
+  }
+
+  bool MaterialPropertyPhaseChange::isTemperatureCoefficientforThermalConductivityDefaulted() const {
+    return getImpl<detail::MaterialPropertyPhaseChange_Impl>()->isTemperatureCoefficientforThermalConductivityDefaulted();
+  }
+
+  std::vector<TemperatureEnthalpy> MaterialPropertyPhaseChange::temperatureEnthalpys() const {
+    return getImpl<detail::MaterialPropertyPhaseChange_Impl>()->temperatureEnthalpys();
+  }
+
+  unsigned int MaterialPropertyPhaseChange::numberofTemperatureEnthalpys() const {
+    return getImpl<detail::MaterialPropertyPhaseChange_Impl>()->numberofTemperatureEnthalpys();
+  }
+
+  bool MaterialPropertyPhaseChange::setTemperatureCoefficientforThermalConductivity(double temperatureCoefficientforThermalConductivity) {
+    return getImpl<detail::MaterialPropertyPhaseChange_Impl>()->setTemperatureCoefficientforThermalConductivity(
+      temperatureCoefficientforThermalConductivity);
+  }
+
+  void MaterialPropertyPhaseChange::resetTemperatureCoefficientforThermalConductivity() {
+    getImpl<detail::MaterialPropertyPhaseChange_Impl>()->resetTemperatureCoefficientforThermalConductivity();
+  }
+
+  bool MaterialPropertyPhaseChange::addTemperatureEnthalpy(const TemperatureEnthalpy& temperatureEnthalpy) {
+    return getImpl<detail::MaterialPropertyPhaseChange_Impl>()->addTemperatureEnthalpy(temperatureEnthalpy);
+  }
+
+  bool MaterialPropertyPhaseChange::addTemperatureEnthalpy(double temperature, double enthalpy) {
+    return getImpl<detail::MaterialPropertyPhaseChange_Impl>()->addTemperatureEnthalpy(temperature, enthalpy);
+  }
+
+  bool MaterialPropertyPhaseChange::addTemperatureEnthalpys(const std::vector<TemperatureEnthalpy>& temperatureEnthalpys) {
+    return getImpl<detail::MaterialPropertyPhaseChange_Impl>()->addTemperatureEnthalpys(temperatureEnthalpys);
+  }
+
+  void MaterialPropertyPhaseChange::removeTemperatureEnthalpy(unsigned groupIndex) {
+    getImpl<detail::MaterialPropertyPhaseChange_Impl>()->removeTemperatureEnthalpy(groupIndex);
+  }
+
+  void MaterialPropertyPhaseChange::removeAllTemperatureEnthalpys() {
+    getImpl<detail::MaterialPropertyPhaseChange_Impl>()->removeAllTemperatureEnthalpys();
+  }
+
+  /// @cond
+  MaterialPropertyPhaseChange::MaterialPropertyPhaseChange(std::shared_ptr<detail::MaterialPropertyPhaseChange_Impl> impl)
+    : ModelObject(std::move(impl)) {}
+  /// @endcond
+
+}  // namespace model
+}  // namespace openstudio
diff --git a/src/model/MaterialPropertyPhaseChange.hpp b/src/model/MaterialPropertyPhaseChange.hpp
new file mode 100644
index 00000000000..d9ea301b265
--- /dev/null
+++ b/src/model/MaterialPropertyPhaseChange.hpp
@@ -0,0 +1,151 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#ifndef MODEL_MATERIALPROPERTYPHASECHANGE_HPP
+#define MODEL_MATERIALPROPERTYPHASECHANGE_HPP
+
+#include <vector>
+#include "ModelAPI.hpp"
+#include "ModelObject.hpp"
+
+namespace openstudio {
+namespace model {
+
+  class Material;
+  class StandardOpaqueMaterial;
+  class MasslessOpaqueMaterial;
+
+  namespace detail {
+
+    class MaterialPropertyPhaseChange_Impl;
+
+  }  // namespace detail
+
+  /** This class implements a temperature enthalpy */
+  class MODEL_API TemperatureEnthalpy
+  {
+   public:
+    TemperatureEnthalpy(double temperature, double enthalpy);
+
+    double temperature() const;
+    double enthalpy() const;
+
+   private:
+    double m_temperature;
+    double m_enthalpy;
+    REGISTER_LOGGER("openstudio.model.TemperatureEnthalpy");
+  };
+
+  // Overload operator<<
+  MODEL_API std::ostream& operator<<(std::ostream& out, const openstudio::model::TemperatureEnthalpy& temperatureEnthalpy);
+
+  /** MaterialPropertyPhaseChange is a ModelObject that wraps the OpenStudio IDD object 'OS:MaterialProperty:PhaseChange'. */
+  class MODEL_API MaterialPropertyPhaseChange : public ModelObject
+  {
+   public:
+    /** @name Constructors and Destructors */
+    //@{
+
+    explicit MaterialPropertyPhaseChange(StandardOpaqueMaterial& material);
+
+    explicit MaterialPropertyPhaseChange(MasslessOpaqueMaterial& material);
+
+    explicit MaterialPropertyPhaseChange(StandardOpaqueMaterial& material, const std::vector<TemperatureEnthalpy>& temperatureEnthalpys);
+
+    explicit MaterialPropertyPhaseChange(MasslessOpaqueMaterial& material, const std::vector<TemperatureEnthalpy>& temperatureEnthalpys);
+
+    virtual ~MaterialPropertyPhaseChange() {}
+
+    //@}
+
+    static IddObjectType iddObjectType();
+
+    /** @name Getters */
+    //@{
+
+    std::string materialName() const;
+
+    Material material() const;
+
+    double temperatureCoefficientforThermalConductivity() const;
+
+    bool isTemperatureCoefficientforThermalConductivityDefaulted() const;
+
+    std::vector<TemperatureEnthalpy> temperatureEnthalpys() const;
+
+    unsigned int numberofTemperatureEnthalpys() const;
+
+    //@}
+    /** @name Setters */
+    //@{
+
+    bool setTemperatureCoefficientforThermalConductivity(double temperatureCoefficientforThermalConductivity);
+
+    void resetTemperatureCoefficientforThermalConductivity();
+
+    bool addTemperatureEnthalpy(const TemperatureEnthalpy& temperatureEnthalpy);
+
+    bool addTemperatureEnthalpy(double temperature, double enthalpy);
+
+    bool addTemperatureEnthalpys(const std::vector<TemperatureEnthalpy>& temperatureEnthalpys);
+
+    void removeTemperatureEnthalpy(unsigned groupIndex);
+
+    void removeAllTemperatureEnthalpys();
+
+    //@}
+    /** @name Other */
+    //@{
+
+    //@}
+   protected:
+    /// @cond
+    typedef detail::MaterialPropertyPhaseChange_Impl ImplType;
+
+    explicit MaterialPropertyPhaseChange(std::shared_ptr<detail::MaterialPropertyPhaseChange_Impl> impl);
+
+    friend class detail::MaterialPropertyPhaseChange_Impl;
+    friend class Model;
+    friend class IdfObject;
+    friend class openstudio::detail::IdfObject_Impl;
+    /// @endcond
+   private:
+    REGISTER_LOGGER("openstudio.model.MaterialPropertyPhaseChange");
+  };
+
+  /** \relates MaterialPropertyPhaseChange*/
+  typedef boost::optional<MaterialPropertyPhaseChange> OptionalMaterialPropertyPhaseChange;
+
+  /** \relates MaterialPropertyPhaseChange*/
+  typedef std::vector<MaterialPropertyPhaseChange> MaterialPropertyPhaseChangeVector;
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_MATERIALPROPERTYPHASECHANGE_HPP
diff --git a/src/model/MaterialPropertyPhaseChangeHysteresis.cpp b/src/model/MaterialPropertyPhaseChangeHysteresis.cpp
new file mode 100644
index 00000000000..f5a874e074c
--- /dev/null
+++ b/src/model/MaterialPropertyPhaseChangeHysteresis.cpp
@@ -0,0 +1,472 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include <vector>
+#include "Material.hpp"
+#include "Material_Impl.hpp"
+#include "StandardOpaqueMaterial.hpp"
+#include "StandardOpaqueMaterial_Impl.hpp"
+#include "MasslessOpaqueMaterial.hpp"
+#include "MasslessOpaqueMaterial_Impl.hpp"
+#include "MaterialPropertyPhaseChangeHysteresis.hpp"
+#include "MaterialPropertyPhaseChangeHysteresis_Impl.hpp"
+#include "ModelExtensibleGroup.hpp"
+#include "Model.hpp"
+#include "Model_Impl.hpp"
+
+#include <utilities/idd/IddEnums.hxx>
+#include <utilities/idd/OS_MaterialProperty_PhaseChangeHysteresis_FieldEnums.hxx>
+
+#include "../utilities/core/Assert.hpp"
+
+namespace openstudio {
+namespace model {
+
+  namespace detail {
+
+    MaterialPropertyPhaseChangeHysteresis_Impl::MaterialPropertyPhaseChangeHysteresis_Impl(const IdfObject& idfObject, Model_Impl* model,
+                                                                                           bool keepHandle)
+      : ModelObject_Impl(idfObject, model, keepHandle) {
+      OS_ASSERT(idfObject.iddObject().type() == MaterialPropertyPhaseChangeHysteresis::iddObjectType());
+    }
+
+    MaterialPropertyPhaseChangeHysteresis_Impl::MaterialPropertyPhaseChangeHysteresis_Impl(const openstudio::detail::WorkspaceObject_Impl& other,
+                                                                                           Model_Impl* model, bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {
+      OS_ASSERT(other.iddObject().type() == MaterialPropertyPhaseChangeHysteresis::iddObjectType());
+    }
+
+    MaterialPropertyPhaseChangeHysteresis_Impl::MaterialPropertyPhaseChangeHysteresis_Impl(const MaterialPropertyPhaseChangeHysteresis_Impl& other,
+                                                                                           Model_Impl* model, bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {}
+
+    const std::vector<std::string>& MaterialPropertyPhaseChangeHysteresis_Impl::outputVariableNames() const {
+      static const std::vector<std::string> result;
+      return result;
+    }
+
+    IddObjectType MaterialPropertyPhaseChangeHysteresis_Impl::iddObjectType() const {
+      return MaterialPropertyPhaseChangeHysteresis::iddObjectType();
+    }
+
+    std::string MaterialPropertyPhaseChangeHysteresis_Impl::materialName() const {
+      boost::optional<Material> material =
+        getObject<ModelObject>().getModelObjectTarget<Material>(OS_MaterialProperty_PhaseChangeHysteresisFields::MaterialName);
+      OS_ASSERT(material);
+      return material.get().name().get();
+    }
+
+    Material MaterialPropertyPhaseChangeHysteresis_Impl::material() const {
+      boost::optional<Material> material =
+        getObject<ModelObject>().getModelObjectTarget<Material>(OS_MaterialProperty_PhaseChangeHysteresisFields::MaterialName);
+      OS_ASSERT(material);
+      return material.get();
+    }
+
+    double MaterialPropertyPhaseChangeHysteresis_Impl::latentHeatduringtheEntirePhaseChangeProcess() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::LatentHeatduringtheEntirePhaseChangeProcess);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double MaterialPropertyPhaseChangeHysteresis_Impl::liquidStateThermalConductivity() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::LiquidStateThermalConductivity);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double MaterialPropertyPhaseChangeHysteresis_Impl::liquidStateDensity() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::LiquidStateDensity);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double MaterialPropertyPhaseChangeHysteresis_Impl::liquidStateSpecificHeat() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::LiquidStateSpecificHeat);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double MaterialPropertyPhaseChangeHysteresis_Impl::highTemperatureDifferenceofMeltingCurve() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::HighTemperatureDifferenceofMeltingCurve);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double MaterialPropertyPhaseChangeHysteresis_Impl::peakMeltingTemperature() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::PeakMeltingTemperature);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double MaterialPropertyPhaseChangeHysteresis_Impl::lowTemperatureDifferenceofMeltingCurve() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::LowTemperatureDifferenceofMeltingCurve);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double MaterialPropertyPhaseChangeHysteresis_Impl::solidStateThermalConductivity() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::SolidStateThermalConductivity);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double MaterialPropertyPhaseChangeHysteresis_Impl::solidStateDensity() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::SolidStateDensity);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double MaterialPropertyPhaseChangeHysteresis_Impl::solidStateSpecificHeat() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::SolidStateSpecificHeat);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double MaterialPropertyPhaseChangeHysteresis_Impl::highTemperatureDifferenceofFreezingCurve() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::HighTemperatureDifferenceofFreezingCurve);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double MaterialPropertyPhaseChangeHysteresis_Impl::peakFreezingTemperature() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::PeakFreezingTemperature);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double MaterialPropertyPhaseChangeHysteresis_Impl::lowTemperatureDifferenceofFreezingCurve() const {
+      boost::optional<double> value = getDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::LowTemperatureDifferenceofFreezingCurve);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    bool
+      MaterialPropertyPhaseChangeHysteresis_Impl::setLatentHeatduringtheEntirePhaseChangeProcess(double latentHeatduringtheEntirePhaseChangeProcess) {
+      bool result = setDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::LatentHeatduringtheEntirePhaseChangeProcess,
+                              latentHeatduringtheEntirePhaseChangeProcess);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    bool MaterialPropertyPhaseChangeHysteresis_Impl::setLiquidStateThermalConductivity(double liquidStateThermalConductivity) {
+      bool result = setDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::LiquidStateThermalConductivity, liquidStateThermalConductivity);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    bool MaterialPropertyPhaseChangeHysteresis_Impl::setLiquidStateDensity(double liquidStateDensity) {
+      bool result = setDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::LiquidStateDensity, liquidStateDensity);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    bool MaterialPropertyPhaseChangeHysteresis_Impl::setLiquidStateSpecificHeat(double liquidStateSpecificHeat) {
+      bool result = setDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::LiquidStateSpecificHeat, liquidStateSpecificHeat);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    bool MaterialPropertyPhaseChangeHysteresis_Impl::setHighTemperatureDifferenceofMeltingCurve(double highTemperatureDifferenceofMeltingCurve) {
+      bool result =
+        setDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::HighTemperatureDifferenceofMeltingCurve, highTemperatureDifferenceofMeltingCurve);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    bool MaterialPropertyPhaseChangeHysteresis_Impl::setPeakMeltingTemperature(double peakMeltingTemperature) {
+      bool result = setDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::PeakMeltingTemperature, peakMeltingTemperature);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    bool MaterialPropertyPhaseChangeHysteresis_Impl::setLowTemperatureDifferenceofMeltingCurve(double lowTemperatureDifferenceofMeltingCurve) {
+      bool result =
+        setDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::LowTemperatureDifferenceofMeltingCurve, lowTemperatureDifferenceofMeltingCurve);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    bool MaterialPropertyPhaseChangeHysteresis_Impl::setSolidStateThermalConductivity(double solidStateThermalConductivity) {
+      bool result = setDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::SolidStateThermalConductivity, solidStateThermalConductivity);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    bool MaterialPropertyPhaseChangeHysteresis_Impl::setSolidStateDensity(double solidStateDensity) {
+      bool result = setDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::SolidStateDensity, solidStateDensity);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    bool MaterialPropertyPhaseChangeHysteresis_Impl::setSolidStateSpecificHeat(double solidStateSpecificHeat) {
+      bool result = setDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::SolidStateSpecificHeat, solidStateSpecificHeat);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    bool MaterialPropertyPhaseChangeHysteresis_Impl::setHighTemperatureDifferenceofFreezingCurve(double highTemperatureDifferenceofFreezingCurve) {
+      bool result = setDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::HighTemperatureDifferenceofFreezingCurve,
+                              highTemperatureDifferenceofFreezingCurve);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    bool MaterialPropertyPhaseChangeHysteresis_Impl::setPeakFreezingTemperature(double peakFreezingTemperature) {
+      bool result = setDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::PeakFreezingTemperature, peakFreezingTemperature);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    bool MaterialPropertyPhaseChangeHysteresis_Impl::setLowTemperatureDifferenceofFreezingCurve(double lowTemperatureDifferenceofFreezingCurve) {
+      bool result =
+        setDouble(OS_MaterialProperty_PhaseChangeHysteresisFields::LowTemperatureDifferenceofFreezingCurve, lowTemperatureDifferenceofFreezingCurve);
+      OS_ASSERT(result);
+      return result;
+    }
+
+  }  // namespace detail
+
+  MaterialPropertyPhaseChangeHysteresis::MaterialPropertyPhaseChangeHysteresis(StandardOpaqueMaterial& material)
+    : ModelObject(MaterialPropertyPhaseChangeHysteresis::iddObjectType(), material.model()) {
+    OS_ASSERT(getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>());
+
+    if (material.materialPropertyPhaseChangeHysteresis()) {
+      LOG_AND_THROW("Material '" << material.nameString() << "' already has an associated MaterialPropertyPhaseChangeHysteresis object");
+    }
+
+    bool ok = true;
+    OS_ASSERT(ok);
+
+    ok = setPointer(OS_MaterialProperty_PhaseChangeHysteresisFields::MaterialName, material.handle());
+    OS_ASSERT(ok);
+
+    // These from 1ZoneUncontrolledWithHysteresisPCM.idf for C5 - 4 IN HW CONCRETE.
+    // They should be modified by user!
+    ok = setLatentHeatduringtheEntirePhaseChangeProcess(10000);
+    OS_ASSERT(ok);
+    ok = setLiquidStateThermalConductivity(1.5);
+    OS_ASSERT(ok);
+    ok = setLiquidStateDensity(2200);
+    OS_ASSERT(ok);
+    ok = setLiquidStateSpecificHeat(2000);
+    OS_ASSERT(ok);
+    ok = setHighTemperatureDifferenceofMeltingCurve(1);
+    OS_ASSERT(ok);
+    ok = setPeakMeltingTemperature(23);
+    OS_ASSERT(ok);
+    ok = setLowTemperatureDifferenceofMeltingCurve(1);
+    OS_ASSERT(ok);
+    ok = setSolidStateThermalConductivity(1.8);
+    OS_ASSERT(ok);
+    ok = setSolidStateDensity(2300);
+    OS_ASSERT(ok);
+    ok = setSolidStateSpecificHeat(2000);
+    OS_ASSERT(ok);
+    ok = setHighTemperatureDifferenceofFreezingCurve(1);
+    OS_ASSERT(ok);
+    ok = setPeakFreezingTemperature(20);
+    OS_ASSERT(ok);
+    ok = setLowTemperatureDifferenceofFreezingCurve(1);
+    OS_ASSERT(ok);
+  }
+
+  MaterialPropertyPhaseChangeHysteresis::MaterialPropertyPhaseChangeHysteresis(MasslessOpaqueMaterial& material)
+    : ModelObject(MaterialPropertyPhaseChangeHysteresis::iddObjectType(), material.model()) {
+    OS_ASSERT(getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>());
+
+    if (material.materialPropertyPhaseChangeHysteresis()) {
+      LOG_AND_THROW("Material '" << material.nameString() << "' already has an associated MaterialPropertyPhaseChangeHysteresis object");
+    }
+
+    bool ok = true;
+    OS_ASSERT(ok);
+
+    ok = setPointer(OS_MaterialProperty_PhaseChangeHysteresisFields::MaterialName, material.handle());
+    OS_ASSERT(ok);
+
+    // These from 1ZoneUncontrolledWithHysteresisPCM.idf for C5 - 4 IN HW CONCRETE.
+    // They should be modified by user!
+    ok = setLatentHeatduringtheEntirePhaseChangeProcess(10000);
+    OS_ASSERT(ok);
+    ok = setLiquidStateThermalConductivity(1.5);
+    OS_ASSERT(ok);
+    ok = setLiquidStateDensity(2200);
+    OS_ASSERT(ok);
+    ok = setLiquidStateSpecificHeat(2000);
+    OS_ASSERT(ok);
+    ok = setHighTemperatureDifferenceofMeltingCurve(1);
+    OS_ASSERT(ok);
+    ok = setPeakMeltingTemperature(23);
+    OS_ASSERT(ok);
+    ok = setLowTemperatureDifferenceofMeltingCurve(1);
+    OS_ASSERT(ok);
+    ok = setSolidStateThermalConductivity(1.8);
+    OS_ASSERT(ok);
+    ok = setSolidStateDensity(2300);
+    OS_ASSERT(ok);
+    ok = setSolidStateSpecificHeat(2000);
+    OS_ASSERT(ok);
+    ok = setHighTemperatureDifferenceofFreezingCurve(1);
+    OS_ASSERT(ok);
+    ok = setPeakFreezingTemperature(20);
+    OS_ASSERT(ok);
+    ok = setLowTemperatureDifferenceofFreezingCurve(1);
+    OS_ASSERT(ok);
+  }
+
+  IddObjectType MaterialPropertyPhaseChangeHysteresis::iddObjectType() {
+    return IddObjectType(IddObjectType::OS_MaterialProperty_PhaseChangeHysteresis);
+  }
+
+  std::string MaterialPropertyPhaseChangeHysteresis::materialName() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->materialName();
+  }
+
+  Material MaterialPropertyPhaseChangeHysteresis::material() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->material();
+  }
+
+  double MaterialPropertyPhaseChangeHysteresis::latentHeatduringtheEntirePhaseChangeProcess() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->latentHeatduringtheEntirePhaseChangeProcess();
+  }
+
+  double MaterialPropertyPhaseChangeHysteresis::liquidStateThermalConductivity() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->liquidStateThermalConductivity();
+  }
+
+  double MaterialPropertyPhaseChangeHysteresis::liquidStateDensity() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->liquidStateDensity();
+  }
+
+  double MaterialPropertyPhaseChangeHysteresis::liquidStateSpecificHeat() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->liquidStateSpecificHeat();
+  }
+
+  double MaterialPropertyPhaseChangeHysteresis::highTemperatureDifferenceofMeltingCurve() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->highTemperatureDifferenceofMeltingCurve();
+  }
+
+  double MaterialPropertyPhaseChangeHysteresis::peakMeltingTemperature() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->peakMeltingTemperature();
+  }
+
+  double MaterialPropertyPhaseChangeHysteresis::lowTemperatureDifferenceofMeltingCurve() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->lowTemperatureDifferenceofMeltingCurve();
+  }
+
+  double MaterialPropertyPhaseChangeHysteresis::solidStateThermalConductivity() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->solidStateThermalConductivity();
+  }
+
+  double MaterialPropertyPhaseChangeHysteresis::solidStateDensity() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->solidStateDensity();
+  }
+
+  double MaterialPropertyPhaseChangeHysteresis::solidStateSpecificHeat() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->solidStateSpecificHeat();
+  }
+
+  double MaterialPropertyPhaseChangeHysteresis::highTemperatureDifferenceofFreezingCurve() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->highTemperatureDifferenceofFreezingCurve();
+  }
+
+  double MaterialPropertyPhaseChangeHysteresis::peakFreezingTemperature() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->peakFreezingTemperature();
+  }
+
+  double MaterialPropertyPhaseChangeHysteresis::lowTemperatureDifferenceofFreezingCurve() const {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->lowTemperatureDifferenceofFreezingCurve();
+  }
+
+  bool MaterialPropertyPhaseChangeHysteresis::setLatentHeatduringtheEntirePhaseChangeProcess(double latentHeatduringtheEntirePhaseChangeProcess) {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->setLatentHeatduringtheEntirePhaseChangeProcess(
+      latentHeatduringtheEntirePhaseChangeProcess);
+  }
+
+  bool MaterialPropertyPhaseChangeHysteresis::setLiquidStateThermalConductivity(double liquidStateThermalConductivity) {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->setLiquidStateThermalConductivity(liquidStateThermalConductivity);
+  }
+
+  bool MaterialPropertyPhaseChangeHysteresis::setLiquidStateDensity(double liquidStateDensity) {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->setLiquidStateDensity(liquidStateDensity);
+  }
+
+  bool MaterialPropertyPhaseChangeHysteresis::setLiquidStateSpecificHeat(double liquidStateSpecificHeat) {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->setLiquidStateSpecificHeat(liquidStateSpecificHeat);
+  }
+
+  bool MaterialPropertyPhaseChangeHysteresis::setHighTemperatureDifferenceofMeltingCurve(double highTemperatureDifferenceofMeltingCurve) {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->setHighTemperatureDifferenceofMeltingCurve(
+      highTemperatureDifferenceofMeltingCurve);
+  }
+
+  bool MaterialPropertyPhaseChangeHysteresis::setPeakMeltingTemperature(double peakMeltingTemperature) {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->setPeakMeltingTemperature(peakMeltingTemperature);
+  }
+
+  bool MaterialPropertyPhaseChangeHysteresis::setLowTemperatureDifferenceofMeltingCurve(double lowTemperatureDifferenceofMeltingCurve) {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->setLowTemperatureDifferenceofMeltingCurve(
+      lowTemperatureDifferenceofMeltingCurve);
+  }
+
+  bool MaterialPropertyPhaseChangeHysteresis::setSolidStateThermalConductivity(double solidStateThermalConductivity) {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->setSolidStateThermalConductivity(solidStateThermalConductivity);
+  }
+
+  bool MaterialPropertyPhaseChangeHysteresis::setSolidStateDensity(double solidStateDensity) {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->setSolidStateDensity(solidStateDensity);
+  }
+
+  bool MaterialPropertyPhaseChangeHysteresis::setSolidStateSpecificHeat(double solidStateSpecificHeat) {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->setSolidStateSpecificHeat(solidStateSpecificHeat);
+  }
+
+  bool MaterialPropertyPhaseChangeHysteresis::setHighTemperatureDifferenceofFreezingCurve(double highTemperatureDifferenceofFreezingCurve) {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->setHighTemperatureDifferenceofFreezingCurve(
+      highTemperatureDifferenceofFreezingCurve);
+  }
+
+  bool MaterialPropertyPhaseChangeHysteresis::setPeakFreezingTemperature(double peakFreezingTemperature) {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->setPeakFreezingTemperature(peakFreezingTemperature);
+  }
+
+  bool MaterialPropertyPhaseChangeHysteresis::setLowTemperatureDifferenceofFreezingCurve(double lowTemperatureDifferenceofFreezingCurve) {
+    return getImpl<detail::MaterialPropertyPhaseChangeHysteresis_Impl>()->setLowTemperatureDifferenceofFreezingCurve(
+      lowTemperatureDifferenceofFreezingCurve);
+  }
+
+  /// @cond
+  MaterialPropertyPhaseChangeHysteresis::MaterialPropertyPhaseChangeHysteresis(
+    std::shared_ptr<detail::MaterialPropertyPhaseChangeHysteresis_Impl> impl)
+    : ModelObject(std::move(impl)) {}
+  /// @endcond
+
+}  // namespace model
+}  // namespace openstudio
diff --git a/src/model/MaterialPropertyPhaseChangeHysteresis.hpp b/src/model/MaterialPropertyPhaseChangeHysteresis.hpp
new file mode 100644
index 00000000000..6040e36744d
--- /dev/null
+++ b/src/model/MaterialPropertyPhaseChangeHysteresis.hpp
@@ -0,0 +1,159 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#ifndef MODEL_MATERIALPROPERTYPHASECHANGEHYSTERESIS_HPP
+#define MODEL_MATERIALPROPERTYPHASECHANGEHYSTERESIS_HPP
+
+#include <vector>
+#include "ModelAPI.hpp"
+#include "ModelObject.hpp"
+
+namespace openstudio {
+namespace model {
+
+  class Material;
+  class StandardOpaqueMaterial;
+  class MasslessOpaqueMaterial;
+
+  namespace detail {
+
+    class MaterialPropertyPhaseChangeHysteresis_Impl;
+
+  }  // namespace detail
+
+  /** MaterialPropertyPhaseChangeHysteresis is a ModelObject that wraps the OpenStudio IDD object 'OS:MaterialProperty:PhaseChangeHysteresis'. */
+  class MODEL_API MaterialPropertyPhaseChangeHysteresis : public ModelObject
+  {
+   public:
+    /** @name Constructors and Destructors */
+    //@{
+
+    explicit MaterialPropertyPhaseChangeHysteresis(StandardOpaqueMaterial& material);
+
+    explicit MaterialPropertyPhaseChangeHysteresis(MasslessOpaqueMaterial& material);
+
+    virtual ~MaterialPropertyPhaseChangeHysteresis() {}
+
+    //@}
+
+    static IddObjectType iddObjectType();
+
+    /** @name Getters */
+    //@{
+
+    std::string materialName() const;
+
+    Material material() const;
+
+    double latentHeatduringtheEntirePhaseChangeProcess() const;
+
+    double liquidStateThermalConductivity() const;
+
+    double liquidStateDensity() const;
+
+    double liquidStateSpecificHeat() const;
+
+    double highTemperatureDifferenceofMeltingCurve() const;
+
+    double peakMeltingTemperature() const;
+
+    double lowTemperatureDifferenceofMeltingCurve() const;
+
+    double solidStateThermalConductivity() const;
+
+    double solidStateDensity() const;
+
+    double solidStateSpecificHeat() const;
+
+    double highTemperatureDifferenceofFreezingCurve() const;
+
+    double peakFreezingTemperature() const;
+
+    double lowTemperatureDifferenceofFreezingCurve() const;
+
+    //@}
+    /** @name Setters */
+    //@{
+
+    bool setLatentHeatduringtheEntirePhaseChangeProcess(double latentHeatduringtheEntirePhaseChangeProcess);
+
+    bool setLiquidStateThermalConductivity(double liquidStateThermalConductivity);
+
+    bool setLiquidStateDensity(double liquidStateDensity);
+
+    bool setLiquidStateSpecificHeat(double liquidStateSpecificHeat);
+
+    bool setHighTemperatureDifferenceofMeltingCurve(double highTemperatureDifferenceofMeltingCurve);
+
+    bool setPeakMeltingTemperature(double peakMeltingTemperature);
+
+    bool setLowTemperatureDifferenceofMeltingCurve(double lowTemperatureDifferenceofMeltingCurve);
+
+    bool setSolidStateThermalConductivity(double solidStateThermalConductivity);
+
+    bool setSolidStateDensity(double solidStateDensity);
+
+    bool setSolidStateSpecificHeat(double solidStateSpecificHeat);
+
+    bool setHighTemperatureDifferenceofFreezingCurve(double highTemperatureDifferenceofFreezingCurve);
+
+    bool setPeakFreezingTemperature(double peakFreezingTemperature);
+
+    bool setLowTemperatureDifferenceofFreezingCurve(double lowTemperatureDifferenceofFreezingCurve);
+
+    //@}
+    /** @name Other */
+    //@{
+
+    //@}
+   protected:
+    /// @cond
+    typedef detail::MaterialPropertyPhaseChangeHysteresis_Impl ImplType;
+
+    explicit MaterialPropertyPhaseChangeHysteresis(std::shared_ptr<detail::MaterialPropertyPhaseChangeHysteresis_Impl> impl);
+
+    friend class detail::MaterialPropertyPhaseChangeHysteresis_Impl;
+    friend class Model;
+    friend class IdfObject;
+    friend class openstudio::detail::IdfObject_Impl;
+    /// @endcond
+   private:
+    REGISTER_LOGGER("openstudio.model.MaterialPropertyPhaseChangeHysteresis");
+  };
+
+  /** \relates MaterialPropertyPhaseChangeHysteresis*/
+  typedef boost::optional<MaterialPropertyPhaseChangeHysteresis> OptionalMaterialPropertyPhaseChangeHysteresis;
+
+  /** \relates MaterialPropertyPhaseChangeHysteresis*/
+  typedef std::vector<MaterialPropertyPhaseChangeHysteresis> MaterialPropertyPhaseChangeHysteresisVector;
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_MATERIALPROPERTYPHASECHANGEHYSTERESIS_HPP
diff --git a/src/model/MaterialPropertyPhaseChangeHysteresis_Impl.hpp b/src/model/MaterialPropertyPhaseChangeHysteresis_Impl.hpp
new file mode 100644
index 00000000000..694ef527a3f
--- /dev/null
+++ b/src/model/MaterialPropertyPhaseChangeHysteresis_Impl.hpp
@@ -0,0 +1,147 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#ifndef MODEL_MATERIALPROPERTYPHASECHANGEHYSTERESIS_IMPL_HPP
+#define MODEL_MATERIALPROPERTYPHASECHANGEHYSTERESIS_IMPL_HPP
+
+#include <vector>
+#include "ModelAPI.hpp"
+#include "ModelObject_Impl.hpp"
+
+namespace openstudio {
+namespace model {
+
+  class Material;
+
+  namespace detail {
+
+    /** MaterialPropertyPhaseChangeHysteresis_Impl is a ModelObject_Impl that is the implementation class for MaterialPropertyPhaseChangeHysteresis.*/
+    class MODEL_API MaterialPropertyPhaseChangeHysteresis_Impl : public ModelObject_Impl
+    {
+
+     public:
+      /** @name Constructors and Destructors */
+      //@{
+
+      MaterialPropertyPhaseChangeHysteresis_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle);
+
+      MaterialPropertyPhaseChangeHysteresis_Impl(const openstudio::detail::WorkspaceObject_Impl& other, Model_Impl* model, bool keepHandle);
+
+      MaterialPropertyPhaseChangeHysteresis_Impl(const MaterialPropertyPhaseChangeHysteresis_Impl& other, Model_Impl* model, bool keepHandle);
+
+      virtual ~MaterialPropertyPhaseChangeHysteresis_Impl() {}
+
+      //@}
+      /** @name Virtual Methods */
+      //@{
+
+      virtual const std::vector<std::string>& outputVariableNames() const override;
+
+      virtual IddObjectType iddObjectType() const override;
+
+      //@}
+      /** @name Getters */
+      //@{
+
+      std::string materialName() const;
+
+      Material material() const;
+
+      double latentHeatduringtheEntirePhaseChangeProcess() const;
+
+      double liquidStateThermalConductivity() const;
+
+      double liquidStateDensity() const;
+
+      double liquidStateSpecificHeat() const;
+
+      double highTemperatureDifferenceofMeltingCurve() const;
+
+      double peakMeltingTemperature() const;
+
+      double lowTemperatureDifferenceofMeltingCurve() const;
+
+      double solidStateThermalConductivity() const;
+
+      double solidStateDensity() const;
+
+      double solidStateSpecificHeat() const;
+
+      double highTemperatureDifferenceofFreezingCurve() const;
+
+      double peakFreezingTemperature() const;
+
+      double lowTemperatureDifferenceofFreezingCurve() const;
+
+      //@}
+      /** @name Setters */
+      //@{
+
+      bool setLatentHeatduringtheEntirePhaseChangeProcess(double latentHeatduringtheEntirePhaseChangeProcess);
+
+      bool setLiquidStateThermalConductivity(double liquidStateThermalConductivity);
+
+      bool setLiquidStateDensity(double liquidStateDensity);
+
+      bool setLiquidStateSpecificHeat(double liquidStateSpecificHeat);
+
+      bool setHighTemperatureDifferenceofMeltingCurve(double highTemperatureDifferenceofMeltingCurve);
+
+      bool setPeakMeltingTemperature(double peakMeltingTemperature);
+
+      bool setLowTemperatureDifferenceofMeltingCurve(double lowTemperatureDifferenceofMeltingCurve);
+
+      bool setSolidStateThermalConductivity(double solidStateThermalConductivity);
+
+      bool setSolidStateDensity(double solidStateDensity);
+
+      bool setSolidStateSpecificHeat(double solidStateSpecificHeat);
+
+      bool setHighTemperatureDifferenceofFreezingCurve(double highTemperatureDifferenceofFreezingCurve);
+
+      bool setPeakFreezingTemperature(double peakFreezingTemperature);
+
+      bool setLowTemperatureDifferenceofFreezingCurve(double lowTemperatureDifferenceofFreezingCurve);
+
+      //@}
+      /** @name Other */
+      //@{
+
+      //@}
+     protected:
+     private:
+      REGISTER_LOGGER("openstudio.model.MaterialPropertyPhaseChangeHysteresis");
+    };
+
+  }  // namespace detail
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_MATERIALPROPERTYPHASECHANGEHYSTERESIS_IMPL_HPP
diff --git a/src/model/MaterialPropertyPhaseChange_Impl.hpp b/src/model/MaterialPropertyPhaseChange_Impl.hpp
new file mode 100644
index 00000000000..b598e46ac67
--- /dev/null
+++ b/src/model/MaterialPropertyPhaseChange_Impl.hpp
@@ -0,0 +1,118 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#ifndef MODEL_MATERIALPROPERTYPHASECHANGE_IMPL_HPP
+#define MODEL_MATERIALPROPERTYPHASECHANGE_IMPL_HPP
+
+#include <vector>
+#include "ModelAPI.hpp"
+#include "ModelObject_Impl.hpp"
+
+namespace openstudio {
+namespace model {
+
+  class TemperatureEnthalpy;
+  class Material;
+
+  namespace detail {
+
+    /** MaterialPropertyPhaseChange_Impl is a ModelObject_Impl that is the implementation class for MaterialPropertyPhaseChange.*/
+    class MODEL_API MaterialPropertyPhaseChange_Impl : public ModelObject_Impl
+    {
+
+     public:
+      /** @name Constructors and Destructors */
+      //@{
+
+      MaterialPropertyPhaseChange_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle);
+
+      MaterialPropertyPhaseChange_Impl(const openstudio::detail::WorkspaceObject_Impl& other, Model_Impl* model, bool keepHandle);
+
+      MaterialPropertyPhaseChange_Impl(const MaterialPropertyPhaseChange_Impl& other, Model_Impl* model, bool keepHandle);
+
+      virtual ~MaterialPropertyPhaseChange_Impl() {}
+
+      //@}
+      /** @name Virtual Methods */
+      //@{
+
+      virtual const std::vector<std::string>& outputVariableNames() const override;
+
+      virtual IddObjectType iddObjectType() const override;
+
+      //@}
+      /** @name Getters */
+      //@{
+
+      std::string materialName() const;
+
+      Material material() const;
+
+      double temperatureCoefficientforThermalConductivity() const;
+
+      bool isTemperatureCoefficientforThermalConductivityDefaulted() const;
+
+      std::vector<TemperatureEnthalpy> temperatureEnthalpys() const;
+
+      unsigned int numberofTemperatureEnthalpys() const;
+
+      //@}
+      /** @name Setters */
+      //@{
+
+      bool setTemperatureCoefficientforThermalConductivity(double temperatureCoefficientforThermalConductivity);
+
+      void resetTemperatureCoefficientforThermalConductivity();
+
+      bool addTemperatureEnthalpy(const TemperatureEnthalpy& temperatureEnthalpy);
+
+      bool addTemperatureEnthalpy(double temperature, double enthalpy);
+
+      bool addTemperatureEnthalpys(const std::vector<TemperatureEnthalpy>& temperatureEnthalpys);
+
+      bool removeTemperatureEnthalpy(unsigned groupIndex);
+
+      void removeAllTemperatureEnthalpys();
+
+      //@}
+      /** @name Other */
+      //@{
+
+      //@}
+     protected:
+     private:
+      REGISTER_LOGGER("openstudio.model.MaterialPropertyPhaseChange");
+    };
+
+  }  // namespace detail
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_MATERIALPROPERTYPHASECHANGE_IMPL_HPP
diff --git a/src/model/Material_Impl.hpp b/src/model/Material_Impl.hpp
index a6c7be55925..56bca4ad43e 100644
--- a/src/model/Material_Impl.hpp
+++ b/src/model/Material_Impl.hpp
@@ -85,19 +85,6 @@ namespace model {
       /** Set thickness to value (m). For some materials, false is always returned. */
       virtual bool setThickness(double value);
 
-      // if material property moisture penetration depth settings already exists, do nothing and return nil; creates the material property moisture penetration depth settings if it does not already exist and return it;
-      boost::optional<MaterialPropertyMoisturePenetrationDepthSettings>
-        createMaterialPropertyMoisturePenetrationDepthSettings(double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA,
-                                                               double moistureEquationCoefficientB, double moistureEquationCoefficientC,
-                                                               double moistureEquationCoefficientD, double coatingLayerThickness,
-                                                               double coatingLayerWaterVaporDiffusionResistanceFactor);
-
-      // returns the material property moisture penetration depth settings if set
-      boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> materialPropertyMoisturePenetrationDepthSettings() const;
-
-      // resets the material property moisture penetration depth settings
-      void resetMaterialPropertyMoisturePenetrationDepthSettings();
-
       //@}
 
      private:
diff --git a/src/model/Model.cpp b/src/model/Model.cpp
index 67387f1ebb1..5e644902687 100644
--- a/src/model/Model.cpp
+++ b/src/model/Model.cpp
@@ -4027,6 +4027,8 @@ namespace model {
     REGISTER_CONSTRUCTOR(LuminaireDefinition);
     REGISTER_CONSTRUCTOR(MaterialPropertyGlazingSpectralData);
     REGISTER_CONSTRUCTOR(MaterialPropertyMoisturePenetrationDepthSettings);
+    REGISTER_CONSTRUCTOR(MaterialPropertyPhaseChange);
+    REGISTER_CONSTRUCTOR(MaterialPropertyPhaseChangeHysteresis);
     REGISTER_CONSTRUCTOR(MasslessOpaqueMaterial);
     REGISTER_CONSTRUCTOR(MeterCustom);
     REGISTER_CONSTRUCTOR(MeterCustomDecrement);
@@ -4562,6 +4564,8 @@ namespace model {
     REGISTER_COPYCONSTRUCTORS(LuminaireDefinition);
     REGISTER_COPYCONSTRUCTORS(MaterialPropertyGlazingSpectralData);
     REGISTER_COPYCONSTRUCTORS(MaterialPropertyMoisturePenetrationDepthSettings);
+    REGISTER_COPYCONSTRUCTORS(MaterialPropertyPhaseChange);
+    REGISTER_COPYCONSTRUCTORS(MaterialPropertyPhaseChangeHysteresis);
     REGISTER_COPYCONSTRUCTORS(MasslessOpaqueMaterial);
     REGISTER_COPYCONSTRUCTORS(MeterCustom);
     REGISTER_COPYCONSTRUCTORS(MeterCustomDecrement);
diff --git a/src/model/ModelGeometry.i b/src/model/ModelGeometry.i
index 78d99ee5cbe..b094d68c133 100644
--- a/src/model/ModelGeometry.i
+++ b/src/model/ModelGeometry.i
@@ -220,10 +220,10 @@ MODELOBJECT_TEMPLATES(DaylightingDeviceTubular);
 MODELOBJECT_TEMPLATES(DaylightingDeviceLightWell);
 MODELOBJECT_TEMPLATES(SpaceType);
 MODELOBJECT_TEMPLATES(LightingSimulationZone);
-MODELOBJECT_TEMPLATES(CustomBlock);
+MODELOBJECT_TEMPLATES(CustomBlock); // Helper class defined in FoundationKiva
 MODELOBJECT_TEMPLATES(FoundationKiva);
 MODELOBJECT_TEMPLATES(SurfacePropertyExposedFoundationPerimeter);
-MODELOBJECT_TEMPLATES(ViewFactor);
+MODELOBJECT_TEMPLATES(ViewFactor); // Helper class defined in ZonePropertyUserViewFactorsBySurfaceName
 MODELOBJECT_TEMPLATES(ZonePropertyUserViewFactorsBySurfaceName);
 MODELOBJECT_TEMPLATES(ExteriorLoadInstance);
 MODELOBJECT_TEMPLATES(ExteriorLights);
diff --git a/src/model/ModelResources.i b/src/model/ModelResources.i
index d84b508bff6..f54b159539f 100644
--- a/src/model/ModelResources.i
+++ b/src/model/ModelResources.i
@@ -86,6 +86,16 @@ class HeatExchangerDesiccantBalancedFlow;
   }
 };
 
+// extend classes
+%extend openstudio::model::TemperatureEnthalpy {
+  // Use the overloaded operator<< for string representation
+  std::string __str__() {
+    std::ostringstream os;
+    os << *$self;
+    return os.str();
+  }
+};
+
 MODELOBJECT_TEMPLATES(ScheduleType)
 MODELOBJECT_TEMPLATES(ScheduleInterval);
 MODELOBJECT_TEMPLATES(ScheduleFixedInterval);
@@ -102,6 +112,9 @@ MODELOBJECT_TEMPLATES(DefaultScheduleSet);
 MODELOBJECT_TEMPLATES(SpectralDataField); // Helper class defined in MaterialPropertyGlazingSpectralData
 MODELOBJECT_TEMPLATES(MaterialPropertyGlazingSpectralData);
 MODELOBJECT_TEMPLATES(MaterialPropertyMoisturePenetrationDepthSettings);
+MODELOBJECT_TEMPLATES(TemperatureEnthalpy); // Helper class defined in MaterialPropertyPhaseChange
+MODELOBJECT_TEMPLATES(MaterialPropertyPhaseChange);
+MODELOBJECT_TEMPLATES(MaterialPropertyPhaseChangeHysteresis);
 MODELOBJECT_TEMPLATES(Material);
 MODELOBJECT_TEMPLATES(FenestrationMaterial);
 MODELOBJECT_TEMPLATES(GasLayer);
@@ -159,7 +172,7 @@ MODELOBJECT_TEMPLATES(CurveRectangularHyperbola1);
 MODELOBJECT_TEMPLATES(CurveRectangularHyperbola2);
 MODELOBJECT_TEMPLATES(CurveSigmoid);
 MODELOBJECT_TEMPLATES(CurveTriquadratic);
-MODELOBJECT_TEMPLATES(TableMultiVariableLookupPoint);
+MODELOBJECT_TEMPLATES(TableMultiVariableLookupPoint);  // Helper class defined in TableMultiVariableLookup
 MODELOBJECT_TEMPLATES(TableMultiVariableLookup);
 MODELOBJECT_TEMPLATES(SpaceLoadDefinition);
 MODELOBJECT_TEMPLATES(PeopleDefinition);
@@ -200,6 +213,8 @@ SWIG_MODELOBJECT(ScheduleConstant, 1);
 SWIG_MODELOBJECT(DefaultScheduleSet, 1);
 SWIG_MODELOBJECT(MaterialPropertyGlazingSpectralData, 1);
 SWIG_MODELOBJECT(MaterialPropertyMoisturePenetrationDepthSettings, 1);
+SWIG_MODELOBJECT(MaterialPropertyPhaseChange, 1);
+SWIG_MODELOBJECT(MaterialPropertyPhaseChangeHysteresis, 1);
 SWIG_MODELOBJECT(Material, 0);
 SWIG_MODELOBJECT(FenestrationMaterial, 0);
 SWIG_MODELOBJECT(GasLayer, 0);
diff --git a/src/model/StandardOpaqueMaterial.cpp b/src/model/StandardOpaqueMaterial.cpp
index ffdeb1a11c2..190fcbedfc1 100644
--- a/src/model/StandardOpaqueMaterial.cpp
+++ b/src/model/StandardOpaqueMaterial.cpp
@@ -29,6 +29,14 @@
 
 #include "StandardOpaqueMaterial.hpp"
 #include "StandardOpaqueMaterial_Impl.hpp"
+#include "StandardsInformationMaterial.hpp"
+#include "StandardsInformationMaterial_Impl.hpp"
+#include "MaterialPropertyMoisturePenetrationDepthSettings.hpp"
+#include "MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp"
+#include "MaterialPropertyPhaseChange.hpp"
+#include "MaterialPropertyPhaseChange_Impl.hpp"
+#include "MaterialPropertyPhaseChangeHysteresis.hpp"
+#include "MaterialPropertyPhaseChangeHysteresis_Impl.hpp"
 
 #include <utilities/idd/IddFactory.hxx>
 
@@ -62,6 +70,24 @@ namespace model {
       return StandardOpaqueMaterial::iddObjectType();
     }
 
+    std::vector<ModelObject> StandardOpaqueMaterial_Impl::children() const {
+      std::vector<ModelObject> results(castVector<ModelObject>(getObject<Material>().getModelObjectSources<StandardsInformationMaterial>()));
+
+      if (boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> empd = this->materialPropertyMoisturePenetrationDepthSettings()) {
+        results.push_back(empd.get());
+      }
+
+      if (boost::optional<MaterialPropertyPhaseChange> phaseChange = this->materialPropertyPhaseChange()) {
+        results.push_back(phaseChange.get());
+      }
+
+      if (boost::optional<MaterialPropertyPhaseChangeHysteresis> phaseChangeHysteresis = this->materialPropertyPhaseChangeHysteresis()) {
+        results.push_back(phaseChangeHysteresis.get());
+      }
+
+      return results;
+    }
+
     boost::optional<double> StandardOpaqueMaterial_Impl::getVisibleTransmittance() const {
       return 0.0;
     }
@@ -317,6 +343,124 @@ namespace model {
       return types;
     }
 
+    boost::optional<MaterialPropertyMoisturePenetrationDepthSettings>
+      StandardOpaqueMaterial_Impl::createMaterialPropertyMoisturePenetrationDepthSettings(
+        double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA, double moistureEquationCoefficientB,
+        double moistureEquationCoefficientC, double moistureEquationCoefficientD, double coatingLayerThickness,
+        double coatingLayerWaterVaporDiffusionResistanceFactor) {
+      StandardOpaqueMaterial thisMaterial = getObject<StandardOpaqueMaterial>();
+      std::vector<MaterialPropertyMoisturePenetrationDepthSettings> empds =
+        thisMaterial.getModelObjectSources<MaterialPropertyMoisturePenetrationDepthSettings>(
+          MaterialPropertyMoisturePenetrationDepthSettings::iddObjectType());
+      if (!empds.empty()) {
+        return boost::none;
+      }
+
+      MaterialPropertyMoisturePenetrationDepthSettings empd(thisMaterial, waterVaporDiffusionResistanceFactor, moistureEquationCoefficientA,
+                                                            moistureEquationCoefficientB, moistureEquationCoefficientC, moistureEquationCoefficientD,
+                                                            coatingLayerThickness, coatingLayerWaterVaporDiffusionResistanceFactor);
+      return empd;
+    }
+
+    boost::optional<MaterialPropertyMoisturePenetrationDepthSettings>
+      StandardOpaqueMaterial_Impl::materialPropertyMoisturePenetrationDepthSettings() const {
+      std::vector<MaterialPropertyMoisturePenetrationDepthSettings> empds =
+        getObject<ModelObject>().getModelObjectSources<MaterialPropertyMoisturePenetrationDepthSettings>(
+          MaterialPropertyMoisturePenetrationDepthSettings::iddObjectType());
+      if (empds.empty()) {
+        // no error
+      } else if (empds.size() == 1) {
+        return empds[0];
+      } else {
+        // error
+      }
+      return boost::none;
+    }
+
+    void StandardOpaqueMaterial_Impl::resetMaterialPropertyMoisturePenetrationDepthSettings() {
+      boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> empd = this->materialPropertyMoisturePenetrationDepthSettings();
+      if (empd) {
+        empd->remove();
+      }
+    }
+
+    boost::optional<MaterialPropertyPhaseChange> StandardOpaqueMaterial_Impl::createMaterialPropertyPhaseChange() {
+      StandardOpaqueMaterial thisMaterial = getObject<StandardOpaqueMaterial>();
+      std::vector<MaterialPropertyPhaseChange> phaseChanges =
+        thisMaterial.getModelObjectSources<MaterialPropertyPhaseChange>(MaterialPropertyPhaseChange::iddObjectType());
+      if (!phaseChanges.empty()) {
+        return boost::none;
+      }
+
+      MaterialPropertyPhaseChange phaseChange(thisMaterial);
+      return phaseChange;
+    }
+
+    boost::optional<MaterialPropertyPhaseChange>
+      StandardOpaqueMaterial_Impl::createMaterialPropertyPhaseChange(const std::vector<TemperatureEnthalpy>& temperatureEnthalpys) {
+      StandardOpaqueMaterial thisMaterial = getObject<StandardOpaqueMaterial>();
+      std::vector<MaterialPropertyPhaseChange> phaseChanges =
+        thisMaterial.getModelObjectSources<MaterialPropertyPhaseChange>(MaterialPropertyPhaseChange::iddObjectType());
+      if (!phaseChanges.empty()) {
+        return boost::none;
+      }
+
+      MaterialPropertyPhaseChange phaseChange(thisMaterial, temperatureEnthalpys);
+      return phaseChange;
+    }
+
+    boost::optional<MaterialPropertyPhaseChange> StandardOpaqueMaterial_Impl::materialPropertyPhaseChange() const {
+      std::vector<MaterialPropertyPhaseChange> phaseChanges =
+        getObject<ModelObject>().getModelObjectSources<MaterialPropertyPhaseChange>(MaterialPropertyPhaseChange::iddObjectType());
+      if (phaseChanges.empty()) {
+        // no error
+      } else if (phaseChanges.size() == 1) {
+        return phaseChanges[0];
+      } else {
+        // error
+      }
+      return boost::none;
+    }
+
+    void StandardOpaqueMaterial_Impl::resetMaterialPropertyPhaseChange() {
+      boost::optional<MaterialPropertyPhaseChange> phaseChange = this->materialPropertyPhaseChange();
+      if (phaseChange) {
+        phaseChange->remove();
+      }
+    }
+
+    boost::optional<MaterialPropertyPhaseChangeHysteresis> StandardOpaqueMaterial_Impl::createMaterialPropertyPhaseChangeHysteresis() {
+      StandardOpaqueMaterial thisMaterial = getObject<StandardOpaqueMaterial>();
+      std::vector<MaterialPropertyPhaseChangeHysteresis> phaseChangeHysteresiss =
+        thisMaterial.getModelObjectSources<MaterialPropertyPhaseChangeHysteresis>(MaterialPropertyPhaseChangeHysteresis::iddObjectType());
+      if (!phaseChangeHysteresiss.empty()) {
+        return boost::none;
+      }
+
+      MaterialPropertyPhaseChangeHysteresis phaseChangeHysteresis(thisMaterial);
+      return phaseChangeHysteresis;
+    }
+
+    boost::optional<MaterialPropertyPhaseChangeHysteresis> StandardOpaqueMaterial_Impl::materialPropertyPhaseChangeHysteresis() const {
+      std::vector<MaterialPropertyPhaseChangeHysteresis> phaseChangeHysteresiss =
+        getObject<ModelObject>().getModelObjectSources<MaterialPropertyPhaseChangeHysteresis>(MaterialPropertyPhaseChangeHysteresis::iddObjectType());
+      if (phaseChangeHysteresiss.empty()) {
+        // no error
+      } else if (phaseChangeHysteresiss.size() == 1) {
+        return phaseChangeHysteresiss[0];
+      } else {
+        // error
+      }
+      return boost::none;
+    }
+
+    void StandardOpaqueMaterial_Impl::resetMaterialPropertyPhaseChangeHysteresis() {
+      boost::optional<MaterialPropertyPhaseChangeHysteresis> phaseChangeHysteresis = this->materialPropertyPhaseChangeHysteresis();
+      if (phaseChangeHysteresis) {
+        phaseChangeHysteresis->remove();
+      }
+    }
+
   }  // namespace detail
 
   StandardOpaqueMaterial::StandardOpaqueMaterial(const Model& model, const std::string& roughness, double thickness, double conductivity,
@@ -508,6 +652,52 @@ namespace model {
     getImpl<detail::StandardOpaqueMaterial_Impl>()->resetVisibleAbsorptance();
   }
 
+  boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> StandardOpaqueMaterial::createMaterialPropertyMoisturePenetrationDepthSettings(
+    double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA, double moistureEquationCoefficientB,
+    double moistureEquationCoefficientC, double moistureEquationCoefficientD, double coatingLayerThickness,
+    double coatingLayerWaterVaporDiffusionResistanceFactor) {
+    return getImpl<detail::StandardOpaqueMaterial_Impl>()->createMaterialPropertyMoisturePenetrationDepthSettings(
+      waterVaporDiffusionResistanceFactor, moistureEquationCoefficientA, moistureEquationCoefficientB, moistureEquationCoefficientC,
+      moistureEquationCoefficientD, coatingLayerThickness, coatingLayerWaterVaporDiffusionResistanceFactor);
+  }
+
+  boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> StandardOpaqueMaterial::materialPropertyMoisturePenetrationDepthSettings() const {
+    return getImpl<detail::StandardOpaqueMaterial_Impl>()->materialPropertyMoisturePenetrationDepthSettings();
+  }
+
+  void StandardOpaqueMaterial::resetMaterialPropertyMoisturePenetrationDepthSettings() {
+    getImpl<detail::StandardOpaqueMaterial_Impl>()->resetMaterialPropertyMoisturePenetrationDepthSettings();
+  }
+
+  boost::optional<MaterialPropertyPhaseChange> StandardOpaqueMaterial::createMaterialPropertyPhaseChange() {
+    return getImpl<detail::StandardOpaqueMaterial_Impl>()->createMaterialPropertyPhaseChange();
+  }
+
+  boost::optional<MaterialPropertyPhaseChange>
+    StandardOpaqueMaterial::createMaterialPropertyPhaseChange(const std::vector<TemperatureEnthalpy>& temperatureEnthalpys) {
+    return getImpl<detail::StandardOpaqueMaterial_Impl>()->createMaterialPropertyPhaseChange(temperatureEnthalpys);
+  }
+
+  boost::optional<MaterialPropertyPhaseChange> StandardOpaqueMaterial::materialPropertyPhaseChange() const {
+    return getImpl<detail::StandardOpaqueMaterial_Impl>()->materialPropertyPhaseChange();
+  }
+
+  void StandardOpaqueMaterial::resetMaterialPropertyPhaseChange() {
+    getImpl<detail::StandardOpaqueMaterial_Impl>()->resetMaterialPropertyPhaseChange();
+  }
+
+  boost::optional<MaterialPropertyPhaseChangeHysteresis> StandardOpaqueMaterial::createMaterialPropertyPhaseChangeHysteresis() {
+    return getImpl<detail::StandardOpaqueMaterial_Impl>()->createMaterialPropertyPhaseChangeHysteresis();
+  }
+
+  boost::optional<MaterialPropertyPhaseChangeHysteresis> StandardOpaqueMaterial::materialPropertyPhaseChangeHysteresis() const {
+    return getImpl<detail::StandardOpaqueMaterial_Impl>()->materialPropertyPhaseChangeHysteresis();
+  }
+
+  void StandardOpaqueMaterial::resetMaterialPropertyPhaseChangeHysteresis() {
+    getImpl<detail::StandardOpaqueMaterial_Impl>()->resetMaterialPropertyPhaseChangeHysteresis();
+  }
+
   /// @cond
   StandardOpaqueMaterial::StandardOpaqueMaterial(std::shared_ptr<detail::StandardOpaqueMaterial_Impl> impl) : OpaqueMaterial(std::move(impl)) {}
   /// @endcond
diff --git a/src/model/StandardOpaqueMaterial.hpp b/src/model/StandardOpaqueMaterial.hpp
index b769ae55448..ee648ea4da3 100644
--- a/src/model/StandardOpaqueMaterial.hpp
+++ b/src/model/StandardOpaqueMaterial.hpp
@@ -33,10 +33,21 @@
 #include "ModelAPI.hpp"
 #include "OpaqueMaterial.hpp"
 
+#include "MaterialPropertyMoisturePenetrationDepthSettings.hpp"
+#include "MaterialPropertyMoisturePenetrationDepthSettings_Impl.hpp"
+#include "MaterialPropertyPhaseChange.hpp"
+#include "MaterialPropertyPhaseChange_Impl.hpp"
+#include "MaterialPropertyPhaseChangeHysteresis.hpp"
+#include "MaterialPropertyPhaseChangeHysteresis_Impl.hpp"
+
 namespace openstudio {
 
 namespace model {
 
+  class MaterialPropertyMoisturePenetrationDepthSettings;
+  class MaterialPropertyPhaseChange;
+  class MaterialPropertyPhaseChangeHysteresis;
+
   namespace detail {
 
     class StandardOpaqueMaterial_Impl;
@@ -163,6 +174,38 @@ namespace model {
 
     void resetVisibleAbsorptance();
 
+    // if material property moisture penetration depth settings already exists, do nothing and return nil; creates the material property moisture penetration depth settings if it does not already exist and return it
+    boost::optional<MaterialPropertyMoisturePenetrationDepthSettings>
+      createMaterialPropertyMoisturePenetrationDepthSettings(double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA,
+                                                             double moistureEquationCoefficientB, double moistureEquationCoefficientC,
+                                                             double moistureEquationCoefficientD, double coatingLayerThickness,
+                                                             double coatingLayerWaterVaporDiffusionResistanceFactor);
+
+    // returns the material property moisture penetration depth settings if set
+    boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> materialPropertyMoisturePenetrationDepthSettings() const;
+
+    // resets the material property moisture penetration depth settings
+    void resetMaterialPropertyMoisturePenetrationDepthSettings();
+
+    // if material property phase change already exists, do nothing and return nil; creates the material property phase change if it does not already exist and return it
+    boost::optional<MaterialPropertyPhaseChange> createMaterialPropertyPhaseChange();
+    boost::optional<MaterialPropertyPhaseChange> createMaterialPropertyPhaseChange(const std::vector<TemperatureEnthalpy>& temperatureEnthalpys);
+
+    // returns the material property phase change if set
+    boost::optional<MaterialPropertyPhaseChange> materialPropertyPhaseChange() const;
+
+    // resets the material property phase change
+    void resetMaterialPropertyPhaseChange();
+
+    // if material property phase change hysteresis already exists, do nothing and return nil; creates the material property phase change hysteresis if it does not already exist and return it
+    boost::optional<MaterialPropertyPhaseChangeHysteresis> createMaterialPropertyPhaseChangeHysteresis();
+
+    // returns the material property phase change hysteresis if set
+    boost::optional<MaterialPropertyPhaseChangeHysteresis> materialPropertyPhaseChangeHysteresis() const;
+
+    // resets the material property phase change hysteresis
+    void resetMaterialPropertyPhaseChangeHysteresis();
+
     //@}
     /** @name Queries */
     //@{
diff --git a/src/model/StandardOpaqueMaterial_Impl.hpp b/src/model/StandardOpaqueMaterial_Impl.hpp
index 44425389c89..958fe783fb8 100644
--- a/src/model/StandardOpaqueMaterial_Impl.hpp
+++ b/src/model/StandardOpaqueMaterial_Impl.hpp
@@ -70,6 +70,9 @@ namespace model {
       /** @name Getters */
       //@{
 
+      // return any children objects in the hierarchy
+      virtual std::vector<ModelObject> children() const override;
+
       /** The conductivitiy of the material in W/m*K. */
       virtual double thermalConductivity() const override;
 
@@ -168,6 +171,38 @@ namespace model {
 
       virtual void resetVisibleAbsorptance();
 
+      // if material property moisture penetration depth settings already exists, do nothing and return nil; creates the material property moisture penetration depth settings if it does not already exist and return it;
+      boost::optional<MaterialPropertyMoisturePenetrationDepthSettings>
+        createMaterialPropertyMoisturePenetrationDepthSettings(double waterVaporDiffusionResistanceFactor, double moistureEquationCoefficientA,
+                                                               double moistureEquationCoefficientB, double moistureEquationCoefficientC,
+                                                               double moistureEquationCoefficientD, double coatingLayerThickness,
+                                                               double coatingLayerWaterVaporDiffusionResistanceFactor);
+
+      // returns the material property moisture penetration depth settings if set
+      boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> materialPropertyMoisturePenetrationDepthSettings() const;
+
+      // resets the material property moisture penetration depth settings
+      void resetMaterialPropertyMoisturePenetrationDepthSettings();
+
+      // if material property phase change already exists, do nothing and return nil; creates the material property phase change if it does not already exist and return it;
+      boost::optional<MaterialPropertyPhaseChange> createMaterialPropertyPhaseChange();
+      boost::optional<MaterialPropertyPhaseChange> createMaterialPropertyPhaseChange(const std::vector<TemperatureEnthalpy>& temperatureEnthalpys);
+
+      // returns the material property phase change if set
+      boost::optional<MaterialPropertyPhaseChange> materialPropertyPhaseChange() const;
+
+      // resets the material property phase change
+      void resetMaterialPropertyPhaseChange();
+
+      // if material property phase change hysteresis already exists, do nothing and return nil; creates the material property phase change hysteresis if it does not already exist and return it
+      boost::optional<MaterialPropertyPhaseChangeHysteresis> createMaterialPropertyPhaseChangeHysteresis();
+
+      // returns the material property phase change hysteresis if set
+      boost::optional<MaterialPropertyPhaseChangeHysteresis> materialPropertyPhaseChangeHysteresis() const;
+
+      // resets the material property phase change hysteresis
+      void resetMaterialPropertyPhaseChangeHysteresis();
+
       //@}
       /** @name Queries */
       //@{


Test patch:
diff --git a/src/model/test/MaterialPropertyMoisturePenetrationDepthSettings_GTest.cpp b/src/model/test/MaterialPropertyMoisturePenetrationDepthSettings_GTest.cpp
index 23dbc1e32d4..6487eee770b 100644
--- a/src/model/test/MaterialPropertyMoisturePenetrationDepthSettings_GTest.cpp
+++ b/src/model/test/MaterialPropertyMoisturePenetrationDepthSettings_GTest.cpp
@@ -44,20 +44,6 @@ using namespace openstudio;
 using namespace openstudio::model;
 
 TEST_F(ModelFixture, MaterialPropertyMoisturePenetrationDepthSettings_MaterialPropertyMoisturePenetrationDepthSettings) {
-  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
-
-  ASSERT_EXIT(
-    {
-      // create a model to use
-      Model model;
-
-      // create a material object to use
-      StandardOpaqueMaterial material(model);
-
-      exit(0);
-    },
-    ::testing::ExitedWithCode(0), "");
-
   // create a model to use
   Model model;
 
@@ -66,7 +52,7 @@ TEST_F(ModelFixture, MaterialPropertyMoisturePenetrationDepthSettings_MaterialPr
   EXPECT_EQ(1, model.modelObjects().size());
 
   // new material does not have material property moisture penetration depth settings yet
-  EXPECT_TRUE(!material.materialPropertyMoisturePenetrationDepthSettings());
+  EXPECT_FALSE(material.materialPropertyMoisturePenetrationDepthSettings());
 
   // create a material property moisture penetration depth settings object to use
   boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> optempd =
@@ -200,9 +186,22 @@ TEST_F(ModelFixture, MaterialPropertyMoisturePenetrationDepthSettings_MaterialNa
     material.createMaterialPropertyMoisturePenetrationDepthSettings(8.9, 0.0069, 0.9066, 0.0404, 22.1121, 0.005, 140);
   auto empd = optempd.get();
   EXPECT_EQ("Material 1", empd.materialName());
+  EXPECT_EQ(material.handle(), empd.material().handle());
   StandardOpaqueMaterial material2(model);
   boost::optional<MaterialPropertyMoisturePenetrationDepthSettings> optempd2 =
     material2.createMaterialPropertyMoisturePenetrationDepthSettings(8.9, 0.0069, 0.9066, 0.0404, 22.1121, 0.005, 140);
   auto empd2 = optempd2.get();
   EXPECT_EQ("Material 2", empd2.materialName());
+  EXPECT_EQ(material2.handle(), empd2.material().handle());
+}
+
+TEST_F(ModelFixture, MaterialPropertyMoisturePenetrationDepthSettings_CtorThrow) {
+  Model model;
+  StandardOpaqueMaterial material(model);
+
+  EXPECT_NO_THROW(MaterialPropertyMoisturePenetrationDepthSettings empd(material, 8.9, 0.0069, 0.9066, 0.0404, 22.1121, 0.005, 140));
+  EXPECT_TRUE(material.materialPropertyMoisturePenetrationDepthSettings());
+  EXPECT_THROW(MaterialPropertyMoisturePenetrationDepthSettings empd(material, 8.9, 0.0069, 0.9066, 0.0404, 22.1121, 0.005, 140),
+               openstudio::Exception);
+  EXPECT_TRUE(material.materialPropertyMoisturePenetrationDepthSettings());
 }
diff --git a/src/model/test/MaterialPropertyPhaseChangeHysteresis_GTest.cpp b/src/model/test/MaterialPropertyPhaseChangeHysteresis_GTest.cpp
new file mode 100644
index 00000000000..05617424b64
--- /dev/null
+++ b/src/model/test/MaterialPropertyPhaseChangeHysteresis_GTest.cpp
@@ -0,0 +1,137 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "ModelFixture.hpp"
+
+#include "../Model.hpp"
+#include "../Model_Impl.hpp"
+
+#include "../MaterialPropertyPhaseChangeHysteresis.hpp"
+#include "../MaterialPropertyPhaseChangeHysteresis_Impl.hpp"
+
+#include "../StandardOpaqueMaterial.hpp"
+#include "../StandardOpaqueMaterial_Impl.hpp"
+
+using namespace openstudio;
+using namespace openstudio::model;
+
+TEST_F(ModelFixture, MaterialPropertyPhaseChangeHysteresis_MaterialPropertyPhaseChangeHysteresis) {
+  // create a model to use
+  Model model;
+
+  // create a material object to use
+  StandardOpaqueMaterial material(model);
+  EXPECT_EQ(1, model.modelObjects().size());
+
+  // new material does not have material property moisture penetration depth settings yet
+  EXPECT_FALSE(material.materialPropertyPhaseChangeHysteresis());
+
+  // create a material property phase change hysteresis object to use
+  boost::optional<MaterialPropertyPhaseChangeHysteresis> optphaseChangeHysteresis = material.createMaterialPropertyPhaseChangeHysteresis();
+  ASSERT_TRUE(optphaseChangeHysteresis);
+  EXPECT_EQ(2, model.modelObjects().size());
+
+  // now the material has material property phase change
+  EXPECT_TRUE(material.materialPropertyPhaseChangeHysteresis());
+
+  // check to make sure the liquid state density is as expected
+  auto phaseChangeHysteresis = optphaseChangeHysteresis.get();
+  EXPECT_EQ(material.nameString(), phaseChangeHysteresis.materialName());
+  EXPECT_EQ(material.handle(), phaseChangeHysteresis.material().handle());
+  EXPECT_EQ(2200.0, phaseChangeHysteresis.liquidStateDensity());
+
+  // check that creating the material property phase change hysteresis when they already exists does nothing and returns nil
+  boost::optional<MaterialPropertyPhaseChangeHysteresis> optphaseChangeHysteresis2 = material.createMaterialPropertyPhaseChangeHysteresis();
+  ASSERT_FALSE(optphaseChangeHysteresis2);
+  EXPECT_EQ(2, model.modelObjects().size());
+}
+
+// test setting and getting
+TEST_F(ModelFixture, MaterialPropertyPhaseChangeHysteresis_SetGetFields) {
+  Model model;
+  StandardOpaqueMaterial material(model);
+  boost::optional<MaterialPropertyPhaseChangeHysteresis> optphaseChangeHysteresis = material.createMaterialPropertyPhaseChangeHysteresis();
+  auto phaseChangeHysteresis = optphaseChangeHysteresis.get();
+
+  // check that the properties were set properly
+  EXPECT_EQ(10000.0, phaseChangeHysteresis.latentHeatduringtheEntirePhaseChangeProcess());
+  EXPECT_EQ(1.5, phaseChangeHysteresis.liquidStateThermalConductivity());
+  EXPECT_EQ(2200.0, phaseChangeHysteresis.liquidStateDensity());
+  EXPECT_EQ(2000.0, phaseChangeHysteresis.liquidStateSpecificHeat());
+  EXPECT_EQ(1.0, phaseChangeHysteresis.highTemperatureDifferenceofMeltingCurve());
+  EXPECT_EQ(23.0, phaseChangeHysteresis.peakMeltingTemperature());
+  EXPECT_EQ(1.0, phaseChangeHysteresis.lowTemperatureDifferenceofMeltingCurve());
+  EXPECT_EQ(1.8, phaseChangeHysteresis.solidStateThermalConductivity());
+  EXPECT_EQ(2300.0, phaseChangeHysteresis.solidStateDensity());
+  EXPECT_EQ(2000.0, phaseChangeHysteresis.solidStateSpecificHeat());
+  EXPECT_EQ(1.0, phaseChangeHysteresis.highTemperatureDifferenceofFreezingCurve());
+  EXPECT_EQ(20.0, phaseChangeHysteresis.peakFreezingTemperature());
+  EXPECT_EQ(1.0, phaseChangeHysteresis.lowTemperatureDifferenceofFreezingCurve());
+
+  // now override the defaults with explicit values
+  phaseChangeHysteresis.setLatentHeatduringtheEntirePhaseChangeProcess(10500.0);
+  phaseChangeHysteresis.setLiquidStateThermalConductivity(1.6);
+  phaseChangeHysteresis.setLiquidStateDensity(1900.0);
+  phaseChangeHysteresis.setLiquidStateSpecificHeat(1800.0);
+  phaseChangeHysteresis.setHighTemperatureDifferenceofMeltingCurve(2.0);
+  phaseChangeHysteresis.setPeakMeltingTemperature(24.0);
+  phaseChangeHysteresis.setLowTemperatureDifferenceofMeltingCurve(3.0);
+  phaseChangeHysteresis.setSolidStateThermalConductivity(1.9);
+  phaseChangeHysteresis.setSolidStateDensity(2500.0);
+  phaseChangeHysteresis.setSolidStateSpecificHeat(1750.0);
+  phaseChangeHysteresis.setHighTemperatureDifferenceofFreezingCurve(1.3);
+  phaseChangeHysteresis.setPeakFreezingTemperature(22.0);
+  phaseChangeHysteresis.setLowTemperatureDifferenceofFreezingCurve(2.0);
+
+  EXPECT_EQ(10500.0, phaseChangeHysteresis.latentHeatduringtheEntirePhaseChangeProcess());
+  EXPECT_EQ(1.6, phaseChangeHysteresis.liquidStateThermalConductivity());
+  EXPECT_EQ(1900.0, phaseChangeHysteresis.liquidStateDensity());
+  EXPECT_EQ(1800.0, phaseChangeHysteresis.liquidStateSpecificHeat());
+  EXPECT_EQ(2.0, phaseChangeHysteresis.highTemperatureDifferenceofMeltingCurve());
+  EXPECT_EQ(24.0, phaseChangeHysteresis.peakMeltingTemperature());
+  EXPECT_EQ(3.0, phaseChangeHysteresis.lowTemperatureDifferenceofMeltingCurve());
+  EXPECT_EQ(1.9, phaseChangeHysteresis.solidStateThermalConductivity());
+  EXPECT_EQ(2500.0, phaseChangeHysteresis.solidStateDensity());
+  EXPECT_EQ(1750.0, phaseChangeHysteresis.solidStateSpecificHeat());
+  EXPECT_EQ(1.3, phaseChangeHysteresis.highTemperatureDifferenceofFreezingCurve());
+  EXPECT_EQ(22.0, phaseChangeHysteresis.peakFreezingTemperature());
+  EXPECT_EQ(2.0, phaseChangeHysteresis.lowTemperatureDifferenceofFreezingCurve());
+}
+
+TEST_F(ModelFixture, MaterialPropertyPhaseChangeHysteresis_CtorThrow) {
+  Model model;
+  StandardOpaqueMaterial material(model);
+
+  EXPECT_NO_THROW(MaterialPropertyPhaseChangeHysteresis phaseChangeHysteresis(material));
+  EXPECT_TRUE(material.materialPropertyPhaseChangeHysteresis());
+  EXPECT_THROW(MaterialPropertyPhaseChangeHysteresis phaseChangeHysteresis(material), openstudio::Exception);
+  EXPECT_TRUE(material.materialPropertyPhaseChangeHysteresis());
+}
diff --git a/src/model/test/MaterialPropertyPhaseChange_GTest.cpp b/src/model/test/MaterialPropertyPhaseChange_GTest.cpp
new file mode 100644
index 00000000000..b1bff8d1777
--- /dev/null
+++ b/src/model/test/MaterialPropertyPhaseChange_GTest.cpp
@@ -0,0 +1,170 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "ModelFixture.hpp"
+
+#include "../Model.hpp"
+#include "../Model_Impl.hpp"
+
+#include "../MaterialPropertyPhaseChange.hpp"
+#include "../MaterialPropertyPhaseChange_Impl.hpp"
+
+#include "../StandardOpaqueMaterial.hpp"
+#include "../StandardOpaqueMaterial_Impl.hpp"
+
+using namespace openstudio;
+using namespace openstudio::model;
+
+TEST_F(ModelFixture, MaterialPropertyPhaseChange_MaterialPropertyPhaseChange) {
+  // create a model to use
+  Model model;
+
+  // create a material object to use
+  StandardOpaqueMaterial material(model);
+  EXPECT_EQ(1, model.modelObjects().size());
+
+  // new material does not have material property phase change yet
+  EXPECT_FALSE(material.materialPropertyPhaseChange());
+
+  // create a material property phase change object to use
+  boost::optional<MaterialPropertyPhaseChange> optphaseChange = material.createMaterialPropertyPhaseChange();
+  ASSERT_TRUE(optphaseChange);
+  EXPECT_EQ(2, model.modelObjects().size());
+
+  // now the material has material property phase change
+  EXPECT_TRUE(material.materialPropertyPhaseChange());
+
+  // check to make sure the temperature coefficient for thermal conductivity field is defaulted as expected
+  auto phaseChange = optphaseChange.get();
+  EXPECT_EQ(material.nameString(), phaseChange.materialName());
+  EXPECT_EQ(material.handle(), phaseChange.material().handle());
+  EXPECT_TRUE(phaseChange.isTemperatureCoefficientforThermalConductivityDefaulted());
+
+  // check that creating the material property phase change when they already exists does nothing and returns nil
+  boost::optional<MaterialPropertyPhaseChange> optphaseChange2 = material.createMaterialPropertyPhaseChange();
+  ASSERT_FALSE(optphaseChange2);
+  EXPECT_EQ(2, model.modelObjects().size());
+}
+
+// test setting and getting
+TEST_F(ModelFixture, MaterialPropertyPhaseChange_SetGetFields) {
+  Model model;
+  StandardOpaqueMaterial material(model);
+  boost::optional<MaterialPropertyPhaseChange> optphaseChange = material.createMaterialPropertyPhaseChange();
+  auto phaseChange = optphaseChange.get();
+
+  // check that the properties were set properly
+  EXPECT_EQ(0.0, phaseChange.temperatureCoefficientforThermalConductivity());
+  EXPECT_EQ(4, phaseChange.temperatureEnthalpys().size());
+  EXPECT_EQ(4, phaseChange.numberofTemperatureEnthalpys());
+
+  // now override the defaults with explicit values
+  phaseChange.setTemperatureCoefficientforThermalConductivity(1.0);
+
+  EXPECT_EQ(1.0, phaseChange.temperatureCoefficientforThermalConductivity());
+  EXPECT_FALSE(phaseChange.isTemperatureCoefficientforThermalConductivityDefaulted());
+
+  // test setting back to defaults
+  phaseChange.resetTemperatureCoefficientforThermalConductivity();
+  EXPECT_TRUE(phaseChange.isTemperatureCoefficientforThermalConductivityDefaulted());
+}
+
+// check temperature-enthalpy
+TEST_F(ModelFixture, MaterialPropertyPhaseChange_TemperatureEnthalpy) {
+  Model model;
+  StandardOpaqueMaterial material(model);
+  boost::optional<MaterialPropertyPhaseChange> optphaseChange = material.createMaterialPropertyPhaseChange();
+  auto phaseChange = optphaseChange.get();
+
+  phaseChange.removeAllTemperatureEnthalpys();
+
+  EXPECT_EQ(0, phaseChange.numberofTemperatureEnthalpys());
+  ASSERT_TRUE(phaseChange.addTemperatureEnthalpy(10.0, 20.0));
+  EXPECT_EQ(1, phaseChange.numberofTemperatureEnthalpys());
+  ASSERT_TRUE(phaseChange.addTemperatureEnthalpy(25.0, 30.0));
+  EXPECT_EQ(2, phaseChange.numberofTemperatureEnthalpys());
+  ASSERT_TRUE(phaseChange.addTemperatureEnthalpy(1.0, 2.0));
+  EXPECT_EQ(3, phaseChange.numberofTemperatureEnthalpys());
+
+  phaseChange.removeTemperatureEnthalpy(1);
+  EXPECT_EQ(2, phaseChange.numberofTemperatureEnthalpys());
+
+  // check that remaining temperature enthalpys moved correctly
+  std::vector<TemperatureEnthalpy> temperatureEnthalpys = phaseChange.temperatureEnthalpys();
+  EXPECT_EQ(10.0, temperatureEnthalpys[0].temperature());
+  EXPECT_EQ(20.0, temperatureEnthalpys[0].enthalpy());
+  EXPECT_EQ(1.0, temperatureEnthalpys[1].temperature());
+  EXPECT_EQ(2.0, temperatureEnthalpys[1].enthalpy());
+
+  // more remove checking
+  phaseChange.removeAllTemperatureEnthalpys();
+  EXPECT_EQ(0, phaseChange.numberofTemperatureEnthalpys());
+  phaseChange.removeTemperatureEnthalpy(0);
+  EXPECT_EQ(0, phaseChange.numberofTemperatureEnthalpys());
+
+  // check adding temperature enthalpy non-conveniently
+  TemperatureEnthalpy temperatureEnthalpy(50.0, 100.0);
+  ASSERT_TRUE(phaseChange.addTemperatureEnthalpy(temperatureEnthalpy));
+  EXPECT_EQ(1, phaseChange.numberofTemperatureEnthalpys());
+
+  // check bulk-adding temperature enthalpys
+  // check bulk-adding temperature enthalpys
+  std::vector<TemperatureEnthalpy> temperatureEnthalpysToAdd{{3.0, 4.0}, {5.0, 6.0}};
+  ASSERT_TRUE(phaseChange.addTemperatureEnthalpys(temperatureEnthalpysToAdd));
+  EXPECT_EQ(3, phaseChange.numberofTemperatureEnthalpys());
+  EXPECT_EQ(3, phaseChange.temperatureEnthalpys().size());
+}
+
+TEST_F(ModelFixture, MaterialPropertyPhaseChange_AlternateCtor) {
+  Model model;
+  StandardOpaqueMaterial material(model);
+  std::vector<TemperatureEnthalpy> temperatureEnthalpys;
+  TemperatureEnthalpy temperatureEnthalpy1(-20.0, 0.1);
+  temperatureEnthalpys.push_back(temperatureEnthalpy1);
+  TemperatureEnthalpy temperatureEnthalpy2(22.0, 18260.0);
+  temperatureEnthalpys.push_back(temperatureEnthalpy2);
+  TemperatureEnthalpy temperatureEnthalpy3(22.1, 32000.0);
+  temperatureEnthalpys.push_back(temperatureEnthalpy3);
+
+  boost::optional<MaterialPropertyPhaseChange> optphaseChange = material.createMaterialPropertyPhaseChange(temperatureEnthalpys);
+  auto phaseChange = optphaseChange.get();
+  EXPECT_EQ(3, phaseChange.temperatureEnthalpys().size());
+}
+
+TEST_F(ModelFixture, MaterialPropertyPhaseChange_CtorThrow) {
+  Model model;
+  StandardOpaqueMaterial material(model);
+
+  EXPECT_NO_THROW(MaterialPropertyPhaseChange phaseChange(material));
+  EXPECT_TRUE(material.materialPropertyPhaseChange());
+  EXPECT_THROW(MaterialPropertyPhaseChange phaseChange(material), openstudio::Exception);
+  EXPECT_TRUE(material.materialPropertyPhaseChange());
+}