Repository: NREL/OpenStudio (language: python)

Issue:
Wrap E+ 22.2 `SurfaceProperty:IncidentSolarMultiplier` object
Enhancement Request
--------------
EnergyPlus 22.2 is adding a new `SurfaceProperty:IncidentSolarMultiplier`, which was requested by NREL-Residential. We'd like to take advantage of this in OS 3.5.0 if possible. See https://github.com/NREL/EnergyPlus/pull/9404 for details.
Wrap E+ 22.2 `SurfaceProperty:GroundSurfaces` object
Enhancement Request
--------------

Includes a field addition "Ground Surfaces Object Name" to `SurfaceProperty:LocalEnvironment`.

## Detailed Description
<!--- Provide a detailed description of the change or addition you are proposing. Include screenshot/schemas as appropriate -->

## Possible Implementation
<!--- Not mandatory, but if you can, suggest an idea for implementing the feature -->

Wrap E+ 22.2 `SurfaceProperty:IncidentSolarMultiplier` object
Enhancement Request
--------------
EnergyPlus 22.2 is adding a new `SurfaceProperty:IncidentSolarMultiplier`, which was requested by NREL-Residential. We'd like to take advantage of this in OS 3.5.0 if possible. See https://github.com/NREL/EnergyPlus/pull/9404 for details.


Discussion / hints:

Fix patch:
diff --git a/developer/ruby/GenerateClass.rb b/developer/ruby/GenerateClass.rb
index ded8f07c811..44c9f238f88 100644
--- a/developer/ruby/GenerateClass.rb
+++ b/developer/ruby/GenerateClass.rb
@@ -365,7 +365,7 @@ def forwardTranslate(options)
 
 # VIRTUAL DESTRUCTORS
 
-hpp << "  virtual ~" << className << "() {}\n\n"
+hpp << "  virtual ~" << className << "() = default;\n\n"
 hpp << "  //@}\n\n"
 
 if pImpl
diff --git a/developer/ruby/SubProjectClassGenerators/SubProjectClassGenerator.rb b/developer/ruby/SubProjectClassGenerators/SubProjectClassGenerator.rb
index 47433a03a7b..703f30d8948 100644
--- a/developer/ruby/SubProjectClassGenerators/SubProjectClassGenerator.rb
+++ b/developer/ruby/SubProjectClassGenerators/SubProjectClassGenerator.rb
@@ -220,7 +220,7 @@ def cppPublicClassProtectedImpl()
       if @baseClassName.empty?
         result << "  : m_impl(impl)\n"
       else
-        result << "  : " << baseClassName << "(impl)\n"
+        result << "  : " << baseClassName << "(std::move(impl))\n"
       end
       result << "{}\n"
     end
diff --git a/resources/energyplus/ProposedEnergy+.idd b/resources/energyplus/ProposedEnergy+.idd
index 0047118a5bc..00a56b47253 100644
--- a/resources/energyplus/ProposedEnergy+.idd
+++ b/resources/energyplus/ProposedEnergy+.idd
@@ -9703,6 +9703,28 @@ SurfaceProperty:SolarIncidentInside,
        \type object-list
        \object-list ScheduleNames
 
+SurfaceProperty:IncidentSolarMultiplier,
+      \min-fields 3
+  A1, \field Surface Name
+      \required-field
+      \type object-list
+      \object-list GlazedExtSubSurfNames
+      \note Enter the name of an exterior window outside surface object
+  N1, \field Incident Solar Multiplier
+      \note a constant multiplier for window solar transmittance
+      \note and visible transmittance. If the Shading Multiplier Schedule Name is
+      \note defined, the product of these two will be the final shading multiplier.
+      \type real
+      \units dimensionless
+      \minimum 0
+      \maximum 1
+      \default 1.0
+  A2; \field Incident Solar Multiplier Schedule Name
+      \note The schedule values should be greater than or equal
+      \note to 0 and less than or equal to 1.
+      \type object-list
+      \object-list ScheduleNames
+
 SurfaceProperty:LocalEnvironment,
        \min-fields 3
        \memo This object defines the local environment properties of an exterior surface.
@@ -9789,6 +9811,33 @@ SurfaceProperty:SurroundingSurfaces,
        \object-list ScheduleNames
        \note Schedule values are real numbers, -100.0 to 100.0, units C
 
+SurfaceProperty:GroundSurfaces,
+       \min-fields 3
+       \memo This object defines a list of ground surfaces for use with an exterior surface.
+       \extensible:4 -- duplicate last set of ground surface properties (the last four fields), remembering to remove ; from "inner" fields.
+   A1, \field Name
+       \required-field
+       \type alpha
+       \reference GroundSurfacesNames
+   A2, \field Ground Surface 1 Name
+       \begin-extensible
+       \required-field
+       \type alpha
+   N1, \field Ground Surface 1 View Factor
+       \type real
+       \units dimensionless
+       \minimum 0.0
+       \maximum 1.0
+   A3, \field Ground Surface 1 Temperature Schedule Name
+       \type alpha
+       \type object-list
+       \object-list ScheduleNames
+       \note Schedule values are real numbers, -100.0 to 100.0, units C
+   A4; \field Ground Surface 1 Reflectance Schedule Name
+       \type object-list
+       \object-list ScheduleNames
+       \note Schedule values are fraction, 0.0 to 1.0, units dimensionless
+
 ComplexFenestrationProperty:SolarAbsorbedLayers,
        \memo Used to provide solar radiation absorbed in fenestration layers. References surface-construction pair
        \memo and if that pair is used in a simulation, then program will use value provided in schedules instead of calculating it.
diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd
index 1dc138092d6..06dc8180b93 100644
--- a/resources/model/OpenStudio.idd
+++ b/resources/model/OpenStudio.idd
@@ -6697,7 +6697,7 @@ OS:SurfaceProperty:SurroundingSurfaces,
        \type object-list
        \object-list ScheduleNames
        \note Schedule values are real numbers, -100.0 to 100.0, units C
-       \note If the field is left blank the global sky temperature is be used
+       \note If the field is left blank the global sky temperature is used
    N2, \field Ground View Factor
        \minimum 0.0
        \maximum 1.0
@@ -6747,10 +6747,68 @@ OS:SurfaceProperty:LocalEnvironment,
        \type object-list
        \object-list SurroundingSurfacesNames
        \note Enter the name of a SurfaceProperty:SurroundingSurfaces object
-   A6; \field Outdoor Air Node Name
+   A6, \field Outdoor Air Node Name
        \type object-list
        \object-list OutdoorAirNodeNames
        \note Enter the name of an OutdoorAir:Node object
+   A7; \field Ground Surfaces Object Name
+       \type object-list
+       \object-list GroundSurfacesNames
+
+OS:SurfaceProperty:GroundSurfaces,
+       \min-fields 4
+       \memo This object defines a list of ground surfaces for use with an exterior surface.
+       \extensible:4 -- duplicate last set of ground surface properties (the last four fields), remembering to remove ; from "inner" fields.
+   A1, \field Handle
+       \type handle
+       \required-field
+   A2, \field Name
+       \required-field
+       \type alpha
+       \reference GroundSurfacesNames
+   A3, \field Ground Surface 1 Name
+       \begin-extensible
+       \required-field
+       \type alpha
+   N1, \field Ground Surface 1 View Factor
+       \type real
+       \units dimensionless
+       \minimum 0.0
+       \maximum 1.0
+       \autocalculatable
+   A4, \field Ground Surface 1 Temperature Schedule Name
+       \type object-list
+       \object-list ScheduleNames
+       \note Schedule values are real numbers, -100.0 to 100.0, units C
+   A5; \field Ground Surface 1 Reflectance Schedule Name
+       \type object-list
+       \object-list ScheduleNames
+       \note Schedule values are fraction, 0.0 to 1.0, units dimensionless
+
+OS:SurfaceProperty:IncidentSolarMultiplier,
+       \min-fields 4
+   A1, \field Handle
+       \type handle
+       \required-field
+   A2, \field Surface Name
+       \required-field
+       \type object-list
+       \object-list GlazedExtSubSurfNames
+       \note Enter the name of an exterior window outside surface object
+   N1, \field Incident Solar Multiplier
+       \note a constant multiplier for window solar transmittance
+       \note and visible transmittance. If the Shading Multiplier Schedule Name is
+       \note defined, the product of these two will be the final shading multiplier.
+       \type real
+       \units dimensionless
+       \minimum 0
+       \maximum 1
+       \required-field
+   A3; \field Incident Solar Multiplier Schedule Name
+       \note The schedule values should be greater than or equal
+       \note to 0 and less than or equal to 1.
+       \type object-list
+       \object-list ScheduleNames
 
 \group OpenStudio Space Loads
 
diff --git a/src/energyplus/CMakeLists.txt b/src/energyplus/CMakeLists.txt
index 54fa411346c..39f2dd9788d 100644
--- a/src/energyplus/CMakeLists.txt
+++ b/src/energyplus/CMakeLists.txt
@@ -388,6 +388,8 @@ set(${target_name}_src
   ForwardTranslator/ForwardTranslateSurfacePropertyOtherSideCoefficients.cpp
   ForwardTranslator/ForwardTranslateSurfacePropertyOtherSideConditionsModel.cpp
   ForwardTranslator/ForwardTranslateSurfacePropertySurroundingSurfaces.cpp
+  ForwardTranslator/ForwardTranslateSurfacePropertyGroundSurfaces.cpp
+  ForwardTranslator/ForwardTranslateSurfacePropertyIncidentSolarMultiplier.cpp
   ForwardTranslator/ForwardTranslateSwimmingPoolIndoor.cpp
   ForwardTranslator/ForwardTranslateTableMultiVariableLookup.cpp
   ForwardTranslator/ForwardTranslateTableLookup.cpp
@@ -588,6 +590,8 @@ set(${target_name}_src
   ReverseTranslator/ReverseTranslateSurfacePropertyExposedFoundationPerimeter.cpp
   ReverseTranslator/ReverseTranslateSurfacePropertyLocalEnvironment.cpp
   ReverseTranslator/ReverseTranslateSurfacePropertySurroundingSurfaces.cpp
+  ReverseTranslator/ReverseTranslateSurfacePropertyGroundSurfaces.cpp
+  ReverseTranslator/ReverseTranslateSurfacePropertyIncidentSolarMultiplier.cpp
   ReverseTranslator/ReverseTranslateSwimmingPoolIndoor.cpp
   ReverseTranslator/ReverseTranslateTableLookup.cpp
   ReverseTranslator/ReverseTranslateTableIndependentVariable.cpp
@@ -761,6 +765,8 @@ set(${target_name}_test_src
   Test/SurfacePropertyConvectionCoefficients_GTest.cpp
   Test/SurfacePropertyLocalEnvironment_GTest.cpp
   Test/SurfacePropertySurroundingSurfaces_GTest.cpp
+  Test/SurfacePropertyGroundSurfaces_GTest.cpp
+  Test/SurfacePropertyIncidentSolarMultiplier_GTest.cpp
   Test/SwimmingPoolIndoor_GTest.cpp
   Test/TableMultiVariableLookup_GTest.cpp
   Test/TableLookup_GTest.cpp
diff --git a/src/energyplus/ForwardTranslator.cpp b/src/energyplus/ForwardTranslator.cpp
index 2f59ccfdee6..3c4855de9b0 100644
--- a/src/energyplus/ForwardTranslator.cpp
+++ b/src/energyplus/ForwardTranslator.cpp
@@ -2853,6 +2853,16 @@ namespace energyplus {
         retVal = translateSurfacePropertySurroundingSurfaces(obj);
         break;
       }
+      case openstudio::IddObjectType::OS_SurfaceProperty_GroundSurfaces: {
+        model::SurfacePropertyGroundSurfaces obj = modelObject.cast<SurfacePropertyGroundSurfaces>();
+        retVal = translateSurfacePropertyGroundSurfaces(obj);
+        break;
+      }
+      case openstudio::IddObjectType::OS_SurfaceProperty_IncidentSolarMultiplier: {
+        model::SurfacePropertyIncidentSolarMultiplier obj = modelObject.cast<SurfacePropertyIncidentSolarMultiplier>();
+        retVal = translateSurfacePropertyIncidentSolarMultiplier(obj);
+        break;
+      }
       case openstudio::IddObjectType::OS_SubSurface: {
         model::SubSurface subSurface = modelObject.cast<SubSurface>();
         retVal = translateSubSurface(subSurface);
diff --git a/src/energyplus/ForwardTranslator.hpp b/src/energyplus/ForwardTranslator.hpp
index a4dec8adb65..0ad5dc5302f 100644
--- a/src/energyplus/ForwardTranslator.hpp
+++ b/src/energyplus/ForwardTranslator.hpp
@@ -448,6 +448,8 @@ namespace model {
   class SurfacePropertyOtherSideCoefficients;
   class SurfacePropertyOtherSideConditionsModel;
   class SurfacePropertySurroundingSurfaces;
+  class SurfacePropertyGroundSurfaces;
+  class SurfacePropertyIncidentSolarMultiplier;
   class SwimmingPoolIndoor;
   class TableMultiVariableLookup;
   class TableLookup;
@@ -1428,6 +1430,10 @@ namespace energyplus {
 
     boost::optional<IdfObject> translateSurfacePropertySurroundingSurfaces(model::SurfacePropertySurroundingSurfaces& modelObject);
 
+    boost::optional<IdfObject> translateSurfacePropertyGroundSurfaces(model::SurfacePropertyGroundSurfaces& modelObject);
+
+    boost::optional<IdfObject> translateSurfacePropertyIncidentSolarMultiplier(model::SurfacePropertyIncidentSolarMultiplier& modelObject);
+
     boost::optional<IdfObject> translateSwimmingPoolIndoor(model::SwimmingPoolIndoor& modelObject);
 
     OS_DEPRECATED boost::optional<IdfObject> translateTableMultiVariableLookup(model::TableMultiVariableLookup& modelObject);
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp
index beb9a389b43..6aeef3058f2 100644
--- a/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp
@@ -42,6 +42,7 @@
 #include "../../model/SurfacePropertyOtherSideConditionsModel.hpp"
 #include "../../model/SurfacePropertyConvectionCoefficients.hpp"
 #include "../../model/SurfacePropertyLocalEnvironment.hpp"
+#include "../../model/SurfacePropertyIncidentSolarMultiplier.hpp"
 
 #include "../../utilities/idf/IdfExtensibleGroup.hpp"
 
@@ -66,10 +67,31 @@ namespace energyplus {
 
     idfObject.setString(FenestrationSurface_DetailedFields::Name, modelObject.name().get());
 
+    openstudio::Vector3d offset(0, 0, 0);
+    idfObject.clearExtensibleGroups();
+    for (const Point3d& point : modelObject.vertices()) {
+      IdfExtensibleGroup group = idfObject.pushExtensibleGroup();
+      if (group.empty()) {
+        LOG(Error,
+            "Currently unable to translate " << modelObject.briefDescription() << ", because it has more vertices than allowed by EnergyPlus.");
+        return boost::none;
+      }
+
+      Point3d newPoint = point + offset;
+
+      group.setDouble(0, newPoint.x());
+      group.setDouble(1, newPoint.y());
+      group.setDouble(2, newPoint.z());
+    }
+
+    // Register and emplace into m_map, so that any child object such as translateSurfacePropertyIncidentSolarMultiplier
+    // can retrieve the subsurface namestring and we don't risk duplicating the subsurface when that child also calls
+    // translateAndMapModelObject(subSurface)
+    m_idfObjects.push_back(idfObject);
+    m_map.insert(std::make_pair(modelObject.handle(), idfObject));
+
     std::string subSurfaceType = modelObject.subSurfaceType();
-    if (istringEqual("FixedWindow", subSurfaceType)) {
-      subSurfaceType = "Window";
-    } else if (istringEqual("OperableWindow", subSurfaceType)) {
+    if (istringEqual("FixedWindow", subSurfaceType) || istringEqual("OperableWindow", subSurfaceType)) {
       subSurfaceType = "Window";
     } else if (istringEqual("OverheadDoor", subSurfaceType)) {
       subSurfaceType = "Door";
@@ -140,7 +162,6 @@ namespace energyplus {
     }
 
     boost::optional<WindowPropertyFrameAndDivider> frameAndDivider = modelObject.windowPropertyFrameAndDivider();
-    openstudio::Vector3d offset(0, 0, 0);
     if (frameAndDivider) {
       if (!frameAndDivider->isOutsideRevealDepthDefaulted()) {
         offset = -frameAndDivider->outsideRevealDepth() * modelObject.outwardNormal();
@@ -152,24 +173,10 @@ namespace energyplus {
       idfObject.setDouble(FenestrationSurface_DetailedFields::Multiplier, modelObject.multiplier());
     }
 
-    idfObject.clearExtensibleGroups();
-    for (const Point3d& point : modelObject.vertices()) {
-      IdfExtensibleGroup group = idfObject.pushExtensibleGroup();
-      if (group.empty()) {
-        LOG(Error,
-            "Currently unable to translate " << modelObject.briefDescription() << ", because it has more vertices than allowed by EnergyPlus.");
-        return boost::none;
-      }
-
-      Point3d newPoint = point + offset;
-
-      group.setDouble(0, newPoint.x());
-      group.setDouble(1, newPoint.y());
-      group.setDouble(2, newPoint.z());
+    if (boost::optional<SurfacePropertyIncidentSolarMultiplier> spMult_ = modelObject.surfacePropertyIncidentSolarMultiplier()) {
+      translateAndMapModelObject(spMult_.get());
     }
 
-    m_idfObjects.push_back(idfObject);
-
     return idfObject;
   }
 
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertyGroundSurfaces.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertyGroundSurfaces.cpp
new file mode 100644
index 00000000000..a77879e7721
--- /dev/null
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertyGroundSurfaces.cpp
@@ -0,0 +1,75 @@
+/***********************************************************************************************************************
+*  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/SurfacePropertyGroundSurfaces.hpp"
+#include "../../model/Schedule.hpp"
+
+#include "../../utilities/idf/IdfExtensibleGroup.hpp"
+
+#include <utilities/idd/SurfaceProperty_GroundSurfaces_FieldEnums.hxx>
+// #include "../../utilities/idd/IddEnums.hpp"
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::model;
+
+namespace openstudio {
+
+namespace energyplus {
+
+  boost::optional<IdfObject> ForwardTranslator::translateSurfacePropertyGroundSurfaces(model::SurfacePropertyGroundSurfaces& modelObject) {
+    boost::optional<IdfObject> result;
+
+    // Instantiate an IdfObject of the class to store the values
+    IdfObject idfObject = createRegisterAndNameIdfObject(openstudio::IddObjectType::SurfaceProperty_GroundSurfaces, modelObject);
+
+    for (const auto& group : modelObject.groundSurfaceGroups()) {
+
+      IdfExtensibleGroup eg = idfObject.pushExtensibleGroup();
+      eg.setString(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceName, group.groundSurfaceName());
+      eg.setDouble(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceViewFactor, group.viewFactor());
+      if (auto sch_ = group.temperatureSchedule()) {
+        if (boost::optional<IdfObject> _owo = translateAndMapModelObject(sch_.get())) {
+          eg.setString(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceTemperatureScheduleName, _owo->nameString());
+        }  // TODO: handle failure?
+      }
+      if (auto sch_ = group.reflectanceSchedule()) {
+        if (boost::optional<IdfObject> _owo = translateAndMapModelObject(sch_.get())) {
+          eg.setString(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceReflectanceScheduleName, _owo->nameString());
+        }  // TODO: handle failure?
+      }
+    }
+
+    return idfObject;
+  }  // End of translate function
+
+}  // end namespace energyplus
+}  // end namespace openstudio
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertyIncidentSolarMultiplier.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertyIncidentSolarMultiplier.cpp
new file mode 100644
index 00000000000..5cb27b7689f
--- /dev/null
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertyIncidentSolarMultiplier.cpp
@@ -0,0 +1,77 @@
+/***********************************************************************************************************************
+*  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/SurfacePropertyIncidentSolarMultiplier.hpp"
+
+#include "../../model/SubSurface.hpp"
+#include "../../model/SubSurface_Impl.hpp"
+
+#include "../../model/Schedule.hpp"
+#include "../../model/Schedule_Impl.hpp"
+
+#include <utilities/idd/SurfaceProperty_IncidentSolarMultiplier_FieldEnums.hxx>
+// #include "../../utilities/idd/IddEnums.hpp"
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::model;
+
+namespace openstudio {
+
+namespace energyplus {
+
+  boost::optional<IdfObject>
+    ForwardTranslator::translateSurfacePropertyIncidentSolarMultiplier(model::SurfacePropertyIncidentSolarMultiplier& modelObject) {
+
+    // Instantiate an IdfObject of the class to store the values
+    IdfObject idfObject = createAndRegisterIdfObject(openstudio::IddObjectType::SurfaceProperty_IncidentSolarMultiplier, modelObject);
+
+    // Surface Name: Required Object
+    SubSurface subSurface = modelObject.subSurface();
+    if (boost::optional<IdfObject> _owo = translateAndMapModelObject(subSurface)) {
+      idfObject.setString(SurfaceProperty_IncidentSolarMultiplierFields::SurfaceName, _owo->nameString());
+    }
+
+    // Incident Solar Multiplier: Optional Double
+    idfObject.setDouble(SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplier, modelObject.incidentSolarMultiplier());
+
+    // Incident Solar Multiplier Schedule Name: Optional Object
+    if (boost::optional<Schedule> _incidentSolarMultiplierSchedule = modelObject.incidentSolarMultiplierSchedule()) {
+      if (boost::optional<IdfObject> _owo = translateAndMapModelObject(_incidentSolarMultiplierSchedule.get())) {
+        idfObject.setString(SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplierScheduleName, _owo->nameString());
+      }
+    }
+
+    return idfObject;
+  }  // End of translate function
+
+}  // end namespace energyplus
+}  // end namespace openstudio
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertyLocalEnvironment.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertyLocalEnvironment.cpp
index 9ef79f54c47..859baba6a72 100644
--- a/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertyLocalEnvironment.cpp
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertyLocalEnvironment.cpp
@@ -35,7 +35,7 @@
 #include "../../model/PlanarSurface.hpp"
 
 #include "../../model/SurfacePropertySurroundingSurfaces.hpp"
-#include "../../model/SurfacePropertySurroundingSurfaces_Impl.hpp"
+#include "../../model/SurfacePropertyGroundSurfaces.hpp"
 
 //#include "../../model/OutdoorAirNode.hpp"
 //#include "../../model/OutdoorAirNode_Impl.hpp"
@@ -75,6 +75,13 @@ namespace energyplus {
       }
     }
 
+    // Ground Surfaces Object Name: Optional Object
+    if (boost::optional<SurfacePropertyGroundSurfaces> sp_ = modelObject.surfacePropertyGroundSurfaces()) {
+      if (boost::optional<IdfObject> _owo = translateAndMapModelObject(sp_.get())) {
+        idfObject.setString(SurfaceProperty_LocalEnvironmentFields::GroundSurfacesObjectName, _owo->nameString());
+      }
+    }
+
     // Outdoor Air Node Name: Optional Object
     // if (boost::optional<OutdoorAirNode> _outdoorAirNode = modelObject.outdoorAirNode()) {
     //   if (boost::optional<IdfObject> _owo = translateAndMapModelObject(_outdoorAirNode.get())) {
diff --git a/src/energyplus/ReverseTranslator.cpp b/src/energyplus/ReverseTranslator.cpp
index 4c52b3c7415..9d3ef0e8997 100644
--- a/src/energyplus/ReverseTranslator.cpp
+++ b/src/energyplus/ReverseTranslator.cpp
@@ -903,6 +903,14 @@ namespace energyplus {
       case openstudio::IddObjectType::SurfaceProperty_SurroundingSurfaces: {
         modelObject = translateSurfacePropertySurroundingSurfaces(workspaceObject);
         break;
+      }
+      case openstudio::IddObjectType::SurfaceProperty_GroundSurfaces: {
+        modelObject = translateSurfacePropertyGroundSurfaces(workspaceObject);
+        break;
+      }
+      case openstudio::IddObjectType::SurfaceProperty_IncidentSolarMultiplier: {
+        modelObject = translateSurfacePropertyIncidentSolarMultiplier(workspaceObject);
+        break;
       }
         //case openstudio::IddObjectType::SwimmingPool_Indoor :
         //{
diff --git a/src/energyplus/ReverseTranslator.hpp b/src/energyplus/ReverseTranslator.hpp
index afde8e55708..73bbda6606e 100644
--- a/src/energyplus/ReverseTranslator.hpp
+++ b/src/energyplus/ReverseTranslator.hpp
@@ -363,6 +363,10 @@ namespace energyplus {
 
     boost::optional<model::ModelObject> translateSurfacePropertySurroundingSurfaces(const WorkspaceObject& workspaceObject);
 
+    boost::optional<model::ModelObject> translateSurfacePropertyGroundSurfaces(const WorkspaceObject& workspaceObject);
+
+    boost::optional<model::ModelObject> translateSurfacePropertyIncidentSolarMultiplier(const WorkspaceObject& workspaceObject);
+
     boost::optional<model::ModelObject> translateSwimmingPoolIndoor(const WorkspaceObject& workspaceObject);
 
     boost::optional<model::ModelObject> translateTableLookup(const WorkspaceObject& workspaceObject);
diff --git a/src/energyplus/ReverseTranslator/ReverseTranslateSurfacePropertyGroundSurfaces.cpp b/src/energyplus/ReverseTranslator/ReverseTranslateSurfacePropertyGroundSurfaces.cpp
new file mode 100644
index 00000000000..ead86111026
--- /dev/null
+++ b/src/energyplus/ReverseTranslator/ReverseTranslateSurfacePropertyGroundSurfaces.cpp
@@ -0,0 +1,107 @@
+/***********************************************************************************************************************
+*  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 "../ReverseTranslator.hpp"
+
+#include "../../model/SurfacePropertyGroundSurfaces.hpp"
+#include "../../model/Schedule.hpp"
+#include "../../model/Schedule_Impl.hpp"
+
+#include "../../utilities/idf/IdfExtensibleGroup.hpp"
+#include "../../utilities/idf/WorkspaceExtensibleGroup.hpp"
+
+#include <utilities/idd/SurfaceProperty_GroundSurfaces_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::model;
+
+namespace openstudio {
+
+namespace energyplus {
+
+  boost::optional<ModelObject> ReverseTranslator::translateSurfacePropertyGroundSurfaces(const WorkspaceObject& workspaceObject) {
+
+    // Instantiate an object of the class to store the values,
+    openstudio::model::SurfacePropertyGroundSurfaces modelObject(m_model);
+
+    // Name
+    if (boost::optional<std::string> _name = workspaceObject.name()) {
+      modelObject.setName(_name.get());
+    }
+
+    // Extensible groups
+    for (const IdfExtensibleGroup& eg : workspaceObject.extensibleGroups()) {
+      auto weg = eg.cast<WorkspaceExtensibleGroup>();
+
+      auto groundSurfaceName = weg.getString(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceName).get();
+      if (groundSurfaceName.empty()) {
+        LOG(Warn, "Extensible group " << eg.groupIndex() << "(0-indexed) has an empty Ground Surface Name field, skipping group");
+        continue;
+      }
+
+      // This has a default of 0, so roll with it
+      auto viewFactor = weg.getDouble(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceViewFactor).get();
+
+      boost::optional<Schedule> tempSch_;
+      boost::optional<Schedule> refSch_;
+
+      if (auto wo_ = weg.getTarget(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceTemperatureScheduleName)) {
+        if (auto mo_ = translateAndMapWorkspaceObject(wo_.get())) {
+          if (boost::optional<Schedule> sch_ = mo_->optionalCast<Schedule>()) {
+            tempSch_ = sch_;
+          } else {
+            LOG(Warn, "Extensible group " << eg.groupIndex() << "(0-indexed) has a wrong type for Temperature Schedule, expected Schedule, got "
+                                          << tempSch_->briefDescription());
+          }
+        } else {
+          LOG(Warn, "Could not translate Temperature Schedule for Extensible group " << eg.groupIndex());
+        }
+      }
+
+      if (auto wo_ = weg.getTarget(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceReflectanceScheduleName)) {
+        if (auto mo_ = translateAndMapWorkspaceObject(wo_.get())) {
+          if (boost::optional<Schedule> sch_ = mo_->optionalCast<Schedule>()) {
+            refSch_ = sch_;
+          } else {
+            LOG(Warn, "Extensible group " << eg.groupIndex() << "(0-indexed) has a wrong type for Reflectance Schedule, expected Schedule, got "
+                                          << tempSch_->briefDescription());
+          }
+        } else {
+          LOG(Warn, "Could not translate Reflectance Schedule for Extensible group " << eg.groupIndex());
+        }
+      }
+
+      modelObject.addGroundSurfaceGroup(groundSurfaceName, viewFactor, tempSch_, refSch_);
+    }
+
+    return modelObject;
+  }  // End of translate function
+
+}  // end namespace energyplus
+}  // end namespace openstudio
diff --git a/src/energyplus/ReverseTranslator/ReverseTranslateSurfacePropertyIncidentSolarMultiplier.cpp b/src/energyplus/ReverseTranslator/ReverseTranslateSurfacePropertyIncidentSolarMultiplier.cpp
new file mode 100644
index 00000000000..bcb4029ddb6
--- /dev/null
+++ b/src/energyplus/ReverseTranslator/ReverseTranslateSurfacePropertyIncidentSolarMultiplier.cpp
@@ -0,0 +1,95 @@
+/***********************************************************************************************************************
+*  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 "../ReverseTranslator.hpp"
+
+#include "../../model/SurfacePropertyIncidentSolarMultiplier.hpp"
+
+#include "../../model/SubSurface.hpp"
+#include "../../model/SubSurface_Impl.hpp"
+
+#include "../../model/Schedule.hpp"
+#include "../../model/Schedule_Impl.hpp"
+
+#include <utilities/idd/SurfaceProperty_IncidentSolarMultiplier_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::model;
+
+namespace openstudio {
+
+namespace energyplus {
+
+  boost::optional<ModelObject> ReverseTranslator::translateSurfacePropertyIncidentSolarMultiplier(const WorkspaceObject& workspaceObject) {
+
+    boost::optional<SubSurface> subSurface_;
+
+    // Surface Name: Required Object
+    if (auto wo_ = workspaceObject.getTarget(SurfaceProperty_IncidentSolarMultiplierFields::SurfaceName)) {
+      if (auto mo_ = translateAndMapWorkspaceObject(wo_.get())) {
+
+        if (auto ss_ = mo_->optionalCast<SubSurface>()) {
+          subSurface_ = ss_;
+        } else {
+          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'Surface Name', cannot reverse translate.");
+          return boost::none;
+        }
+      } else {
+        LOG(Error, "For " << workspaceObject.briefDescription() << ", cannot reverse translate required object 'Surface Name'");
+        return boost::none;
+      }
+    } else {
+      LOG(Error, "For " << workspaceObject.briefDescription() << ", cannot find required object 'Surface Name'");
+      return boost::none;
+    }
+
+    openstudio::model::SurfacePropertyIncidentSolarMultiplier modelObject(subSurface_.get());
+
+    // Incident Solar Multiplier: Optional Double
+    if (boost::optional<double> _incidentSolarMultiplier =
+          workspaceObject.getDouble(SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplier)) {
+      modelObject.setIncidentSolarMultiplier(_incidentSolarMultiplier.get());
+    }
+
+    // Incident Solar Multiplier Schedule Name: Optional Object
+    if (auto wo_ = workspaceObject.getTarget(SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplierScheduleName)) {
+      if (auto mo_ = translateAndMapWorkspaceObject(wo_.get())) {
+        if (boost::optional<Schedule> _incidentSolarMultiplierSchedule = mo_->optionalCast<Schedule>()) {
+          modelObject.setIncidentSolarMultiplierSchedule(_incidentSolarMultiplierSchedule.get());
+        } else {
+          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'Incident Solar Multiplier Schedule Name'");
+        }
+      }
+    }
+
+    return modelObject;
+  }  // End of translate function
+
+}  // end namespace energyplus
+}  // end namespace openstudio
diff --git a/src/energyplus/Test/SurfacePropertyGroundSurfaces_GTest.cpp b/src/energyplus/Test/SurfacePropertyGroundSurfaces_GTest.cpp
new file mode 100644
index 00000000000..7e4b11a9c79
--- /dev/null
+++ b/src/energyplus/Test/SurfacePropertyGroundSurfaces_GTest.cpp
@@ -0,0 +1,239 @@
+/***********************************************************************************************************************
+*  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 "../ErrorFile.hpp"
+#include "../ForwardTranslator.hpp"
+#include "../ReverseTranslator.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/ThermalZone.hpp"
+#include "../../model/Space.hpp"
+#include "../../model/SurfacePropertyLocalEnvironment.hpp"
+#include "../../model/SurfacePropertyGroundSurfaces.hpp"
+#include "../../model/SurfacePropertyGroundSurfaces_Impl.hpp"
+#include "../../model/ScheduleConstant.hpp"
+#include "../../model/Surface.hpp"
+#include "../../model/Surface_Impl.hpp"
+#include "../../model/SubSurface.hpp"
+
+#include "../../utilities/idf/WorkspaceObject.hpp"
+#include "../../utilities/geometry/Point3d.hpp"
+#include "../../utilities/idf/IdfExtensibleGroup.hpp"
+#include "../../utilities/idf/WorkspaceExtensibleGroup.hpp"
+
+#include <utilities/idd/IddEnums.hxx>
+#include <utilities/idd/IddFactory.hxx>
+#include <utilities/idd/SurfaceProperty_LocalEnvironment_FieldEnums.hxx>
+#include <utilities/idd/SurfaceProperty_GroundSurfaces_FieldEnums.hxx>
+#include <utilities/idd/Schedule_Constant_FieldEnums.hxx>
+
+#include <vector>
+
+using namespace openstudio::energyplus;
+using namespace openstudio::model;
+using namespace openstudio;
+
+TEST_F(EnergyPlusFixture, ForwardTranslator_SurfacePropertyGroundSurfaces) {
+
+  ForwardTranslator ft;
+
+  // Zone translates Space, Space translates Surface, Surface translates its LocalEnv object, and this in turns translates our
+  Model m;
+  ThermalZone tz(m);
+  Space space(m);
+  EXPECT_TRUE(space.setThermalZone(tz));
+
+  std::vector<Point3d> sPoints{
+    {0, 2, 0},
+    {0, 0, 0},
+    {2, 0, 0},
+    {2, 2, 0},
+  };
+  Surface surface(sPoints, m);
+  surface.setSpace(space);
+
+  SurfacePropertyGroundSurfaces sp(m);
+  sp.setName("SurfaceProperty Ground Surfaces");
+
+  // Not assigned to a LocalEnv? not translate
+  {
+    // Assigned to a Surface
+    Workspace w = ft.translateModel(m);
+
+    EXPECT_EQ(0, w.getObjectsByType(IddObjectType::SurfaceProperty_LocalEnvironment).size());
+    EXPECT_EQ(0, w.getObjectsByType(IddObjectType::SurfaceProperty_GroundSurfaces).size());
+  }
+
+  SurfacePropertyLocalEnvironment localEnv(surface);
+  localEnv.setName(surface.nameString() + " LocalEnv");
+  EXPECT_TRUE(localEnv.setSurfacePropertyGroundSurfaces(sp));
+  ASSERT_TRUE(localEnv.surfacePropertyGroundSurfaces());
+  EXPECT_EQ(sp, localEnv.surfacePropertyGroundSurfaces().get());
+
+  // Create 5 groups
+  for (int i = 1; i <= 5; ++i) {
+    ScheduleConstant tempSch(m);
+    tempSch.setName("tempSch" + std::to_string(i));
+
+    ScheduleConstant reflectanceSch(m);
+    reflectanceSch.setName("reflectanceSch" + std::to_string(i));
+
+    std::string sfName = "External Surface " + std::to_string(i);
+    double viewFactor = 0.01 * i;
+
+    if (i % 2 == 0) {
+      EXPECT_TRUE(sp.addGroundSurfaceGroup(sfName, viewFactor, tempSch, boost::none));
+    } else {
+      GroundSurfaceGroup group(sfName, viewFactor, boost::none, reflectanceSch);
+      EXPECT_TRUE(sp.addGroundSurfaceGroup(group));
+    }
+    EXPECT_EQ(i, sp.numberofGroundSurfaceGroups());
+  }
+  EXPECT_EQ(5, sp.numberofGroundSurfaceGroups());
+
+  std::vector<GroundSurfaceGroup> groups = sp.groundSurfaceGroups();
+
+  {
+    // Only assigned the groups here
+    Workspace w = ft.translateModel(m);
+
+    std::vector<WorkspaceObject> woEnvs = w.getObjectsByType(IddObjectType::SurfaceProperty_LocalEnvironment);
+    ASSERT_EQ(1, woEnvs.size());
+    std::vector<WorkspaceObject> woSps = w.getObjectsByType(IddObjectType::SurfaceProperty_GroundSurfaces);
+    ASSERT_EQ(1, woSps.size());
+
+    auto& wo_localEnv = woEnvs[0];
+    EXPECT_EQ(localEnv.nameString(), wo_localEnv.nameString());
+
+    EXPECT_EQ(sp.nameString(), wo_localEnv.getString(SurfaceProperty_LocalEnvironmentFields::GroundSurfacesObjectName).get());
+    auto& woSp = woSps[0];
+    EXPECT_EQ(sp.nameString(), woSp.nameString());
+
+    ASSERT_EQ(5, woSp.numExtensibleGroups());
+    for (const auto& idf_eg : woSp.extensibleGroups()) {
+      auto& group = groups[idf_eg.groupIndex()];
+
+      EXPECT_EQ(group.groundSurfaceName(), idf_eg.getString(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceName).get());
+      EXPECT_EQ(group.viewFactor(), idf_eg.getDouble(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceViewFactor).get());
+      if ((idf_eg.groupIndex() + 1) % 2 == 0) {
+        ASSERT_TRUE(group.temperatureSchedule());
+        EXPECT_EQ(group.temperatureSchedule()->nameString(),
+                  idf_eg.getString(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceTemperatureScheduleName).get());
+        EXPECT_FALSE(group.reflectanceSchedule());
+      } else {
+        EXPECT_FALSE(group.temperatureSchedule());
+        ASSERT_TRUE(group.reflectanceSchedule());
+        EXPECT_EQ(group.reflectanceSchedule()->nameString(),
+                  idf_eg.getString(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceReflectanceScheduleName).get());
+      }
+    }
+  }
+}
+
+TEST_F(EnergyPlusFixture, ReverseTranslator_SurfacePropertyGroundSurfaces) {
+
+  ReverseTranslator rt;
+
+  Workspace w(StrictnessLevel::Minimal, IddFileType::EnergyPlus);
+
+  auto wo_zone = w.addObject(IdfObject(IddObjectType::Zone)).get();
+  wo_zone.setName("Thermal Zone 1");
+
+  auto wo_sp = w.addObject(IdfObject(IddObjectType::SurfaceProperty_GroundSurfaces)).get();
+
+  auto tempSch = w.addObject(IdfObject(IddObjectType::Schedule_Constant)).get();
+  tempSch.setName("tempSch1");
+  EXPECT_TRUE(tempSch.setDouble(Schedule_ConstantFields::HourlyValue, 13.5));
+
+  auto reflectanceSch = w.addObject(IdfObject(IddObjectType::Schedule_Constant)).get();
+  reflectanceSch.setName("reflectanceSch");
+  EXPECT_TRUE(reflectanceSch.setDouble(Schedule_ConstantFields::HourlyValue, 0.9));
+
+  struct Group
+  {
+    Group(std::string s, double v, std::string tempSch, std::string refSch)
+      : groundSurfaceName(std::move(s)), viewFactor(v), temperatureScheduleName(std::move(tempSch)), reflectanceScheduleName(std::move(refSch)) {}
+
+    std::string groundSurfaceName;
+    double viewFactor;
+    std::string temperatureScheduleName;
+    std::string reflectanceScheduleName;
+  };
+
+  std::vector<Group> check_groups;
+
+  for (int i = 1; i <= 5; ++i) {
+    auto w_eg = wo_sp.pushExtensibleGroup().cast<WorkspaceExtensibleGroup>();
+    std::string sfName = "External Surface " + std::to_string(i);
+    EXPECT_TRUE(w_eg.setString(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceName, sfName));
+
+    double viewFactor = 0.01 * i;
+    EXPECT_TRUE(w_eg.setDouble(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceViewFactor, viewFactor));
+
+    if (i % 2 == 0) {
+      EXPECT_TRUE(w_eg.setPointer(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceTemperatureScheduleName, tempSch.handle()));
+      check_groups.emplace_back(sfName, viewFactor, tempSch.nameString(), "");
+    } else {
+      EXPECT_TRUE(w_eg.setPointer(SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceReflectanceScheduleName, reflectanceSch.handle()));
+      check_groups.emplace_back(sfName, viewFactor, "", reflectanceSch.nameString());
+    }
+  }
+
+  Model m = rt.translateWorkspace(w);
+
+  auto sps = m.getConcreteModelObjects<SurfacePropertyGroundSurfaces>();
+  ASSERT_EQ(1, sps.size());
+  auto& sp = sps[0];
+
+  ASSERT_EQ(5, sp.numberofGroundSurfaceGroups());
+  auto groups = sp.groundSurfaceGroups();
+  ASSERT_EQ(5, groups.size());
+
+  for (size_t i = 0; i < 5; ++i) {
+    auto& group = groups[i];
+    auto& check_group = check_groups[i];
+    EXPECT_EQ(check_group.groundSurfaceName, group.groundSurfaceName());
+    EXPECT_EQ(check_group.viewFactor, group.viewFactor());
+    if (!check_group.temperatureScheduleName.empty()) {
+      ASSERT_TRUE(group.temperatureSchedule());
+      EXPECT_EQ(check_group.temperatureScheduleName, group.temperatureSchedule()->nameString());
+    } else {
+      EXPECT_FALSE(group.temperatureSchedule());
+    }
+    if (!check_group.reflectanceScheduleName.empty()) {
+      ASSERT_TRUE(group.reflectanceSchedule());
+      EXPECT_EQ(check_group.reflectanceScheduleName, group.reflectanceSchedule()->nameString());
+    } else {
+      EXPECT_FALSE(group.reflectanceSchedule());
+    }
+  }
+}
diff --git a/src/energyplus/Test/SurfacePropertyIncidentSolarMultiplier_GTest.cpp b/src/energyplus/Test/SurfacePropertyIncidentSolarMultiplier_GTest.cpp
new file mode 100644
index 00000000000..713a7159e66
--- /dev/null
+++ b/src/energyplus/Test/SurfacePropertyIncidentSolarMultiplier_GTest.cpp
@@ -0,0 +1,200 @@
+/***********************************************************************************************************************
+*  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 "../ErrorFile.hpp"
+#include "../ForwardTranslator.hpp"
+#include "../ReverseTranslator.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/ThermalZone.hpp"
+#include "../../model/Space.hpp"
+#include "../../model/SurfacePropertyIncidentSolarMultiplier.hpp"
+#include "../../model/SurfacePropertyIncidentSolarMultiplier_Impl.hpp"
+#include "../../model/ScheduleConstant.hpp"
+#include "../../model/Surface.hpp"
+#include "../../model/Surface_Impl.hpp"
+#include "../../model/SubSurface.hpp"
+#include "../../model/SubSurface_Impl.hpp"
+
+#include "../../utilities/idf/WorkspaceObject.hpp"
+#include "../../utilities/geometry/Point3d.hpp"
+#include "../../utilities/idf/IdfExtensibleGroup.hpp"
+#include "../../utilities/idf/WorkspaceExtensibleGroup.hpp"
+
+#include <utilities/idd/IddEnums.hxx>
+#include <utilities/idd/IddFactory.hxx>
+#include <utilities/idd/SurfaceProperty_IncidentSolarMultiplier_FieldEnums.hxx>
+#include <utilities/idd/BuildingSurface_Detailed_FieldEnums.hxx>
+#include <utilities/idd/FenestrationSurface_Detailed_FieldEnums.hxx>
+#include <utilities/idd/Schedule_Constant_FieldEnums.hxx>
+
+#include <vector>
+
+using namespace openstudio::energyplus;
+using namespace openstudio::model;
+using namespace openstudio;
+
+TEST_F(EnergyPlusFixture, ForwardTranslator_SurfacePropertyIncidentSolarMultiplier) {
+
+  ForwardTranslator ft;
+
+  // Zone translates Space, Space translates Surface, Surface translates its LocalEnv object, and this in turns translates our
+  Model m;
+  ThermalZone tz(m);
+  Space space(m);
+  EXPECT_TRUE(space.setThermalZone(tz));
+
+  std::vector<Point3d> sPoints{{0, 2, 0}, {0, 0, 0}, {2, 0, 0}, {2, 2, 0}};
+  Surface surface(sPoints, m);
+  surface.setSpace(space);
+
+  std::vector<Point3d> ssPoints{{0, 0, 1}, {0, 0, 0}, {1, 0, 0}, {1, 0, 1}};
+
+  SubSurface ss(ssPoints, m);
+  ss.setName("SubSurface1");
+  ss.setSurface(surface);
+
+  SurfacePropertyIncidentSolarMultiplier sp(ss);
+  // Incident Solar Multiplier: Required Double
+  EXPECT_TRUE(sp.setIncidentSolarMultiplier(0.75));
+
+  // Incident Solar Multiplier Schedule Name: Optional Object
+  ScheduleConstant sch(m);
+  EXPECT_TRUE(sp.setIncidentSolarMultiplierSchedule(sch));
+
+  // Only assigned the groups here
+  Workspace w = ft.translateModel(m);
+
+  std::vector<WorkspaceObject> woSps = w.getObjectsByType(IddObjectType::SurfaceProperty_IncidentSolarMultiplier);
+  ASSERT_EQ(1, woSps.size());
+  auto& woSp = woSps.front();
+
+  ASSERT_EQ(1, w.getObjectsByType(IddObjectType::BuildingSurface_Detailed).size());
+  ASSERT_EQ(1, w.getObjectsByType(IddObjectType::FenestrationSurface_Detailed).size());
+
+  EXPECT_EQ(ss.nameString(), woSp.getTarget(SurfaceProperty_IncidentSolarMultiplierFields::SurfaceName)->nameString());
+  EXPECT_EQ("SubSurface1", woSp.getTarget(SurfaceProperty_IncidentSolarMultiplierFields::SurfaceName)->nameString());
+  EXPECT_EQ(sp.incidentSolarMultiplier(), woSp.getDouble(SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplier).get());
+  EXPECT_EQ(sch.nameString(), woSp.getString(SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplierScheduleName).get());
+}
+
+TEST_F(EnergyPlusFixture, ReverseTranslator_SurfacePropertyIncidentSolarMultiplier) {
+
+  ReverseTranslator rt;
+
+  Workspace w(StrictnessLevel::Minimal, IddFileType::EnergyPlus);
+
+  auto wo_zone = w.addObject(IdfObject(IddObjectType::Zone)).get();
+  wo_zone.setName("Thermal Zone 1");
+
+  auto wo_sf = w.addObject(IdfObject(IddObjectType::BuildingSurface_Detailed)).get();
+  wo_sf.setName("Surface 1");
+  EXPECT_TRUE(wo_sf.setString(BuildingSurface_DetailedFields::SurfaceType, "Wall"));
+  EXPECT_TRUE(wo_sf.setString(BuildingSurface_DetailedFields::ConstructionName, ""));
+  EXPECT_TRUE(wo_sf.setPointer(BuildingSurface_DetailedFields::ZoneName, wo_zone.handle()));
+  EXPECT_TRUE(wo_sf.setString(BuildingSurface_DetailedFields::OutsideBoundaryCondition, "Outdoors"));
+  EXPECT_TRUE(wo_sf.setString(BuildingSurface_DetailedFields::OutsideBoundaryConditionObject, ""));
+  EXPECT_TRUE(wo_sf.setString(BuildingSurface_DetailedFields::SunExposure, "SunExposed"));
+  EXPECT_TRUE(wo_sf.setString(BuildingSurface_DetailedFields::WindExposure, "WindExposed"));
+  EXPECT_TRUE(wo_sf.setString(BuildingSurface_DetailedFields::ViewFactortoGround, ""));
+  EXPECT_TRUE(wo_sf.setString(BuildingSurface_DetailedFields::NumberofVertices, ""));
+  {
+    IdfExtensibleGroup group1 = wo_sf.pushExtensibleGroup();  // vertex 1
+    group1.setDouble(0, 0);
+    group1.setDouble(1, 2);
+    group1.setDouble(2, 0);
+    IdfExtensibleGroup group2 = wo_sf.pushExtensibleGroup();  // vertex 2
+    group2.setDouble(0, 0);
+    group2.setDouble(1, 0);
+    group2.setDouble(2, 0);
+    IdfExtensibleGroup group3 = wo_sf.pushExtensibleGroup();  // vertex 3
+    group3.setDouble(0, 2);
+    group3.setDouble(1, 0);
+    group3.setDouble(2, 0);
+    IdfExtensibleGroup group4 = wo_sf.pushExtensibleGroup();  // vertex 4
+    group4.setDouble(0, 2);
+    group4.setDouble(1, 2);
+    group4.setDouble(2, 0);
+  }
+
+  auto wo_ss = w.addObject(IdfObject(IddObjectType::FenestrationSurface_Detailed)).get();
+  wo_ss.setName("SubSurface 1");
+  EXPECT_TRUE(wo_ss.setString(FenestrationSurface_DetailedFields::SurfaceType, "Window"));
+  EXPECT_TRUE(wo_ss.setString(FenestrationSurface_DetailedFields::ConstructionName, ""));
+  EXPECT_TRUE(wo_ss.setPointer(FenestrationSurface_DetailedFields::BuildingSurfaceName, wo_sf.handle()));
+  EXPECT_TRUE(wo_ss.setString(FenestrationSurface_DetailedFields::OutsideBoundaryConditionObject, ""));
+  EXPECT_TRUE(wo_ss.setDouble(FenestrationSurface_DetailedFields::ViewFactortoGround, 0.0));
+  EXPECT_TRUE(wo_ss.setString(FenestrationSurface_DetailedFields::FrameandDividerName, ""));
+  EXPECT_TRUE(wo_ss.setDouble(FenestrationSurface_DetailedFields::Multiplier, 0.0));
+  EXPECT_TRUE(wo_ss.setDouble(FenestrationSurface_DetailedFields::NumberofVertices, 0.0));
+  {
+    IdfExtensibleGroup group1 = wo_ss.pushExtensibleGroup();  // vertex 1
+    group1.setDouble(0, 0);
+    group1.setDouble(1, 1);
+    group1.setDouble(2, 0);
+    IdfExtensibleGroup group2 = wo_ss.pushExtensibleGroup();  // vertex 2
+    group2.setDouble(0, 0);
+    group2.setDouble(1, 0);
+    group2.setDouble(2, 0);
+    IdfExtensibleGroup group3 = wo_ss.pushExtensibleGroup();  // vertex 3
+    group3.setDouble(0, 1);
+    group3.setDouble(1, 0);
+    group3.setDouble(2, 0);
+    IdfExtensibleGroup group4 = wo_ss.pushExtensibleGroup();  // vertex 4
+    group4.setDouble(0, 1);
+    group4.setDouble(1, 1);
+    group4.setDouble(2, 0);
+  }
+
+  auto multSch = w.addObject(IdfObject(IddObjectType::Schedule_Constant)).get();
+  multSch.setName("multSch");
+  EXPECT_TRUE(multSch.setDouble(Schedule_ConstantFields::HourlyValue, 0.9));
+
+  auto wo_sp = w.addObject(IdfObject(IddObjectType::SurfaceProperty_IncidentSolarMultiplier)).get();
+
+  EXPECT_TRUE(wo_sp.setPointer(SurfaceProperty_IncidentSolarMultiplierFields::SurfaceName, wo_ss.handle()));
+  EXPECT_TRUE(wo_sp.setDouble(SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplier, 0.8));
+  EXPECT_TRUE(wo_sp.setPointer(SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplierScheduleName, multSch.handle()));
+
+  Model m = rt.translateWorkspace(w);
+
+  EXPECT_EQ(1, m.getConcreteModelObjects<Surface>().size());
+  EXPECT_EQ(1, m.getConcreteModelObjects<SubSurface>().size());
+
+  auto sps = m.getConcreteModelObjects<SurfacePropertyIncidentSolarMultiplier>();
+  ASSERT_EQ(1, sps.size());
+  auto& sp = sps[0];
+  EXPECT_EQ("SubSurface 1", sp.subSurface().nameString());
+  EXPECT_EQ(0.8, sp.incidentSolarMultiplier());
+  ASSERT_TRUE(sp.incidentSolarMultiplierSchedule());
+  EXPECT_EQ("multSch", sp.incidentSolarMultiplierSchedule()->nameString());
+}
diff --git a/src/energyplus/Test/SurfacePropertyLocalEnvironment_GTest.cpp b/src/energyplus/Test/SurfacePropertyLocalEnvironment_GTest.cpp
index 1a6ac0f6bb2..fe6ee18ce46 100644
--- a/src/energyplus/Test/SurfacePropertyLocalEnvironment_GTest.cpp
+++ b/src/energyplus/Test/SurfacePropertyLocalEnvironment_GTest.cpp
@@ -122,6 +122,9 @@ TEST_F(EnergyPlusFixture, ForwardTranslator_SurfacePropertyLocalEnvironment) {
     // Assigned to a Surface
     Workspace w = ft.translateModel(m);
 
+    ASSERT_EQ(1, w.getObjectsByType(IddObjectType::BuildingSurface_Detailed).size());
+    ASSERT_EQ(1, w.getObjectsByType(IddObjectType::FenestrationSurface_Detailed).size());
+
     std::vector<WorkspaceObject> idfObjs = w.getObjectsByType(IddObjectType::SurfaceProperty_LocalEnvironment);
     ASSERT_EQ(1, idfObjs.size());
     auto& wo_localEnv = idfObjs[0];
@@ -148,6 +151,9 @@ TEST_F(EnergyPlusFixture, ForwardTranslator_SurfacePropertyLocalEnvironment) {
     // Assigned to a SubSurface
     Workspace w = ft.translateModel(m);
 
+    ASSERT_EQ(1, w.getObjectsByType(IddObjectType::BuildingSurface_Detailed).size());
+    ASSERT_EQ(1, w.getObjectsByType(IddObjectType::FenestrationSurface_Detailed).size());
+
     std::vector<WorkspaceObject> idfObjs = w.getObjectsByType(IddObjectType::SurfaceProperty_LocalEnvironment);
     ASSERT_EQ(1, idfObjs.size());
     auto& wo_localEnv = idfObjs[0];
diff --git a/src/model/CMakeLists.txt b/src/model/CMakeLists.txt
index b57ee8784c9..30e15e8c4b3 100644
--- a/src/model/CMakeLists.txt
+++ b/src/model/CMakeLists.txt
@@ -1543,6 +1543,12 @@ set(${target_name}_src
   SurfacePropertySurroundingSurfaces.cpp
   SurfacePropertySurroundingSurfaces.hpp
   SurfacePropertySurroundingSurfaces_Impl.hpp
+  SurfacePropertyGroundSurfaces.cpp
+  SurfacePropertyGroundSurfaces.hpp
+  SurfacePropertyGroundSurfaces_Impl.hpp
+  SurfacePropertyIncidentSolarMultiplier.cpp
+  SurfacePropertyIncidentSolarMultiplier.hpp
+  SurfacePropertyIncidentSolarMultiplier_Impl.hpp
   SwimmingPoolIndoor.cpp
   SwimmingPoolIndoor.hpp
   SwimmingPoolIndoor_Impl.hpp
@@ -2242,6 +2248,8 @@ set(${target_name}_test_src
   test/SurfacePropertyOtherSideCoefficients_GTest.cpp
   test/SurfacePropertyExposedFoundationPerimeter_GTest.cpp
   test/SurfacePropertySurroundingSurfaces_GTest.cpp
+  test/SurfacePropertyGroundSurfaces_GTest.cpp
+  test/SurfacePropertyIncidentSolarMultiplier_GTest.cpp
   test/SwimmingPoolIndoor_GTest.cpp
   test/TableMultiVariableLookup_GTest.cpp
   test/TableLookup_GTest.cpp
diff --git a/src/model/ConcreteModelObjects.hpp b/src/model/ConcreteModelObjects.hpp
index d0af21b7674..b3e02643484 100644
--- a/src/model/ConcreteModelObjects.hpp
+++ b/src/model/ConcreteModelObjects.hpp
@@ -490,6 +490,8 @@
 #include "SurfacePropertyOtherSideCoefficients.hpp"
 #include "SurfacePropertyOtherSideConditionsModel.hpp"
 #include "SurfacePropertySurroundingSurfaces.hpp"
+#include "SurfacePropertyGroundSurfaces.hpp"
+#include "SurfacePropertyIncidentSolarMultiplier.hpp"
 #include "SwimmingPoolIndoor.hpp"
 #include "TableMultiVariableLookup.hpp"
 #include "TableLookup.hpp"
@@ -1022,6 +1024,8 @@
 #include "SurfacePropertyOtherSideCoefficients_Impl.hpp"
 #include "SurfacePropertyOtherSideConditionsModel_Impl.hpp"
 #include "SurfacePropertySurroundingSurfaces_Impl.hpp"
+#include "SurfacePropertyGroundSurfaces_Impl.hpp"
+#include "SurfacePropertyIncidentSolarMultiplier_Impl.hpp"
 #include "SwimmingPoolIndoor_Impl.hpp"
 #include "TableMultiVariableLookup_Impl.hpp"
 #include "TableLookup_Impl.hpp"
diff --git a/src/model/Model.cpp b/src/model/Model.cpp
index 7c45328458f..db96379c9c5 100644
--- a/src/model/Model.cpp
+++ b/src/model/Model.cpp
@@ -4257,6 +4257,8 @@ namespace model {
     REGISTER_CONSTRUCTOR(SurfacePropertyOtherSideCoefficients);
     REGISTER_CONSTRUCTOR(SurfacePropertyOtherSideConditionsModel);
     REGISTER_CONSTRUCTOR(SurfacePropertySurroundingSurfaces);
+    REGISTER_CONSTRUCTOR(SurfacePropertyGroundSurfaces);
+    REGISTER_CONSTRUCTOR(SurfacePropertyIncidentSolarMultiplier);
     REGISTER_CONSTRUCTOR(SwimmingPoolIndoor);
 #if defined(_MSC_VER)
 #  pragma warning(push)
@@ -4809,6 +4811,8 @@ namespace model {
     REGISTER_COPYCONSTRUCTORS(SurfacePropertyOtherSideCoefficients);
     REGISTER_COPYCONSTRUCTORS(SurfacePropertyOtherSideConditionsModel);
     REGISTER_COPYCONSTRUCTORS(SurfacePropertySurroundingSurfaces);
+    REGISTER_COPYCONSTRUCTORS(SurfacePropertyGroundSurfaces);
+    REGISTER_COPYCONSTRUCTORS(SurfacePropertyIncidentSolarMultiplier);
     REGISTER_COPYCONSTRUCTORS(SwimmingPoolIndoor);
 #if defined(_MSC_VER)
 #  pragma warning(push)
diff --git a/src/model/ModelGeometry.i b/src/model/ModelGeometry.i
index 3ae7600afb7..b2113b882dc 100644
--- a/src/model/ModelGeometry.i
+++ b/src/model/ModelGeometry.i
@@ -174,6 +174,15 @@ class ExteriorLoadInstance;
   }
 };
 
+%extend openstudio::model::GroundSurfaceGroup {
+  // Use the overloaded operator<< for string representation
+  std::string __str__() {
+    std::ostringstream os;
+    os << *$self;
+    return os.str();
+  }
+};
+
 UNIQUEMODELOBJECT_TEMPLATES(Site);
 UNIQUEMODELOBJECT_TEMPLATES(Facility);
 UNIQUEMODELOBJECT_TEMPLATES(Building);
@@ -200,6 +209,9 @@ MODELOBJECT_TEMPLATES(SurfacePropertyOtherSideConditionsModel);
 MODELOBJECT_TEMPLATES(SurfacePropertyLocalEnvironment);
 MODELOBJECT_TEMPLATES(SurroundingSurfaceGroup); // helper for extensible fields for SurfacePropertySurroundingSurfaces
 MODELOBJECT_TEMPLATES(SurfacePropertySurroundingSurfaces);
+MODELOBJECT_TEMPLATES(GroundSurfaceGroup); // helper for extensible fields for SurfacePropertyGroundSurfaces
+MODELOBJECT_TEMPLATES(SurfacePropertyGroundSurfaces);
+MODELOBJECT_TEMPLATES(SurfacePropertyIncidentSolarMultiplier);
 MODELOBJECT_TEMPLATES(SurfacePropertyConvectionCoefficients);
 MODELOBJECT_TEMPLATES(People);
 MODELOBJECT_TEMPLATES(Luminaire);
@@ -256,6 +268,8 @@ SWIG_MODELOBJECT(SurfacePropertyOtherSideCoefficients, 1);
 SWIG_MODELOBJECT(SurfacePropertyOtherSideConditionsModel, 1);
 SWIG_MODELOBJECT(SurfacePropertyLocalEnvironment, 1);
 SWIG_MODELOBJECT(SurfacePropertySurroundingSurfaces, 1);
+SWIG_MODELOBJECT(SurfacePropertyGroundSurfaces, 1);
+SWIG_MODELOBJECT(SurfacePropertyIncidentSolarMultiplier, 1);
 SWIG_MODELOBJECT(SurfacePropertyConvectionCoefficients, 1);
 SWIG_MODELOBJECT(People, 1);
 SWIG_MODELOBJECT(Luminaire, 1);
diff --git a/src/model/ScheduleTypeRegistry.cpp b/src/model/ScheduleTypeRegistry.cpp
index 1859c0843d2..c53bd048a06 100644
--- a/src/model/ScheduleTypeRegistry.cpp
+++ b/src/model/ScheduleTypeRegistry.cpp
@@ -399,6 +399,12 @@ namespace model {
       {"SurfacePropertySurroundingSurfaces", "Sky Temperature", "skyTemperatureSchedule", true, "Temperature", OptionalDouble(), OptionalDouble()},
       {"SurfacePropertySurroundingSurfaces", "Ground Temperature", "groundTemperatureSchedule", true, "Temperature", OptionalDouble(),
        OptionalDouble()},
+      {"SurfacePropertySurroundingSurfaces", "Surrounding Surface Temperature Schedule", "surroundingSurfaceTemperatureSchedule", true, "Temperature",
+       OptionalDouble(), OptionalDouble()},
+      {"SurfacePropertyGroundSurfaces", "Ground Surface Temperature", "groundSurfaceTemperatureSchedule", true, "Temperature", OptionalDouble(),
+       OptionalDouble()},
+      {"SurfacePropertyGroundSurfaces", "Ground Surface Reflectance", "groundSurfaceReflectanceSchedule", true, "", 0.0, 1.0},
+      {"SurfacePropertyIncidentSolarMultiplier", "Incident Solar Multiplier", "incidentSolarMultiplierSchedule", true, "", 0.0, 1.0},
       {"SurfacePropertyLocalEnvironment", "External Shading Fraction", "externalShadingFractionSchedule", true, "", 0.0, 1.0},
       {"SwimmingPoolIndoor", "Activity Factor", "activityFactorSchedule", true, "", 0.0, OptionalDouble()},  // can exceed 1.0, for wave pools for eg
       {"SwimmingPoolIndoor", "Make-up Water Supply", "makeupWaterSupplySchedule", true, "Temperature", OptionalDouble(), OptionalDouble()},
diff --git a/src/model/SubSurface.cpp b/src/model/SubSurface.cpp
index 145ac6dcae9..14217338e99 100644
--- a/src/model/SubSurface.cpp
+++ b/src/model/SubSurface.cpp
@@ -62,6 +62,8 @@
 #include "SurfacePropertyConvectionCoefficients_Impl.hpp"
 #include "SurfacePropertyLocalEnvironment.hpp"
 #include "SurfacePropertyLocalEnvironment_Impl.hpp"
+#include "SurfacePropertyIncidentSolarMultiplier.hpp"
+#include "SurfacePropertyIncidentSolarMultiplier_Impl.hpp"
 #include "AirflowNetworkSurface.hpp"
 #include "AirflowNetworkSurface_Impl.hpp"
 #include "AirflowNetworkDetailedOpening.hpp"
@@ -916,6 +918,24 @@ namespace model {
       }
     }
 
+    boost::optional<SurfacePropertyIncidentSolarMultiplier> SubSurface_Impl::surfacePropertyIncidentSolarMultiplier() const {
+      std::vector<SurfacePropertyIncidentSolarMultiplier> allspism(model().getConcreteModelObjects<SurfacePropertyIncidentSolarMultiplier>());
+      std::vector<SurfacePropertyIncidentSolarMultiplier> spism;
+      for (auto& spcc : allspism) {
+        if (spcc.subSurface().handle() == handle()) {
+          spism.push_back(spcc);
+        }
+      }
+      if (spism.empty()) {
+        return boost::none;
+      } else if (spism.size() == 1) {
+        return spism.at(0);
+      } else {
+        LOG(Error, "More than one SurfacePropertyIncidentSolarMultiplier points to this SubSurface");
+        return boost::none;
+      }
+    }
+
     boost::optional<SurfacePropertyOtherSideCoefficients> SubSurface_Impl::surfacePropertyOtherSideCoefficients() const {
       return getObject<SubSurface>().getModelObjectTarget<SurfacePropertyOtherSideCoefficients>(OS_SubSurfaceFields::OutsideBoundaryConditionObject);
     }
@@ -1564,6 +1584,10 @@ namespace model {
     return getImpl<detail::SubSurface_Impl>()->surfacePropertyLocalEnvironment();
   }
 
+  boost::optional<SurfacePropertyIncidentSolarMultiplier> SubSurface::surfacePropertyIncidentSolarMultiplier() const {
+    return getImpl<detail::SubSurface_Impl>()->surfacePropertyIncidentSolarMultiplier();
+  }
+
   boost::optional<SurfacePropertyOtherSideCoefficients> SubSurface::surfacePropertyOtherSideCoefficients() const {
     return getImpl<detail::SubSurface_Impl>()->surfacePropertyOtherSideCoefficients();
   }
diff --git a/src/model/SubSurface.hpp b/src/model/SubSurface.hpp
index 26413e134a5..a7aaa4ec575 100644
--- a/src/model/SubSurface.hpp
+++ b/src/model/SubSurface.hpp
@@ -49,6 +49,7 @@ namespace model {
   class SurfacePropertyOtherSideConditionsModel;
   class SurfacePropertyConvectionCoefficients;
   class SurfacePropertyLocalEnvironment;
+  class SurfacePropertyIncidentSolarMultiplier;
   class AirflowNetworkSurface;
   class AirflowNetworkDetailedOpening;
   class AirflowNetworkSimpleOpening;
@@ -199,6 +200,9 @@ namespace model {
     /** Returns the SurfacePropertyLocalEnvironment, if it exists. */
     boost::optional<SurfacePropertyLocalEnvironment> surfacePropertyLocalEnvironment() const;
 
+    /** Return the SurfacePropertyIncidentSolarMultiplier that points to this surface if any */
+    boost::optional<SurfacePropertyIncidentSolarMultiplier> surfacePropertyIncidentSolarMultiplier() const;
+
     /** Returns the adjacent SurfaceSurfacePropertyOtherSideCoefficients, if it exists. */
     boost::optional<SurfacePropertyOtherSideCoefficients> surfacePropertyOtherSideCoefficients() const;
 
diff --git a/src/model/SubSurface_Impl.hpp b/src/model/SubSurface_Impl.hpp
index c2caa310308..50eb8ba0126 100644
--- a/src/model/SubSurface_Impl.hpp
+++ b/src/model/SubSurface_Impl.hpp
@@ -51,6 +51,7 @@ namespace model {
   class SurfacePropertyOtherSideConditionsModel;
   class SurfacePropertyConvectionCoefficients;
   class SurfacePropertyLocalEnvironment;
+  class SurfacePropertyIncidentSolarMultiplier;
 
   namespace detail {
 
@@ -237,6 +238,8 @@ namespace model {
 
       boost::optional<SurfacePropertyLocalEnvironment> surfacePropertyLocalEnvironment() const;
 
+      boost::optional<SurfacePropertyIncidentSolarMultiplier> surfacePropertyIncidentSolarMultiplier() const;
+
       /** Returns the adjacent SurfaceSurfacePropertyOtherSideCoefficients, if it exists. */
       boost::optional<SurfacePropertyOtherSideCoefficients> surfacePropertyOtherSideCoefficients() const;
 
diff --git a/src/model/SurfacePropertyGroundSurfaces.cpp b/src/model/SurfacePropertyGroundSurfaces.cpp
new file mode 100644
index 00000000000..1c4a5bfa7a8
--- /dev/null
+++ b/src/model/SurfacePropertyGroundSurfaces.cpp
@@ -0,0 +1,423 @@
+/***********************************************************************************************************************
+*  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 "SurfacePropertyGroundSurfaces.hpp"
+#include "SurfacePropertyGroundSurfaces_Impl.hpp"
+
+#include "Schedule.hpp"
+#include "Schedule_Impl.hpp"
+#include "ScheduleTypeLimits.hpp"
+#include "ScheduleTypeRegistry.hpp"
+#include "ModelExtensibleGroup.hpp"
+#include "SurfacePropertyLocalEnvironment.hpp"
+#include "SurfacePropertyLocalEnvironment_Impl.hpp"
+
+#include <utilities/idd/IddEnums.hxx>
+#include <utilities/idd/OS_SurfaceProperty_GroundSurfaces_FieldEnums.hxx>
+#include <utility>
+
+#include "../utilities/core/Assert.hpp"
+
+namespace openstudio {
+namespace model {
+
+  /***************************************************************************************************************************************************
+   *                                             G R O U N D    S U R F A C E    G R O U P    W R A P P E R                                          *
+   **************************************************************************************************************************************************/
+
+  GroundSurfaceGroup::GroundSurfaceGroup(std::string groundSurfaceName, double viewFactor, boost::optional<Schedule> temperatureSchedule,
+                                         boost::optional<Schedule> reflectanceSchedule)
+    : m_groundSurfaceName(std::move(groundSurfaceName)),
+      m_viewFactor(viewFactor),
+      m_temperatureSch(std::move(temperatureSchedule)),
+      m_reflectanceSch(std::move(reflectanceSchedule)) {
+
+    // Matches the maximum value in IDD
+    if (m_viewFactor > 1) {
+      LOG_AND_THROW("Unable to create GroundSurfaceGroup, View Factor of " << m_viewFactor << " cannot be more than 1.");
+    } else if (m_viewFactor < 0) {
+      LOG_AND_THROW("Unable to create GroundSurfaceGroup, View Factor of " << m_viewFactor << " cannot be less than 0.");
+    }
+
+    if (m_groundSurfaceName.empty()) {
+      LOG_AND_THROW("Unable to create GroundSurfaceGroup, GroundSurfaceName cannot be empty.");
+    }
+  }
+
+  std::string GroundSurfaceGroup::groundSurfaceName() const {
+    return m_groundSurfaceName;
+  }
+
+  double GroundSurfaceGroup::viewFactor() const {
+    return m_viewFactor;
+  }
+
+  boost::optional<Schedule> GroundSurfaceGroup::temperatureSchedule() const {
+    return m_temperatureSch;
+  }
+
+  boost::optional<Schedule> GroundSurfaceGroup::reflectanceSchedule() const {
+    return m_reflectanceSch;
+  }
+
+  std::ostream& operator<<(std::ostream& out, const openstudio::model::GroundSurfaceGroup& groundSurfaceGroup) {
+    out << "(Surface = '" << groundSurfaceGroup.groundSurfaceName() << "', "
+        << "View Factor = " << groundSurfaceGroup.viewFactor() << ", ";
+    if (groundSurfaceGroup.temperatureSchedule()) {
+      out << "Temperature Schedule = '" << groundSurfaceGroup.temperatureSchedule()->nameString() << "', ";
+    } else {
+      out << "No Temperature Schedule Assigned, ";
+    }
+    if (groundSurfaceGroup.reflectanceSchedule()) {
+      out << "Reflectance Schedule = '" << groundSurfaceGroup.reflectanceSchedule()->nameString() << "')";
+    } else {
+      out << "No Reflectance Schedule Assigned)";
+    }
+    return out;
+  }
+
+  namespace detail {
+
+    SurfacePropertyGroundSurfaces_Impl::SurfacePropertyGroundSurfaces_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle)
+      : ModelObject_Impl(idfObject, model, keepHandle) {
+      OS_ASSERT(idfObject.iddObject().type() == SurfacePropertyGroundSurfaces::iddObjectType());
+    }
+
+    SurfacePropertyGroundSurfaces_Impl::SurfacePropertyGroundSurfaces_Impl(const openstudio::detail::WorkspaceObject_Impl& other, Model_Impl* model,
+                                                                           bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {
+      OS_ASSERT(other.iddObject().type() == SurfacePropertyGroundSurfaces::iddObjectType());
+    }
+
+    SurfacePropertyGroundSurfaces_Impl::SurfacePropertyGroundSurfaces_Impl(const SurfacePropertyGroundSurfaces_Impl& other, Model_Impl* model,
+                                                                           bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {}
+
+    const std::vector<std::string>& SurfacePropertyGroundSurfaces_Impl::outputVariableNames() const {
+      static std::vector<std::string> result;
+      if (result.empty()) {
+      }
+      return result;
+    }
+
+    IddObjectType SurfacePropertyGroundSurfaces_Impl::iddObjectType() const {
+      return SurfacePropertyGroundSurfaces::iddObjectType();
+    }
+
+    std::vector<ScheduleTypeKey> SurfacePropertyGroundSurfaces_Impl::getScheduleTypeKeys(const Schedule& schedule) const {
+      std::vector<ScheduleTypeKey> result;
+
+      // This is unusual, but the schedule is in the Extensible Fields (and only there)
+      // UnsignedVector fieldIndices = getSourceIndices(schedule.handle());
+      UnsignedVector fieldIndices;
+      for (const ModelExtensibleGroup& group : castVector<ModelExtensibleGroup>(extensibleGroups())) {
+        UnsignedVector thisFieldIndices = group.getSourceFieldIndices(schedule.handle());
+        fieldIndices.insert(fieldIndices.end(), thisFieldIndices.begin(), thisFieldIndices.end());
+      }
+
+      // Make unique, have to sort before calling unique, unique only works on consecutive elements
+      std::sort(fieldIndices.begin(), fieldIndices.end());
+      fieldIndices.erase(std::unique(fieldIndices.begin(), fieldIndices.end()), fieldIndices.end());
+
+      UnsignedVector::const_iterator b(fieldIndices.begin());
+      UnsignedVector::const_iterator e(fieldIndices.end());
+      if (std::find(b, e, OS_SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceTemperatureScheduleName) != e) {
+        result.emplace_back("SurfacePropertyGroundSurfaces", "Ground Surface Temperature");
+      } else if (std::find(b, e, OS_SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceReflectanceScheduleName) != e) {
+        result.emplace_back("SurfacePropertyGroundSurfaces", "Ground Surface Reflectance");
+      }
+
+      return result;
+    }
+
+    // Extensible groups
+
+    unsigned int SurfacePropertyGroundSurfaces_Impl::numberofGroundSurfaceGroups() const {
+      return numExtensibleGroups();
+    }
+
+    boost::optional<unsigned> SurfacePropertyGroundSurfaces_Impl::groundSurfaceGroupIndex(const std::string& groundSurfaceName) const {
+      boost::optional<unsigned> result;
+
+      // Find with custom predicate, checking handle equality between the toSurface and the fromSurface pairs
+      // We do it with extensibleGroups() (rather than groundSurfaceGroups()) and getString to avoid overhead
+      // of manipulating actual model objects (getTarget, then create a GroundSurfaceGroups wrapper, get handle convert to string...)
+      // and speed up the routine
+      auto egs = castVector<WorkspaceExtensibleGroup>(extensibleGroups());
+      auto it = std::find_if(egs.begin(), egs.end(), [&groundSurfaceName](const WorkspaceExtensibleGroup& eg) {
+        return openstudio::istringEqual(eg.getField(OS_SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceName).get(), groundSurfaceName);
+      });
+
+      // If found, we compute the index by using std::distance between the start of vector and the iterator returned by std::find_if
+      if (it != egs.end()) {
+        result = std::distance(egs.begin(), it);
+      }
+
+      return result;
+    }
+
+    boost::optional<unsigned> SurfacePropertyGroundSurfaces_Impl::groundSurfaceGroupIndex(const GroundSurfaceGroup& groundSurfaceGroup) const {
+      return groundSurfaceGroupIndex(groundSurfaceGroup.groundSurfaceName());
+    }
+
+    boost::optional<GroundSurfaceGroup> SurfacePropertyGroundSurfaces_Impl::getGroundSurfaceGroup(unsigned groupIndex) const {
+
+      boost::optional<GroundSurfaceGroup> result;
+
+      if (groupIndex >= numberofGroundSurfaceGroups()) {
+        LOG(Error, "Asked to get GroundSurfaceGroup with index " << groupIndex << ", but " << briefDescription() << " has just "
+                                                                 << numberofGroundSurfaceGroups() << " GroundSurfaceGroups.");
+        return result;
+      }
+
+      auto group = getExtensibleGroup(groupIndex).cast<ModelExtensibleGroup>();
+
+      boost::optional<std::string> surfaceName_ = group.getString(OS_SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceName);
+      boost::optional<double> viewFactor_ = group.getDouble(OS_SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceViewFactor);
+      boost::optional<Schedule> tempSch_ =
+        group.getModelObjectTarget<Schedule>(OS_SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceTemperatureScheduleName);
+
+      boost::optional<Schedule> reflectanceSch_ =
+        group.getModelObjectTarget<Schedule>(OS_SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceReflectanceScheduleName);
+
+      if (!surfaceName_) {
+        LOG(Error, "Could not retrieve GroundSurfaceName for extensible group " << group.groupIndex() << ".");
+      }
+      if (!viewFactor_) {
+        LOG(Error, "Could not retrieve GroundSurfaceViewFactor for extensible group " << group.groupIndex() << ".");
+      }
+
+      // Schedules are optional
+
+      result = GroundSurfaceGroup(surfaceName_.get(), viewFactor_.get(), tempSch_, reflectanceSch_);
+
+      return result;
+    }
+
+    bool SurfacePropertyGroundSurfaces_Impl::addGroundSurfaceGroup(const GroundSurfaceGroup& groundSurfaceGroup) {
+
+      // Bounds checking happens in the GroundSurfaceGroup ctor
+
+      // Check if viewFactor already exists
+      boost::optional<unsigned> _existingIndex = groundSurfaceGroupIndex(groundSurfaceGroup);
+      if (_existingIndex) {
+        boost::optional<GroundSurfaceGroup> _group = getGroundSurfaceGroup(_existingIndex.get());
+        OS_ASSERT(_group);
+        LOG(Warn, "For " << briefDescription() << ", GroundSurfaceGroup already exists, will be modified in place from " << _group.get() << " to "
+                         << groundSurfaceGroup << ".");
+      }
+
+      // If existing, get it, otherwise Push an extensible group. ModelExtensibleGroup cannot be default-constructed, so use a ternary operator
+      // Given that we will potentially push many extensible groups
+      // we will suffer from going through the internal checks in WorkspaceObject, especially in setPointer,
+      // and performance will be roughly O(n^2) when adding groups.
+      // So to improve the performance we pushExtensible group without validity check, and call setPointer without validity check (`isValid`)
+      std::vector<std::string> temp;
+      ModelExtensibleGroup eg = (_existingIndex ? getExtensibleGroup(_existingIndex.get()).cast<ModelExtensibleGroup>()
+                                                : pushExtensibleGroup(temp, false).cast<ModelExtensibleGroup>());
+
+      bool result = false;
+
+      bool surfaceNameOk = eg.setString(OS_SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceName, groundSurfaceGroup.groundSurfaceName());
+
+      bool viewFactorOk = eg.setDouble(OS_SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceViewFactor, groundSurfaceGroup.viewFactor());
+
+      bool schTempOk = true;
+      if (auto sch_ = groundSurfaceGroup.temperatureSchedule()) {
+        schTempOk = eg.setPointer(OS_SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceTemperatureScheduleName, sch_->handle(), false);
+        if (!schTempOk) {
+          LOG(Error, "Unable to add Ground Surface Group which has an incompatible Temperature Schedule to " << briefDescription());
+          OS_ASSERT(false);
+        }
+      } else {
+        eg.setString(OS_SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceTemperatureScheduleName, "");
+      }
+
+      bool schRefOk = true;
+      if (auto sch_ = groundSurfaceGroup.reflectanceSchedule()) {
+        schRefOk = eg.setPointer(OS_SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceReflectanceScheduleName, sch_->handle(), false);
+        if (!schRefOk) {
+          LOG(Error, "Unable to add Ground Surface Group which has an incompatible Reflectance Schedule to " << briefDescription());
+
+          OS_ASSERT(false);
+        }
+      } else {
+        eg.setString(OS_SurfaceProperty_GroundSurfacesExtensibleFields::GroundSurfaceReflectanceScheduleName, "");
+      }
+
+      if (surfaceNameOk && viewFactorOk && schTempOk && schRefOk) {
+        result = true;
+      } else {
+        // Something went wrong
+        // So erase the new extensible group
+        getObject<ModelObject>().eraseExtensibleGroup(eg.groupIndex());
+        result = false;
+      }
+      return result;
+    }
+
+    // Overloads, it creates a GroundSurfaceGroup wrapper, then call `addGroundSurfaceGroup(const GroundSurfaceGroup& groundSurfaceGroup)`
+    bool SurfacePropertyGroundSurfaces_Impl::addGroundSurfaceGroup(const std::string& groundSurfaceName, double viewFactor,
+                                                                   boost::optional<Schedule> temperatureSchedule,
+                                                                   boost::optional<Schedule> reflectanceSchedule) {
+      GroundSurfaceGroup groundSurfaceGroup(groundSurfaceName, viewFactor, std::move(temperatureSchedule), std::move(reflectanceSchedule));
+      return addGroundSurfaceGroup(groundSurfaceGroup);
+    }
+
+    bool SurfacePropertyGroundSurfaces_Impl::addGroundSurfaceGroups(const std::vector<GroundSurfaceGroup>& groundSurfaceGroups) {
+      bool result = true;
+
+      for (const auto& groundSurfaceGroup : groundSurfaceGroups) {
+        bool thisResult = addGroundSurfaceGroup(groundSurfaceGroup);
+        if (!thisResult) {
+          LOG(Error, "Could not add groundSurfaceGroup " << groundSurfaceGroup << " to " << briefDescription() << ". Continuing with others.");
+          // OS_ASSERT(false);
+          // result = false;
+        }
+      }
+
+      return result;
+    }
+
+    bool SurfacePropertyGroundSurfaces_Impl::removeGroundSurfaceGroup(unsigned groupIndex) {
+      bool result = false;
+
+      unsigned int num = numberofGroundSurfaceGroups();
+      if (groupIndex < num) {
+        getObject<ModelObject>().eraseExtensibleGroup(groupIndex);
+        result = true;
+      }
+      return result;
+    }
+
+    void SurfacePropertyGroundSurfaces_Impl::removeAllGroundSurfaceGroups() {
+      getObject<ModelObject>().clearExtensibleGroups();
+    }
+
+    std::vector<GroundSurfaceGroup> SurfacePropertyGroundSurfaces_Impl::groundSurfaceGroups() const {
+      std::vector<GroundSurfaceGroup> result;
+
+      for (unsigned i = 0; i < numberofGroundSurfaceGroups(); ++i) {
+
+        boost::optional<GroundSurfaceGroup> group_ = getGroundSurfaceGroup(i);
+
+        // getViewFactor is responsible for handling error and issuing Error log messages.
+        // Here we add it to the result array if it worked, and if it didn't, we keep going
+        // We just issue a message about index so user can delete it easily
+        if (group_) {
+          result.push_back(group_.get());
+        } else {
+          LOG(Error, briefDescription() << " has an invalid GroundSurfaceGroup group at index " << i);
+        }
+      }
+
+      return result;
+    }
+
+    // Helper
+    boost::optional<SurfacePropertyLocalEnvironment> SurfacePropertyGroundSurfaces_Impl::surfacePropertyLocalEnvironment() const {
+      std::vector<SurfacePropertyLocalEnvironment> localEnvs =
+        getObject<ModelObject>().getModelObjectSources<SurfacePropertyLocalEnvironment>(SurfacePropertyLocalEnvironment::iddObjectType());
+      if (localEnvs.empty()) {
+        return boost::none;
+      } else if (localEnvs.size() == 1) {
+        return localEnvs.at(0);
+      } else {
+        LOG(Error, "More than one SurfacePropertyLocalEnvironments point to this SurfacePropertyGroundSurfaces");
+        return boost::none;
+      }
+    }
+
+  }  // namespace detail
+
+  SurfacePropertyGroundSurfaces::SurfacePropertyGroundSurfaces(const Model& model)
+    : ModelObject(SurfacePropertyGroundSurfaces::iddObjectType(), model) {
+    OS_ASSERT(getImpl<detail::SurfacePropertyGroundSurfaces_Impl>());
+  }
+
+  IddObjectType SurfacePropertyGroundSurfaces::iddObjectType() {
+    return {IddObjectType::OS_SurfaceProperty_GroundSurfaces};
+  }
+
+  // Extensible fields
+
+  std::vector<GroundSurfaceGroup> SurfacePropertyGroundSurfaces::groundSurfaceGroups() const {
+    return getImpl<detail::SurfacePropertyGroundSurfaces_Impl>()->groundSurfaceGroups();
+  }
+
+  unsigned int SurfacePropertyGroundSurfaces::numberofGroundSurfaceGroups() const {
+    return getImpl<detail::SurfacePropertyGroundSurfaces_Impl>()->numberofGroundSurfaceGroups();
+  }
+
+  boost::optional<unsigned> SurfacePropertyGroundSurfaces::groundSurfaceGroupIndex(const GroundSurfaceGroup& groundSurfaceGroup) const {
+    return getImpl<detail::SurfacePropertyGroundSurfaces_Impl>()->groundSurfaceGroupIndex(groundSurfaceGroup);
+  }
+  boost::optional<unsigned> SurfacePropertyGroundSurfaces::groundSurfaceGroupIndex(const std::string& groundSurfaceName) const {
+    return getImpl<detail::SurfacePropertyGroundSurfaces_Impl>()->groundSurfaceGroupIndex(groundSurfaceName);
+  }
+
+  boost::optional<GroundSurfaceGroup> SurfacePropertyGroundSurfaces::getGroundSurfaceGroup(unsigned groupIndex) const {
+    return getImpl<detail::SurfacePropertyGroundSurfaces_Impl>()->getGroundSurfaceGroup(groupIndex);
+  }
+
+  bool SurfacePropertyGroundSurfaces::addGroundSurfaceGroup(const GroundSurfaceGroup& groundSurfaceGroup) {
+    return getImpl<detail::SurfacePropertyGroundSurfaces_Impl>()->addGroundSurfaceGroup(groundSurfaceGroup);
+  }
+
+  // Overloads, it creates a GroundSurfaceGroup wrapper, then call `addGroundSurfaceGroup(const GroundSurfaceGroup& groundSurfaceGroup)`
+  bool SurfacePropertyGroundSurfaces::addGroundSurfaceGroup(const std::string& groundSurfaceName, double viewFactor,
+                                                            boost::optional<Schedule> temperatureSchedule,
+                                                            boost::optional<Schedule> reflectanceSchedule) {
+    return getImpl<detail::SurfacePropertyGroundSurfaces_Impl>()->addGroundSurfaceGroup(groundSurfaceName, viewFactor, std::move(temperatureSchedule),
+                                                                                        std::move(reflectanceSchedule));
+  }
+
+  bool SurfacePropertyGroundSurfaces::addGroundSurfaceGroups(const std::vector<GroundSurfaceGroup>& groundSurfaceGroups) {
+    return getImpl<detail::SurfacePropertyGroundSurfaces_Impl>()->addGroundSurfaceGroups(groundSurfaceGroups);
+  }
+
+  bool SurfacePropertyGroundSurfaces::removeGroundSurfaceGroup(unsigned groupIndex) {
+    return getImpl<detail::SurfacePropertyGroundSurfaces_Impl>()->removeGroundSurfaceGroup(groupIndex);
+  }
+
+  void SurfacePropertyGroundSurfaces::removeAllGroundSurfaceGroups() {
+    getImpl<detail::SurfacePropertyGroundSurfaces_Impl>()->removeAllGroundSurfaceGroups();
+  }
+
+  boost::optional<SurfacePropertyLocalEnvironment> SurfacePropertyGroundSurfaces::surfacePropertyLocalEnvironment() const {
+    return getImpl<detail::SurfacePropertyGroundSurfaces_Impl>()->surfacePropertyLocalEnvironment();
+  }
+
+  /// @cond
+  SurfacePropertyGroundSurfaces::SurfacePropertyGroundSurfaces(std::shared_ptr<detail::SurfacePropertyGroundSurfaces_Impl> impl)
+    : ModelObject(std::move(impl)) {}
+  /// @endcond
+
+}  // namespace model
+}  // namespace openstudio
diff --git a/src/model/SurfacePropertyGroundSurfaces.hpp b/src/model/SurfacePropertyGroundSurfaces.hpp
new file mode 100644
index 00000000000..c9becafe8f3
--- /dev/null
+++ b/src/model/SurfacePropertyGroundSurfaces.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_SURFACEPROPERTYGROUNDSURFACES_HPP
+#define MODEL_SURFACEPROPERTYGROUNDSURFACES_HPP
+
+#include <model/ModelAPI.hpp>
+#include "ModelObject.hpp"
+#include "Schedule.hpp"
+
+namespace openstudio {
+namespace model {
+
+  class SurfacePropertyLocalEnvironment;
+
+  namespace detail {
+
+    class SurfacePropertyGroundSurfaces_Impl;
+
+  }  // namespace detail
+
+  /** This class implements an extensible group */
+  class MODEL_API GroundSurfaceGroup
+  {
+   public:
+    GroundSurfaceGroup(std::string groundSurfaceName, double viewFactor, boost::optional<Schedule> temperatureSchedule = boost::none,
+                       boost::optional<Schedule> reflectanceSchedule = boost::none);
+
+    std::string groundSurfaceName() const;
+    double viewFactor() const;
+    boost::optional<Schedule> temperatureSchedule() const;
+
+    boost::optional<Schedule> reflectanceSchedule() const;
+
+   private:
+    // From
+    std::string m_groundSurfaceName;
+    double m_viewFactor;
+    boost::optional<Schedule> m_temperatureSch;
+    boost::optional<Schedule> m_reflectanceSch;
+    REGISTER_LOGGER("openstudio.model.GroundSurfaceGroup");
+  };
+
+  // Overload operator<<
+  MODEL_API std::ostream& operator<<(std::ostream& out, const openstudio::model::GroundSurfaceGroup& groundSurfaceGroup);
+
+  /** SurfacePropertyGroundSurfaces is a ModelObject that wraps the OpenStudio IDD object 'OS:SurfaceProperty:GroundSurfaces'. */
+  class MODEL_API SurfacePropertyGroundSurfaces : public ModelObject
+  {
+   public:
+    /** @name Constructors and Destructors */
+    //@{
+
+    explicit SurfacePropertyGroundSurfaces(const Model& model);
+
+    virtual ~SurfacePropertyGroundSurfaces() = default;
+
+    //@}
+
+    static IddObjectType iddObjectType();
+
+    /** @name Getters */
+    //@{
+
+    //@}
+    /** @name Setters */
+    //@{
+
+    //@}
+    /** @name Other */
+    //@{
+
+    // Helper to get the parent SurfaceProperty:LocalEnvironment object
+    boost::optional<SurfacePropertyLocalEnvironment> surfacePropertyLocalEnvironment() const;
+
+    // Handle this object's extensible fields.
+    std::vector<GroundSurfaceGroup> groundSurfaceGroups() const;
+
+    unsigned int numberofGroundSurfaceGroups() const;
+
+    /** Looks up by Surface Name (case-insensitive)  */
+    boost::optional<unsigned> groundSurfaceGroupIndex(const GroundSurfaceGroup& groundSurfaceGroup) const;
+    boost::optional<unsigned> groundSurfaceGroupIndex(const std::string& groundSurfaceName) const;
+
+    boost::optional<GroundSurfaceGroup> getGroundSurfaceGroup(unsigned groupIndex) const;
+
+    /** If a groundSurfaceGroup group is already present (cf `groundSurfaceGroupIndex()`), it will Warn and override the groundSurfaceGroup value */
+    bool addGroundSurfaceGroup(const GroundSurfaceGroup& groundSurfaceGroup);
+
+    // Overloads, it creates a GroundSurfaceGroup wrapper, then call `addGroundSurfaceGroup(const GroundSurfaceGroup& groundSurfaceGroup)`
+    bool addGroundSurfaceGroup(const std::string& groundSurfaceName, double viewFactor, boost::optional<Schedule> temperatureSchedule = boost::none,
+                               boost::optional<Schedule> reflectanceSchedule = boost::none);
+
+    bool addGroundSurfaceGroups(const std::vector<GroundSurfaceGroup>& groundSurfaceGroups);
+
+    bool removeGroundSurfaceGroup(unsigned groupIndex);
+
+    void removeAllGroundSurfaceGroups();
+
+    //@}
+   protected:
+    /// @cond
+    using ImplType = detail::SurfacePropertyGroundSurfaces_Impl;
+
+    explicit SurfacePropertyGroundSurfaces(std::shared_ptr<detail::SurfacePropertyGroundSurfaces_Impl> impl);
+
+    friend class detail::SurfacePropertyGroundSurfaces_Impl;
+    friend class Model;
+    friend class IdfObject;
+    friend class openstudio::detail::IdfObject_Impl;
+    /// @endcond
+   private:
+    REGISTER_LOGGER("openstudio.model.SurfacePropertyGroundSurfaces");
+  };
+
+  /** \relates SurfacePropertyGroundSurfaces*/
+  using OptionalSurfacePropertyGroundSurfaces = boost::optional<SurfacePropertyGroundSurfaces>;
+
+  /** \relates SurfacePropertyGroundSurfaces*/
+  using SurfacePropertyGroundSurfacesVector = std::vector<SurfacePropertyGroundSurfaces>;
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_SURFACEPROPERTYGROUNDSURFACES_HPP
diff --git a/src/model/SurfacePropertyGroundSurfaces_Impl.hpp b/src/model/SurfacePropertyGroundSurfaces_Impl.hpp
new file mode 100644
index 00000000000..e880379129c
--- /dev/null
+++ b/src/model/SurfacePropertyGroundSurfaces_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_SURFACEPROPERTYGROUNDSURFACES_IMPL_HPP
+#define MODEL_SURFACEPROPERTYGROUNDSURFACES_IMPL_HPP
+
+#include <model/ModelAPI.hpp>
+#include "ModelObject_Impl.hpp"
+#include "Schedule.hpp"
+
+namespace openstudio {
+namespace model {
+
+  class GroundSurfaceGroup;
+  class SurfacePropertyLocalEnvironment;
+
+  namespace detail {
+
+    /** SurfacePropertyGroundSurfaces_Impl is a ModelObject_Impl that is the implementation class for SurfacePropertyGroundSurfaces.*/
+    class MODEL_API SurfacePropertyGroundSurfaces_Impl : public ModelObject_Impl
+    {
+     public:
+      /** @name Constructors and Destructors */
+      //@{
+
+      SurfacePropertyGroundSurfaces_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle);
+
+      SurfacePropertyGroundSurfaces_Impl(const openstudio::detail::WorkspaceObject_Impl& other, Model_Impl* model, bool keepHandle);
+
+      SurfacePropertyGroundSurfaces_Impl(const SurfacePropertyGroundSurfaces_Impl& other, Model_Impl* model, bool keepHandle);
+
+      virtual ~SurfacePropertyGroundSurfaces_Impl() = default;
+
+      //@}
+      /** @name Virtual Methods */
+      //@{
+
+      virtual const std::vector<std::string>& outputVariableNames() const override;
+
+      virtual IddObjectType iddObjectType() const override;
+
+      virtual std::vector<ScheduleTypeKey> getScheduleTypeKeys(const Schedule& schedule) const override;
+
+      //@}
+      /** @name Getters */
+      //@{
+
+      //@}
+      /** @name Setters */
+      //@{
+
+      //@}
+      /** @name Other */
+      //@{
+
+      boost::optional<SurfacePropertyLocalEnvironment> surfacePropertyLocalEnvironment() const;
+
+      std::vector<GroundSurfaceGroup> groundSurfaceGroups() const;
+
+      unsigned int numberofGroundSurfaceGroups() const;
+
+      /** Looks up by Surface Name (case-insensitive)  */
+      boost::optional<unsigned> groundSurfaceGroupIndex(const GroundSurfaceGroup& groundSurfaceGroup) const;
+      boost::optional<unsigned> groundSurfaceGroupIndex(const std::string& groundSurfaceName) const;
+
+      boost::optional<GroundSurfaceGroup> getGroundSurfaceGroup(unsigned groupIndex) const;
+
+      /** If a groundSurfaceGroup group is already present (cf `groundSurfaceGroupIndex()`), it will Warn and override the groundSurfaceGroup value */
+      bool addGroundSurfaceGroup(const GroundSurfaceGroup& groundSurfaceGroup);
+
+      // Overloads, it creates a GroundSurfaceGroup wrapper, then call `addGroundSurfaceGroup(const GroundSurfaceGroup& groundSurfaceGroup)`
+      bool addGroundSurfaceGroup(const std::string& groundSurfaceName, double viewFactor, boost::optional<Schedule> temperatureSchedule = boost::none,
+                                 boost::optional<Schedule> reflectanceSchedule = boost::none);
+
+      bool addGroundSurfaceGroups(const std::vector<GroundSurfaceGroup>& groundSurfaceGroups);
+
+      bool removeGroundSurfaceGroup(unsigned groupIndex);
+
+      void removeAllGroundSurfaceGroups();
+
+      //@}
+     protected:
+     private:
+      REGISTER_LOGGER("openstudio.model.SurfacePropertyGroundSurfaces");
+    };
+
+  }  // namespace detail
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_SURFACEPROPERTYGROUNDSURFACES_IMPL_HPP
diff --git a/src/model/SurfacePropertyIncidentSolarMultiplier.cpp b/src/model/SurfacePropertyIncidentSolarMultiplier.cpp
new file mode 100644
index 00000000000..06ffe19fa42
--- /dev/null
+++ b/src/model/SurfacePropertyIncidentSolarMultiplier.cpp
@@ -0,0 +1,200 @@
+/***********************************************************************************************************************
+*  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 "SurfacePropertyIncidentSolarMultiplier.hpp"
+#include "SurfacePropertyIncidentSolarMultiplier_Impl.hpp"
+
+#include "Model.hpp"
+#include "SubSurface.hpp"
+#include "SubSurface_Impl.hpp"
+#include "Schedule.hpp"
+#include "Schedule_Impl.hpp"
+#include "ScheduleTypeLimits.hpp"
+#include "ScheduleTypeRegistry.hpp"
+
+#include <utilities/idd/IddEnums.hxx>
+#include <utilities/idd/OS_SurfaceProperty_IncidentSolarMultiplier_FieldEnums.hxx>
+
+#include "../utilities/units/Unit.hpp"
+
+#include "../utilities/core/Assert.hpp"
+
+namespace openstudio {
+namespace model {
+
+  namespace detail {
+
+    SurfacePropertyIncidentSolarMultiplier_Impl::SurfacePropertyIncidentSolarMultiplier_Impl(const IdfObject& idfObject, Model_Impl* model,
+                                                                                             bool keepHandle)
+      : ModelObject_Impl(idfObject, model, keepHandle) {
+      OS_ASSERT(idfObject.iddObject().type() == SurfacePropertyIncidentSolarMultiplier::iddObjectType());
+    }
+
+    SurfacePropertyIncidentSolarMultiplier_Impl::SurfacePropertyIncidentSolarMultiplier_Impl(const openstudio::detail::WorkspaceObject_Impl& other,
+                                                                                             Model_Impl* model, bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {
+      OS_ASSERT(other.iddObject().type() == SurfacePropertyIncidentSolarMultiplier::iddObjectType());
+    }
+
+    SurfacePropertyIncidentSolarMultiplier_Impl::SurfacePropertyIncidentSolarMultiplier_Impl(const SurfacePropertyIncidentSolarMultiplier_Impl& other,
+                                                                                             Model_Impl* model, bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {}
+
+    const std::vector<std::string>& SurfacePropertyIncidentSolarMultiplier_Impl::outputVariableNames() const {
+      static std::vector<std::string> result;
+      if (result.empty()) {
+      }
+      return result;
+    }
+
+    IddObjectType SurfacePropertyIncidentSolarMultiplier_Impl::iddObjectType() const {
+      return SurfacePropertyIncidentSolarMultiplier::iddObjectType();
+    }
+
+    std::vector<ScheduleTypeKey> SurfacePropertyIncidentSolarMultiplier_Impl::getScheduleTypeKeys(const Schedule& schedule) const {
+      std::vector<ScheduleTypeKey> result;
+      UnsignedVector fieldIndices = getSourceIndices(schedule.handle());
+      UnsignedVector::const_iterator b(fieldIndices.begin());
+      UnsignedVector::const_iterator e(fieldIndices.end());
+      if (std::find(b, e, OS_SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplierScheduleName) != e) {
+        result.emplace_back("SurfacePropertyIncidentSolarMultiplier", "Incident Solar Multiplier");
+      }
+      return result;
+    }
+
+    SubSurface SurfacePropertyIncidentSolarMultiplier_Impl::subSurface() const {
+      boost::optional<SubSurface> value = optionalSubSurface();
+      if (!value) {
+        LOG_AND_THROW(briefDescription() << " does not have an Surface attached.");
+      }
+      return value.get();
+    }
+
+    double SurfacePropertyIncidentSolarMultiplier_Impl::incidentSolarMultiplier() const {
+      boost::optional<double> value = getDouble(OS_SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplier, true);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    boost::optional<Schedule> SurfacePropertyIncidentSolarMultiplier_Impl::incidentSolarMultiplierSchedule() const {
+      return getObject<ModelObject>().getModelObjectTarget<Schedule>(
+        OS_SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplierScheduleName);
+    }
+
+    bool SurfacePropertyIncidentSolarMultiplier_Impl::setSubSurface(const SubSurface& subSurface) {
+      bool result = setPointer(OS_SurfaceProperty_IncidentSolarMultiplierFields::SurfaceName, subSurface.handle());
+      return result;
+    }
+
+    bool SurfacePropertyIncidentSolarMultiplier_Impl::setIncidentSolarMultiplier(double incidentSolarMultiplier) {
+      bool result = setDouble(OS_SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplier, incidentSolarMultiplier);
+      return result;
+    }
+
+    bool SurfacePropertyIncidentSolarMultiplier_Impl::setIncidentSolarMultiplierSchedule(Schedule& schedule) {
+      bool result = setSchedule(OS_SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplierScheduleName,
+                                "SurfacePropertyIncidentSolarMultiplier", "Incident Solar Multiplier", schedule);
+      return result;
+    }
+
+    void SurfacePropertyIncidentSolarMultiplier_Impl::resetIncidentSolarMultiplierSchedule() {
+      bool result = setString(OS_SurfaceProperty_IncidentSolarMultiplierFields::IncidentSolarMultiplierScheduleName, "");
+      OS_ASSERT(result);
+    }
+
+    boost::optional<SubSurface> SurfacePropertyIncidentSolarMultiplier_Impl::optionalSubSurface() const {
+      return getObject<ModelObject>().getModelObjectTarget<SubSurface>(OS_SurfaceProperty_IncidentSolarMultiplierFields::SurfaceName);
+    }
+
+  }  // namespace detail
+
+  SurfacePropertyIncidentSolarMultiplier::SurfacePropertyIncidentSolarMultiplier(const SubSurface& subSurface)
+    : ModelObject(SurfacePropertyIncidentSolarMultiplier::iddObjectType(), subSurface.model()) {
+    OS_ASSERT(getImpl<detail::SurfacePropertyIncidentSolarMultiplier_Impl>());
+
+    auto subSurfaceType = subSurface.subSurfaceType();
+    if (!(istringEqual("FixedWindow", subSurfaceType) || istringEqual("OperableWindow", subSurfaceType)
+          || istringEqual("Skylight", subSurfaceType))) {
+      LOG_AND_THROW("Wrong SubSurface Type: only accepts windows, was passed " << subSurface.briefDescription());
+    }
+    bool ok = true;
+    ok = setSubSurface(subSurface);
+    OS_ASSERT(ok);
+
+    // TODO: default to alwaysOnContinous? Or leave as optional?
+    // {
+    //   auto schedule = subSurface.model().alwaysOnContinuousSchedule();
+    //   ok = setIncidentSolarMultiplierSchedule(schedule);
+    //   OS_ASSERT(ok);
+    // }
+
+    ok = setIncidentSolarMultiplier(1.0);
+    OS_ASSERT(ok);
+  }
+
+  IddObjectType SurfacePropertyIncidentSolarMultiplier::iddObjectType() {
+    return {IddObjectType::OS_SurfaceProperty_IncidentSolarMultiplier};
+  }
+
+  SubSurface SurfacePropertyIncidentSolarMultiplier::subSurface() const {
+    return getImpl<detail::SurfacePropertyIncidentSolarMultiplier_Impl>()->subSurface();
+  }
+
+  double SurfacePropertyIncidentSolarMultiplier::incidentSolarMultiplier() const {
+    return getImpl<detail::SurfacePropertyIncidentSolarMultiplier_Impl>()->incidentSolarMultiplier();
+  }
+
+  boost::optional<Schedule> SurfacePropertyIncidentSolarMultiplier::incidentSolarMultiplierSchedule() const {
+    return getImpl<detail::SurfacePropertyIncidentSolarMultiplier_Impl>()->incidentSolarMultiplierSchedule();
+  }
+
+  bool SurfacePropertyIncidentSolarMultiplier::setSubSurface(const SubSurface& subSurface) {
+    return getImpl<detail::SurfacePropertyIncidentSolarMultiplier_Impl>()->setSubSurface(subSurface);
+  }
+
+  bool SurfacePropertyIncidentSolarMultiplier::setIncidentSolarMultiplier(double incidentSolarMultiplier) {
+    return getImpl<detail::SurfacePropertyIncidentSolarMultiplier_Impl>()->setIncidentSolarMultiplier(incidentSolarMultiplier);
+  }
+
+  bool SurfacePropertyIncidentSolarMultiplier::setIncidentSolarMultiplierSchedule(Schedule& schedule) {
+    return getImpl<detail::SurfacePropertyIncidentSolarMultiplier_Impl>()->setIncidentSolarMultiplierSchedule(schedule);
+  }
+
+  void SurfacePropertyIncidentSolarMultiplier::resetIncidentSolarMultiplierSchedule() {
+    getImpl<detail::SurfacePropertyIncidentSolarMultiplier_Impl>()->resetIncidentSolarMultiplierSchedule();
+  }
+
+  /// @cond
+  SurfacePropertyIncidentSolarMultiplier::SurfacePropertyIncidentSolarMultiplier(
+    std::shared_ptr<detail::SurfacePropertyIncidentSolarMultiplier_Impl> impl)
+    : ModelObject(std::move(impl)) {}
+  /// @endcond
+
+}  // namespace model
+}  // namespace openstudio
diff --git a/src/model/SurfacePropertyIncidentSolarMultiplier.hpp b/src/model/SurfacePropertyIncidentSolarMultiplier.hpp
new file mode 100644
index 00000000000..88b13ec320a
--- /dev/null
+++ b/src/model/SurfacePropertyIncidentSolarMultiplier.hpp
@@ -0,0 +1,114 @@
+/***********************************************************************************************************************
+*  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_SURFACEPROPERTYINCIDENTSOLARMULTIPLIER_HPP
+#define MODEL_SURFACEPROPERTYINCIDENTSOLARMULTIPLIER_HPP
+
+#include <model/ModelAPI.hpp>
+#include "ModelObject.hpp"
+
+namespace openstudio {
+
+namespace model {
+
+  class SubSurface;
+  class Schedule;
+
+  namespace detail {
+
+    class SurfacePropertyIncidentSolarMultiplier_Impl;
+
+  }  // namespace detail
+
+  /** SurfacePropertyIncidentSolarMultiplier is a ModelObject that wraps the OpenStudio IDD object 'OS:SurfaceProperty:IncidentSolarMultiplier'. */
+  class MODEL_API SurfacePropertyIncidentSolarMultiplier : public ModelObject
+  {
+   public:
+    /** @name Constructors and Destructors */
+    //@{
+
+    explicit SurfacePropertyIncidentSolarMultiplier(const SubSurface& subSurface);
+
+    virtual ~SurfacePropertyIncidentSolarMultiplier() = default;
+
+    //@}
+
+    static IddObjectType iddObjectType();
+
+    /** @name Getters */
+    //@{
+
+    SubSurface subSurface() const;
+
+    double incidentSolarMultiplier() const;
+
+    boost::optional<Schedule> incidentSolarMultiplierSchedule() const;
+
+    //@}
+    /** @name Setters */
+    //@{
+
+    bool setSubSurface(const SubSurface& subSurface);
+
+    bool setIncidentSolarMultiplier(double incidentSolarMultiplier);
+
+    bool setIncidentSolarMultiplierSchedule(Schedule& schedule);
+
+    void resetIncidentSolarMultiplierSchedule();
+
+    //@}
+    /** @name Other */
+    //@{
+
+    //@}
+   protected:
+    /// @cond
+    using ImplType = detail::SurfacePropertyIncidentSolarMultiplier_Impl;
+
+    explicit SurfacePropertyIncidentSolarMultiplier(std::shared_ptr<detail::SurfacePropertyIncidentSolarMultiplier_Impl> impl);
+
+    friend class detail::SurfacePropertyIncidentSolarMultiplier_Impl;
+    friend class Model;
+    friend class IdfObject;
+    friend class openstudio::detail::IdfObject_Impl;
+    /// @endcond
+   private:
+    REGISTER_LOGGER("openstudio.model.SurfacePropertyIncidentSolarMultiplier");
+  };
+
+  /** \relates SurfacePropertyIncidentSolarMultiplier*/
+  using OptionalSurfacePropertyIncidentSolarMultiplier = boost::optional<SurfacePropertyIncidentSolarMultiplier>;
+
+  /** \relates SurfacePropertyIncidentSolarMultiplier*/
+  using SurfacePropertyIncidentSolarMultiplierVector = std::vector<SurfacePropertyIncidentSolarMultiplier>;
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_SURFACEPROPERTYINCIDENTSOLARMULTIPLIER_HPP
diff --git a/src/model/SurfacePropertyIncidentSolarMultiplier_Impl.hpp b/src/model/SurfacePropertyIncidentSolarMultiplier_Impl.hpp
new file mode 100644
index 00000000000..34b58ca9e60
--- /dev/null
+++ b/src/model/SurfacePropertyIncidentSolarMultiplier_Impl.hpp
@@ -0,0 +1,108 @@
+/***********************************************************************************************************************
+*  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_SURFACEPROPERTYINCIDENTSOLARMULTIPLIER_IMPL_HPP
+#define MODEL_SURFACEPROPERTYINCIDENTSOLARMULTIPLIER_IMPL_HPP
+
+#include <model/ModelAPI.hpp>
+#include "ModelObject_Impl.hpp"
+
+namespace openstudio {
+namespace model {
+
+  class SubSurface;
+  class Schedule;
+
+  namespace detail {
+
+    /** SurfacePropertyIncidentSolarMultiplier_Impl is a ModelObject_Impl that is the implementation class for SurfacePropertyIncidentSolarMultiplier.*/
+    class MODEL_API SurfacePropertyIncidentSolarMultiplier_Impl : public ModelObject_Impl
+    {
+     public:
+      /** @name Constructors and Destructors */
+      //@{
+
+      SurfacePropertyIncidentSolarMultiplier_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle);
+
+      SurfacePropertyIncidentSolarMultiplier_Impl(const openstudio::detail::WorkspaceObject_Impl& other, Model_Impl* model, bool keepHandle);
+
+      SurfacePropertyIncidentSolarMultiplier_Impl(const SurfacePropertyIncidentSolarMultiplier_Impl& other, Model_Impl* model, bool keepHandle);
+
+      virtual ~SurfacePropertyIncidentSolarMultiplier_Impl() = default;
+
+      //@}
+      /** @name Virtual Methods */
+      //@{
+
+      virtual const std::vector<std::string>& outputVariableNames() const override;
+
+      virtual IddObjectType iddObjectType() const override;
+
+      virtual std::vector<ScheduleTypeKey> getScheduleTypeKeys(const Schedule& schedule) const override;
+
+      //@}
+      /** @name Getters */
+      //@{
+
+      SubSurface subSurface() const;
+
+      double incidentSolarMultiplier() const;
+
+      boost::optional<Schedule> incidentSolarMultiplierSchedule() const;
+
+      //@}
+      /** @name Setters */
+      //@{
+
+      bool setSubSurface(const SubSurface& subSurface);
+
+      bool setIncidentSolarMultiplier(double incidentSolarMultiplier);
+
+      bool setIncidentSolarMultiplierSchedule(Schedule& schedule);
+
+      void resetIncidentSolarMultiplierSchedule();
+
+      //@}
+      /** @name Other */
+      //@{
+
+      //@}
+     protected:
+     private:
+      REGISTER_LOGGER("openstudio.model.SurfacePropertyIncidentSolarMultiplier");
+
+      boost::optional<SubSurface> optionalSubSurface() const;
+    };
+
+  }  // namespace detail
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_SURFACEPROPERTYINCIDENTSOLARMULTIPLIER_IMPL_HPP
diff --git a/src/model/SurfacePropertyLocalEnvironment.cpp b/src/model/SurfacePropertyLocalEnvironment.cpp
index 218e242e40f..ee70094e0df 100644
--- a/src/model/SurfacePropertyLocalEnvironment.cpp
+++ b/src/model/SurfacePropertyLocalEnvironment.cpp
@@ -42,6 +42,8 @@
 
 #include "SurfacePropertySurroundingSurfaces.hpp"
 #include "SurfacePropertySurroundingSurfaces_Impl.hpp"
+#include "SurfacePropertyGroundSurfaces.hpp"
+#include "SurfacePropertyGroundSurfaces_Impl.hpp"
 //#include "OutdoorAirNode.hpp"
 // #include "OutdoorAirNode_Impl.hpp"
 #include "ScheduleTypeLimits.hpp"
@@ -126,6 +128,11 @@ namespace model {
         OS_SurfaceProperty_LocalEnvironmentFields::SurroundingSurfacesObjectName);
     }
 
+    boost::optional<SurfacePropertyGroundSurfaces> SurfacePropertyLocalEnvironment_Impl::surfacePropertyGroundSurfaces() const {
+      return getObject<ModelObject>().getModelObjectTarget<SurfacePropertyGroundSurfaces>(
+        OS_SurfaceProperty_LocalEnvironmentFields::GroundSurfacesObjectName);
+    }
+
     bool SurfacePropertyLocalEnvironment_Impl::setExteriorSurface(const PlanarSurface& surface) {
 
       boost::optional<SurfacePropertyLocalEnvironment> currentLocalEnv;
@@ -172,6 +179,16 @@ namespace model {
       OS_ASSERT(result);
     }
 
+    bool SurfacePropertyLocalEnvironment_Impl::setSurfacePropertyGroundSurfaces(const SurfacePropertyGroundSurfaces& surfacePropertyGroundSurfaces) {
+      bool result = setPointer(OS_SurfaceProperty_LocalEnvironmentFields::GroundSurfacesObjectName, surfacePropertyGroundSurfaces.handle());
+      return result;
+    }
+
+    void SurfacePropertyLocalEnvironment_Impl::resetSurfacePropertyGroundSurfaces() {
+      bool result = setString(OS_SurfaceProperty_LocalEnvironmentFields::GroundSurfacesObjectName, "");
+      OS_ASSERT(result);
+    }
+
     //boost::optional<OutdoorAirNode> SurfacePropertyLocalEnvironment_Impl::outdoorAirNode() const {
     //return getObject<ModelObject>().getModelObjectTarget<OutdoorAirNode>(OS_SurfaceProperty_LocalEnvironmentFields::OutdoorAirNodeName);
     //}
@@ -234,6 +251,10 @@ namespace model {
     return getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->surfacePropertySurroundingSurfaces();
   }
 
+  boost::optional<SurfacePropertyGroundSurfaces> SurfacePropertyLocalEnvironment::surfacePropertyGroundSurfaces() const {
+    return getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->surfacePropertyGroundSurfaces();
+  }
+
   bool SurfacePropertyLocalEnvironment::setExteriorSurface(const PlanarSurface& surface) {
     return getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->setExteriorSurface(surface);
   }
@@ -255,6 +276,14 @@ namespace model {
     getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->resetSurfacePropertySurroundingSurfaces();
   }
 
+  bool SurfacePropertyLocalEnvironment::setSurfacePropertyGroundSurfaces(const SurfacePropertyGroundSurfaces& surfacePropertyGroundSurfaces) {
+    return getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->setSurfacePropertyGroundSurfaces(surfacePropertyGroundSurfaces);
+  }
+
+  void SurfacePropertyLocalEnvironment::resetSurfacePropertyGroundSurfaces() {
+    getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->resetSurfacePropertyGroundSurfaces();
+  }
+
   //boost::optional<OutdoorAirNode> SurfacePropertyLocalEnvironment::outdoorAirNode() const {
   //return getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->outdoorAirNode();
   //}
diff --git a/src/model/SurfacePropertyLocalEnvironment.hpp b/src/model/SurfacePropertyLocalEnvironment.hpp
index a609d88614c..7802114f5b3 100644
--- a/src/model/SurfacePropertyLocalEnvironment.hpp
+++ b/src/model/SurfacePropertyLocalEnvironment.hpp
@@ -41,6 +41,7 @@ namespace model {
   class PlanarSurface;
   class Schedule;
   class SurfacePropertySurroundingSurfaces;
+  class SurfacePropertyGroundSurfaces;
   // class OutdoorAirNode;
 
   namespace detail {
@@ -76,6 +77,8 @@ namespace model {
 
     boost::optional<SurfacePropertySurroundingSurfaces> surfacePropertySurroundingSurfaces() const;
 
+    boost::optional<SurfacePropertyGroundSurfaces> surfacePropertyGroundSurfaces() const;
+
     // boost::optional<OutdoorAirNode> outdoorAirNode() const;
 
     //@}
@@ -92,6 +95,9 @@ namespace model {
     bool setSurfacePropertySurroundingSurfaces(const SurfacePropertySurroundingSurfaces& surfacePropertySurroundingSurfaces);
     void resetSurfacePropertySurroundingSurfaces();
 
+    bool setSurfacePropertyGroundSurfaces(const SurfacePropertyGroundSurfaces& surfacePropertyGroundSurfaces);
+    void resetSurfacePropertyGroundSurfaces();
+
     // bool setOutdoorAirNode(const OutdoorAirNode& outdoorAirNode);
     // void resetOutdoorAirNode();
 
diff --git a/src/model/SurfacePropertyLocalEnvironment_Impl.hpp b/src/model/SurfacePropertyLocalEnvironment_Impl.hpp
index 99df20e6ff7..0ed0adeef15 100644
--- a/src/model/SurfacePropertyLocalEnvironment_Impl.hpp
+++ b/src/model/SurfacePropertyLocalEnvironment_Impl.hpp
@@ -41,6 +41,7 @@ namespace model {
   class SubSurface;
   class Schedule;
   class SurfacePropertySurroundingSurfaces;
+  class SurfacePropertyGroundSurfaces;
   // class OutdoorAirNode;
 
   namespace detail {
@@ -82,6 +83,8 @@ namespace model {
 
       boost::optional<SurfacePropertySurroundingSurfaces> surfacePropertySurroundingSurfaces() const;
 
+      boost::optional<SurfacePropertyGroundSurfaces> surfacePropertyGroundSurfaces() const;
+
       // boost::optional<OutdoorAirNode> outdoorAirNode() const;
 
       //@}
@@ -96,6 +99,9 @@ namespace model {
       bool setSurfacePropertySurroundingSurfaces(const SurfacePropertySurroundingSurfaces& surfacePropertySurroundingSurfaces);
       void resetSurfacePropertySurroundingSurfaces();
 
+      bool setSurfacePropertyGroundSurfaces(const SurfacePropertyGroundSurfaces& surfacePropertyGroundSurfaces);
+      void resetSurfacePropertyGroundSurfaces();
+
       // bool setOutdoorAirNode(const OutdoorAirNode& outdoorAirNode);
       // void resetOutdoorAirNode();
 
diff --git a/src/model/SurfacePropertySurroundingSurfaces.cpp b/src/model/SurfacePropertySurroundingSurfaces.cpp
index 6a46eadbe8d..9c9b50fef04 100644
--- a/src/model/SurfacePropertySurroundingSurfaces.cpp
+++ b/src/model/SurfacePropertySurroundingSurfaces.cpp
@@ -117,14 +117,38 @@ namespace model {
 
     std::vector<ScheduleTypeKey> SurfacePropertySurroundingSurfaces_Impl::getScheduleTypeKeys(const Schedule& schedule) const {
       std::vector<ScheduleTypeKey> result;
-      UnsignedVector fieldIndices = getSourceIndices(schedule.handle());
-      UnsignedVector::const_iterator b(fieldIndices.begin()), e(fieldIndices.end());
-      if (std::find(b, e, OS_SurfaceProperty_SurroundingSurfacesFields::SkyTemperatureScheduleName) != e) {
-        result.emplace_back("SurfacePropertySurroundingSurfaces", "Sky Temperature");
+
+      {
+        UnsignedVector fieldIndices = getSourceIndices(schedule.handle());
+        UnsignedVector::const_iterator b(fieldIndices.begin());
+        UnsignedVector::const_iterator e(fieldIndices.end());
+        if (std::find(b, e, OS_SurfaceProperty_SurroundingSurfacesFields::SkyTemperatureScheduleName) != e) {
+          result.emplace_back("SurfacePropertySurroundingSurfaces", "Sky Temperature");
+        }
+        if (std::find(b, e, OS_SurfaceProperty_SurroundingSurfacesFields::GroundTemperatureScheduleName) != e) {
+          result.emplace_back("SurfacePropertySurroundingSurfaces", "Ground Temperature");
+        }
       }
-      if (std::find(b, e, OS_SurfaceProperty_SurroundingSurfacesFields::GroundTemperatureScheduleName) != e) {
-        result.emplace_back("SurfacePropertySurroundingSurfaces", "Ground Temperature");
+
+      {
+        // This is unusual, but there is also a schedule in the Extensible Fields
+        UnsignedVector fieldIndices;
+        for (const ModelExtensibleGroup& group : castVector<ModelExtensibleGroup>(extensibleGroups())) {
+          UnsignedVector thisFieldIndices = group.getSourceFieldIndices(schedule.handle());
+          fieldIndices.insert(fieldIndices.end(), thisFieldIndices.begin(), thisFieldIndices.end());
+        }
+
+        // Make unique, have to sort before calling unique, unique only works on consecutive elements
+        std::sort(fieldIndices.begin(), fieldIndices.end());
+        fieldIndices.erase(std::unique(fieldIndices.begin(), fieldIndices.end()), fieldIndices.end());
+
+        UnsignedVector::const_iterator b(fieldIndices.begin());
+        UnsignedVector::const_iterator e(fieldIndices.end());
+        if (std::find(b, e, OS_SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceTemperatureScheduleName) != e) {
+          result.emplace_back("SurfacePropertySurroundingSurfaces", "Surrounding Surface Temperature Schedule");
+        }
       }
+
       return result;
     }
 


Test patch:
diff --git a/src/model/test/SurfacePropertyGroundSurfaces_GTest.cpp b/src/model/test/SurfacePropertyGroundSurfaces_GTest.cpp
new file mode 100644
index 00000000000..52ce3242466
--- /dev/null
+++ b/src/model/test/SurfacePropertyGroundSurfaces_GTest.cpp
@@ -0,0 +1,175 @@
+/***********************************************************************************************************************
+*  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 "ModelFixture.hpp"
+
+#include "../SurfacePropertyGroundSurfaces.hpp"
+#include "../SurfacePropertyGroundSurfaces_Impl.hpp"
+#include "../ScheduleConstant.hpp"
+
+using namespace openstudio;
+using namespace openstudio::model;
+
+TEST_F(ModelFixture, SurfacePropertyGroundSurfaces_GettersSetters) {
+  Model m;
+
+  ScheduleConstant tempSch(m);
+  tempSch.setValue(25.0);
+  ScheduleConstant reflectanceSch(m);
+  reflectanceSch.setValue(1.0);
+
+  {
+    // Wrong viewFactor (0 to 1)
+    EXPECT_THROW(GroundSurfaceGroup("External Surface", 1.2), openstudio::Exception);
+    EXPECT_NO_THROW(GroundSurfaceGroup("External Surface", 0.2));
+
+    EXPECT_NO_THROW(GroundSurfaceGroup("External Surface", 0.2, tempSch));
+
+    EXPECT_NO_THROW(GroundSurfaceGroup("External Surface", 0.2, tempSch, reflectanceSch));
+  }
+
+  SurfacePropertyGroundSurfaces sp(m);
+
+  EXPECT_EQ(0, sp.numberofGroundSurfaceGroups());
+  EXPECT_TRUE(sp.addGroundSurfaceGroup("External Surface 1", 0.2, tempSch, reflectanceSch));
+  EXPECT_EQ(1, sp.numberofGroundSurfaceGroups());
+
+  auto group2 = GroundSurfaceGroup("External Surface 2", 0.3, tempSch, reflectanceSch);
+  EXPECT_TRUE(sp.addGroundSurfaceGroup(group2));
+  EXPECT_EQ(2, sp.numberofGroundSurfaceGroups());
+
+  ScheduleConstant tempSch2(m);
+  tempSch2.setValue(35.0);
+  auto group3 = GroundSurfaceGroup("External Surface 3", 0.4, tempSch2);
+  EXPECT_TRUE(sp.addGroundSurfaceGroup(group3));
+  EXPECT_EQ(3, sp.numberofGroundSurfaceGroups());
+
+  boost::optional<GroundSurfaceGroup> group_ = sp.getGroundSurfaceGroup(1U);
+  ASSERT_TRUE(group_);
+  EXPECT_EQ("External Surface 2", group_->groundSurfaceName());
+  EXPECT_EQ(0.3, group_->viewFactor());
+  ASSERT_TRUE(group_->temperatureSchedule());
+  EXPECT_EQ(tempSch, group_->temperatureSchedule().get());
+  ASSERT_TRUE(group_->reflectanceSchedule());
+  EXPECT_EQ(reflectanceSch, group_->reflectanceSchedule().get());
+
+  // Test that you cannot add the same group twice (based on Surface Name), but that instead it'll overwrite the values
+  auto group2bis = GroundSurfaceGroup("External Surface 2", 0.45, tempSch2);
+  // Test that we can locate an existing ViewFactor correctly (comparing on to/from only, not viewFactor value)
+  boost::optional<unsigned> _existingIndex = sp.groundSurfaceGroupIndex(group2bis);
+  ASSERT_TRUE(_existingIndex);
+  EXPECT_EQ(1U, _existingIndex.get());
+  // Test with the std::string version
+  _existingIndex = sp.groundSurfaceGroupIndex("External Surface 2");
+  ASSERT_TRUE(_existingIndex);
+  EXPECT_EQ(1U, _existingIndex.get());
+
+  // Now call add, which should jut override it
+  EXPECT_TRUE(sp.addGroundSurfaceGroup(group2bis));
+  // Should still have the same number
+  EXPECT_EQ(3, sp.numberofGroundSurfaceGroups());
+
+  // Retrieve it again, making sure it changed only the values viewFactor and Schedule
+  boost::optional<GroundSurfaceGroup> group2_ = sp.getGroundSurfaceGroup(1U);
+  ASSERT_TRUE(group2_);
+  EXPECT_EQ("External Surface 2", group2_->groundSurfaceName());
+  EXPECT_EQ(0.45, group2_->viewFactor());
+  ASSERT_TRUE(group2_->temperatureSchedule());
+  EXPECT_EQ(tempSch2, group2_->temperatureSchedule().get());
+  EXPECT_FALSE(group2_->reflectanceSchedule());
+
+  // Via the overloaded method
+  EXPECT_TRUE(sp.addGroundSurfaceGroup("External Surface 2", 0.32, tempSch, reflectanceSch));
+  boost::optional<GroundSurfaceGroup> group3_ = sp.getGroundSurfaceGroup(1U);
+  ASSERT_TRUE(group3_);
+  EXPECT_EQ("External Surface 2", group3_->groundSurfaceName());
+  EXPECT_EQ(0.32, group3_->viewFactor());
+  ASSERT_TRUE(group3_->temperatureSchedule());
+  EXPECT_EQ(tempSch, group3_->temperatureSchedule().get());
+  ASSERT_TRUE(group3_->reflectanceSchedule());
+  EXPECT_EQ(reflectanceSch, group3_->reflectanceSchedule().get());
+
+  // Test that you cannot get a group by an index that's too high
+  EXPECT_FALSE(sp.getGroundSurfaceGroup(sp.numberofGroundSurfaceGroups()));
+
+  // Test that you cannot find a group if it doesn't exist
+  auto groupother = GroundSurfaceGroup("Another surface", 0.45, tempSch2);
+  EXPECT_FALSE(sp.groundSurfaceGroupIndex(groupother));
+
+  // Remove a viewFactor
+  EXPECT_FALSE(sp.removeGroundSurfaceGroup(1000));
+  EXPECT_EQ(3, sp.numberofGroundSurfaceGroups());
+
+  EXPECT_TRUE(sp.removeGroundSurfaceGroup(1));
+  EXPECT_EQ(2, sp.numberofGroundSurfaceGroups());
+
+  // check that remaining blocks moved correctly
+  std::vector<GroundSurfaceGroup> groups = sp.groundSurfaceGroups();
+  EXPECT_EQ(2U, groups.size());
+  EXPECT_EQ("External Surface 1", groups[0].groundSurfaceName());
+  EXPECT_EQ(0.2, groups[0].viewFactor());
+  ASSERT_TRUE(groups[0].temperatureSchedule());
+  EXPECT_EQ(tempSch, groups[0].temperatureSchedule().get());
+  ASSERT_TRUE(groups[0].reflectanceSchedule());
+  EXPECT_EQ(reflectanceSch, groups[0].reflectanceSchedule().get());
+
+  EXPECT_EQ("External Surface 3", groups[1].groundSurfaceName());
+  EXPECT_EQ(0.4, groups[1].viewFactor());
+  ASSERT_TRUE(groups[1].temperatureSchedule());
+  EXPECT_EQ(tempSch2, groups[1].temperatureSchedule().get());
+  EXPECT_FALSE(groups[1].reflectanceSchedule());
+
+  // more remove checking
+  sp.removeAllGroundSurfaceGroups();
+  EXPECT_EQ(0, sp.numberofGroundSurfaceGroups());
+  EXPECT_FALSE(sp.removeGroundSurfaceGroup(0));
+  EXPECT_EQ(0, sp.numberofGroundSurfaceGroups());
+
+  // Via a vector
+  EXPECT_TRUE(sp.addGroundSurfaceGroups({group2bis, groupother, group3}));
+  groups = sp.groundSurfaceGroups();
+  EXPECT_EQ(3U, groups.size());
+  EXPECT_EQ(group2bis.groundSurfaceName(), groups[0].groundSurfaceName());
+  EXPECT_EQ(group2bis.viewFactor(), groups[0].viewFactor());
+  ASSERT_TRUE(groups[0].temperatureSchedule());
+  EXPECT_EQ(group2bis.temperatureSchedule().get(), groups[0].temperatureSchedule().get());
+  EXPECT_FALSE(groups[0].reflectanceSchedule());
+
+  EXPECT_EQ(groupother.groundSurfaceName(), groups[1].groundSurfaceName());
+  EXPECT_EQ(groupother.viewFactor(), groups[1].viewFactor());
+  ASSERT_TRUE(groups[1].temperatureSchedule());
+  EXPECT_EQ(groupother.temperatureSchedule().get(), groups[1].temperatureSchedule().get());
+  EXPECT_FALSE(groups[1].reflectanceSchedule());
+
+  EXPECT_EQ(group3.groundSurfaceName(), groups[2].groundSurfaceName());
+  EXPECT_EQ(group3.viewFactor(), groups[2].viewFactor());
+  ASSERT_TRUE(groups[2].temperatureSchedule());
+  EXPECT_EQ(group3.temperatureSchedule().get(), groups[2].temperatureSchedule().get());
+  EXPECT_FALSE(groups[2].reflectanceSchedule());
+}
diff --git a/src/model/test/SurfacePropertyIncidentSolarMultiplier_GTest.cpp b/src/model/test/SurfacePropertyIncidentSolarMultiplier_GTest.cpp
new file mode 100644
index 00000000000..c48970adec6
--- /dev/null
+++ b/src/model/test/SurfacePropertyIncidentSolarMultiplier_GTest.cpp
@@ -0,0 +1,78 @@
+/***********************************************************************************************************************
+*  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 "ModelFixture.hpp"
+
+#include "../SurfacePropertyIncidentSolarMultiplier.hpp"
+#include "../SurfacePropertyIncidentSolarMultiplier_Impl.hpp"
+
+#include "../SubSurface.hpp"
+
+#include "../Schedule.hpp"
+#include "../ScheduleConstant.hpp"
+
+#include "../../utilities/geometry/Point3d.hpp"
+
+using namespace openstudio;
+using namespace openstudio::model;
+
+TEST_F(ModelFixture, SurfacePropertyIncidentSolarMultiplier_GettersSetters) {
+  Model m;
+
+  std::vector<Point3d> vertices{{0, 0, 1}, {0, 0, 0}, {1, 0, 0}, {1, 0, 1}};
+
+  SubSurface ss(vertices, m);
+
+  SurfacePropertyIncidentSolarMultiplier sp(ss);
+
+  EXPECT_EQ(1, sp.incidentSolarMultiplier());
+  EXPECT_FALSE(sp.incidentSolarMultiplierSchedule());
+  EXPECT_EQ(ss, sp.subSurface());
+  Schedule alwaysOnContinuous = m.alwaysOnContinuousSchedule();
+
+  // Surface Name: Required Object
+  SubSurface ss2(vertices, m);
+  EXPECT_TRUE(sp.setSubSurface(ss2));
+  EXPECT_EQ(ss2, sp.subSurface());
+  ASSERT_TRUE(ss2.surfacePropertyIncidentSolarMultiplier());
+  EXPECT_EQ(sp, ss2.surfacePropertyIncidentSolarMultiplier().get());
+
+  // Incident Solar Multiplier: Required Double
+  EXPECT_TRUE(sp.setIncidentSolarMultiplier(0.75));
+  EXPECT_EQ(0.75, sp.incidentSolarMultiplier());
+  // Bad Value
+  EXPECT_FALSE(sp.setIncidentSolarMultiplier(-10.0));
+  EXPECT_EQ(0.75, sp.incidentSolarMultiplier());
+
+  // Incident Solar Multiplier Schedule Name: Optional Object
+  ScheduleConstant sch(m);
+  EXPECT_TRUE(sp.setIncidentSolarMultiplierSchedule(sch));
+  ASSERT_TRUE(sp.incidentSolarMultiplierSchedule());
+  EXPECT_EQ(sch, sp.incidentSolarMultiplierSchedule().get());
+}
diff --git a/src/model/test/SurfacePropertyLocalEnvironment_GTest.cpp b/src/model/test/SurfacePropertyLocalEnvironment_GTest.cpp
index 1e4675f11fe..7c05fb1bdde 100644
--- a/src/model/test/SurfacePropertyLocalEnvironment_GTest.cpp
+++ b/src/model/test/SurfacePropertyLocalEnvironment_GTest.cpp
@@ -36,6 +36,7 @@
 #include "../Schedule.hpp"
 #include "../ScheduleConstant.hpp"
 #include "../SurfacePropertySurroundingSurfaces.hpp"
+#include "../SurfacePropertyGroundSurfaces.hpp"
 
 #include "../../utilities/geometry/Point3d.hpp"
 
@@ -88,19 +89,38 @@ TEST_F(ModelFixture, SurfacePropertyLocalEnvironment_GettersSetters) {
   EXPECT_FALSE(surfacePropertyLocalEnvironment.externalShadingFractionSchedule());
 
   // Surrounding Surfaces Object Name: Optional Object
-  EXPECT_FALSE(surfacePropertyLocalEnvironment.surfacePropertySurroundingSurfaces());
-  SurfacePropertySurroundingSurfaces sp(m);
-  EXPECT_FALSE(sp.surfacePropertyLocalEnvironment());
-
-  EXPECT_TRUE(surfacePropertyLocalEnvironment.setSurfacePropertySurroundingSurfaces(sp));
-  ASSERT_TRUE(surfacePropertyLocalEnvironment.surfacePropertySurroundingSurfaces());
-  EXPECT_EQ(sp, surfacePropertyLocalEnvironment.surfacePropertySurroundingSurfaces().get());
-
-  ASSERT_TRUE(sp.surfacePropertyLocalEnvironment());
-  EXPECT_EQ(surfacePropertyLocalEnvironment, sp.surfacePropertyLocalEnvironment().get());
-
-  surfacePropertyLocalEnvironment.resetSurfacePropertySurroundingSurfaces();
-  EXPECT_FALSE(surfacePropertyLocalEnvironment.surfacePropertySurroundingSurfaces());
+  {
+    EXPECT_FALSE(surfacePropertyLocalEnvironment.surfacePropertySurroundingSurfaces());
+    SurfacePropertySurroundingSurfaces sp(m);
+    EXPECT_FALSE(sp.surfacePropertyLocalEnvironment());
+
+    EXPECT_TRUE(surfacePropertyLocalEnvironment.setSurfacePropertySurroundingSurfaces(sp));
+    ASSERT_TRUE(surfacePropertyLocalEnvironment.surfacePropertySurroundingSurfaces());
+    EXPECT_EQ(sp, surfacePropertyLocalEnvironment.surfacePropertySurroundingSurfaces().get());
+
+    ASSERT_TRUE(sp.surfacePropertyLocalEnvironment());
+    EXPECT_EQ(surfacePropertyLocalEnvironment, sp.surfacePropertyLocalEnvironment().get());
+
+    surfacePropertyLocalEnvironment.resetSurfacePropertySurroundingSurfaces();
+    EXPECT_FALSE(surfacePropertyLocalEnvironment.surfacePropertySurroundingSurfaces());
+  }
+
+  // Ground Surfaces Object Name: Optional Object
+  {
+    EXPECT_FALSE(surfacePropertyLocalEnvironment.surfacePropertyGroundSurfaces());
+    SurfacePropertyGroundSurfaces sp(m);
+    EXPECT_FALSE(sp.surfacePropertyLocalEnvironment());
+
+    EXPECT_TRUE(surfacePropertyLocalEnvironment.setSurfacePropertyGroundSurfaces(sp));
+    ASSERT_TRUE(surfacePropertyLocalEnvironment.surfacePropertyGroundSurfaces());
+    EXPECT_EQ(sp, surfacePropertyLocalEnvironment.surfacePropertyGroundSurfaces().get());
+
+    ASSERT_TRUE(sp.surfacePropertyLocalEnvironment());
+    EXPECT_EQ(surfacePropertyLocalEnvironment, sp.surfacePropertyLocalEnvironment().get());
+
+    surfacePropertyLocalEnvironment.resetSurfacePropertyGroundSurfaces();
+    EXPECT_FALSE(surfacePropertyLocalEnvironment.surfacePropertyGroundSurfaces());
+  }
 
   // It should also accept a SubSurface
   SubSurface subSurface(points2, m);