Repository: NREL/OpenStudio (language: python)

Issue:
Wrap SurfaceProperty:SurroundingSurfaces for Modeling Thermal Interactions between Buildings in an Urban Context
Enhancement Request
--------------
Wrap feature from this pull request merged into EnergyPlus 8.8 so it can be used through an OpenStudio measure.
https://github.com/NREL/EnergyPlus/pull/6227/files

## Detailed Description
See this paper for detail of functionality
https://escholarship.org/content/qt5261v2kp/qt5261v2kp_noSplash_797b20ea4b4a8652bf208ffabc719425.pdf?t=qaomhp

## Possible Implementation
One or more objects need to be added, I'll see if I can identify those objects.



Discussion / hints:
Link to markdown design doc
https://github.com/NREL/EnergyPlus/blob/96be0affe1704093bbf766f5e051c88819a7bfe1/design/FY2017/NFP-Improving%20Building%20Energy%20Simulation%20in%20an%20Urban%20Context.md

(1) External Shading Fraction Schedule for external shading calculation
- Modify existing `ShadowCalculation` objet

(2) Surrounding surface properties for long-wave radiation calculation between buildings
- A new EnergyPlus object `SurfaceProperty:SurroundingSurfaces`

(3) Local Outdoor Air Node for co-simulation with urban micro-climate
- Modify existing `OutdoorAir:Node`

Looking through this, I am primarily interested in item 2 related to  `SurfaceProperty:SurroundingSurfaces`, although the other objects also seem useful, but wouldn't have to be added to OpenStudio at same time as item 2

Here is link to documentation for that object
https://bigladdersoftware.com/epx/docs/9-6/input-output-reference/group-advanced-surface-concepts.html#surfacePropertysurroundingSurfaces

Fix patch:
diff --git a/resources/energyplus/ProposedEnergy+.idd b/resources/energyplus/ProposedEnergy+.idd
index 4bfbc99ff49..32a588453d3 100644
--- a/resources/energyplus/ProposedEnergy+.idd
+++ b/resources/energyplus/ProposedEnergy+.idd
@@ -9649,7 +9649,7 @@ SurfaceProperty:LocalEnvironment,
        \reference SurfaceLocalEnvironmentNames
    A2, \field Exterior Surface Name
        \type object-list
-       \object-list SurfaceNames
+       \object-list AllHeatTranSurfNames
        \note Enter the name of an exterior surface object
    A3, \field External Shading Fraction Schedule Name
        \type object-list
@@ -9692,7 +9692,6 @@ SurfaceProperty:SurroundingSurfaces,
    N1, \field Sky View Factor
        \minimum 0.0
        \maximum 1.0
-       \default 0.5
        \note optional
    A2, \field Sky Temperature Schedule Name
        \type object-list
@@ -9702,7 +9701,6 @@ SurfaceProperty:SurroundingSurfaces,
    N2, \field Ground View Factor
        \minimum 0.0
        \maximum 1.0
-       \default 0.5
        \note optional
    A3, \field Ground Temperature Schedule Name
        \type object-list
diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd
index 423e26a7ea5..ecbb75e1868 100644
--- a/resources/model/OpenStudio.idd
+++ b/resources/model/OpenStudio.idd
@@ -6503,6 +6503,84 @@ OS:ZoneProperty:UserViewFactors:BySurfaceName,
        \type real
        \maximum 1.0
 
+OS:SurfaceProperty:SurroundingSurfaces,
+       \min-fields 9
+       \memo This object defines a list of surrounding surfaces for an exterior surface.
+       \memo The sum of all defined view factors should not exceed 1.0.
+       \memo If only sky view is defined in this object, the ground view factor to this surface will be 1.0 subtracted with the ground view factor and all other defined surface view factors.
+       \memo If only ground view is defined in this object, the sky view factor to this surface will be 1.0 subtracted with the sky view factor and all other defined surface view factors.
+       \memo If neither of the sky and ground view factors are explicitly declared here, the sum of the sky and ground view factor would be 1.0 subtracted with all other defined surface view factors and the proportion will be set as the same with the global setting
+       \extensible:3
+   A1, \field Handle
+       \type handle
+       \required-field
+   A2, \field Name
+       \required-field
+       \type alpha
+       \reference SurroundingSurfacesNames
+   N1, \field Sky View Factor
+       \minimum 0.0
+       \maximum 1.0
+       \autocalculatable
+   A3, \field Sky Temperature Schedule Name
+       \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
+   N2, \field Ground View Factor
+       \minimum 0.0
+       \maximum 1.0
+       \autocalculatable
+       \note optional
+   A4, \field Ground Temperature Schedule Name
+       \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 ground temperature is used
+   A5, \field Surrounding Surface 1 Name
+       \begin-extensible
+       \required-field
+       \type alpha
+       \note This is the name of the surrounding surface, NOT an actual surface in your model
+   N3, \field Surrounding Surface 1 View Factor
+       \required-field
+       \minimum 0.0
+       \maximum 1.0
+   A6; \field Surrounding Surface 1 Temperature Schedule Name
+       \required-field
+       \type object-list
+       \object-list ScheduleNames
+       \note Schedule values are real numbers, -100.0 to 100.0, units C
+
+OS:SurfaceProperty:LocalEnvironment,
+       \min-fields 4
+       \memo This object defines the local environment properties of an exterior surface.
+       \memo One or more environment properties have to be defined and linked to the exterior surface.
+   A1, \field Handle
+       \type handle
+       \required-field
+   A2, \field Name
+       \required-field
+       \type alpha
+       \reference SurfaceLocalEnvironmentNames
+   A3, \field Exterior Surface Name
+       \required-field
+       \type object-list
+       \object-list AllHeatTranSurfNames
+       \note Enter the name of an exterior surface object
+   A4, \field External Shading Fraction Schedule Name
+       \type object-list
+       \object-list ScheduleNames
+       \note Enter the name of a Schedule object
+   A5, \field Surrounding Surfaces Object Name
+       \type object-list
+       \object-list SurroundingSurfacesNames
+       \note Enter the name of a SurfaceProperty:SurroundingSurfaces object
+   A6; \field Outdoor Air Node Name
+       \type object-list
+       \object-list OutdoorAirNodeNames
+       \note Enter the name of an OutdoorAir:Node object
+
 \group OpenStudio Space Loads
 
 OS:InternalMass,
diff --git a/src/energyplus/CMakeLists.txt b/src/energyplus/CMakeLists.txt
index d2cdd855490..eb3822cc8ae 100644
--- a/src/energyplus/CMakeLists.txt
+++ b/src/energyplus/CMakeLists.txt
@@ -375,8 +375,10 @@ set(${target_name}_src
   ForwardTranslator/ForwardTranslateSurfacePropertyConvectionCoefficients.cpp
   ForwardTranslator/ForwardTranslateSurfacePropertyConvectionCoefficientsMultipleSurface.cpp
   ForwardTranslator/ForwardTranslateSurfacePropertyExposedFoundationPerimeter.cpp
+  ForwardTranslator/ForwardTranslateSurfacePropertyLocalEnvironment.cpp
   ForwardTranslator/ForwardTranslateSurfacePropertyOtherSideCoefficients.cpp
   ForwardTranslator/ForwardTranslateSurfacePropertyOtherSideConditionsModel.cpp
+  ForwardTranslator/ForwardTranslateSurfacePropertySurroundingSurfaces.cpp
   ForwardTranslator/ForwardTranslateSwimmingPoolIndoor.cpp
   ForwardTranslator/ForwardTranslateTableMultiVariableLookup.cpp
   ForwardTranslator/ForwardTranslateTemperingValve.cpp
@@ -568,6 +570,8 @@ set(${target_name}_src
   ReverseTranslator/ReverseTranslateSurfaceConvectionAlgorithmInside.cpp
   ReverseTranslator/ReverseTranslateSurfaceConvectionAlgorithmOutside.cpp
   ReverseTranslator/ReverseTranslateSurfacePropertyExposedFoundationPerimeter.cpp
+  ReverseTranslator/ReverseTranslateSurfacePropertyLocalEnvironment.cpp
+  ReverseTranslator/ReverseTranslateSurfacePropertySurroundingSurfaces.cpp
   ReverseTranslator/ReverseTranslateSwimmingPoolIndoor.cpp
   ReverseTranslator/ReverseTranslateThermostatSetpointDualSetpoint.cpp
   ReverseTranslator/ReverseTranslateTimestep.cpp
@@ -728,6 +732,8 @@ set(${target_name}_test_src
   Test/Surface_GTest.cpp
   Test/SurfaceControlMovableInsulation_GTest.cpp
   Test/SurfacePropertyConvectionCoefficients_GTest.cpp
+  Test/SurfacePropertyLocalEnvironment_GTest.cpp
+  Test/SurfacePropertySurroundingSurfaces_GTest.cpp
   Test/SwimmingPoolIndoor_GTest.cpp
   Test/TableMultiVariableLookup_GTest.cpp
   Test/ThermalStorageChilledWaterStratified_GTest.cpp
diff --git a/src/energyplus/ForwardTranslator.cpp b/src/energyplus/ForwardTranslator.cpp
index 79ef863dd11..1eb0e66661b 100644
--- a/src/energyplus/ForwardTranslator.cpp
+++ b/src/energyplus/ForwardTranslator.cpp
@@ -2824,6 +2824,11 @@ namespace energyplus {
         retVal = translateSurfacePropertyConvectionCoefficientsMultipleSurface(obj);
         break;
       }
+      case openstudio::IddObjectType::OS_SurfaceProperty_LocalEnvironment: {
+        model::SurfacePropertyLocalEnvironment obj = modelObject.cast<SurfacePropertyLocalEnvironment>();
+        retVal = translateSurfacePropertyLocalEnvironment(obj);
+        break;
+      }
       case openstudio::IddObjectType::OS_SurfaceProperty_ExposedFoundationPerimeter: {
         model::SurfacePropertyExposedFoundationPerimeter obj = modelObject.cast<SurfacePropertyExposedFoundationPerimeter>();
         retVal = translateSurfacePropertyExposedFoundationPerimeter(obj);
@@ -2839,6 +2844,11 @@ namespace energyplus {
         retVal = translateSurfacePropertyOtherSideConditionsModel(obj);
         break;
       }
+      case openstudio::IddObjectType::OS_SurfaceProperty_SurroundingSurfaces: {
+        model::SurfacePropertySurroundingSurfaces obj = modelObject.cast<SurfacePropertySurroundingSurfaces>();
+        retVal = translateSurfacePropertySurroundingSurfaces(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 e78aa47b2e3..82da2877ca7 100644
--- a/src/energyplus/ForwardTranslator.hpp
+++ b/src/energyplus/ForwardTranslator.hpp
@@ -432,9 +432,11 @@ namespace model {
   class SurfaceControlMovableInsulation;
   class SurfacePropertyConvectionCoefficients;
   class SurfacePropertyConvectionCoefficientsMultipleSurface;
+  class SurfacePropertyLocalEnvironment;
   class SurfacePropertyExposedFoundationPerimeter;
   class SurfacePropertyOtherSideCoefficients;
   class SurfacePropertyOtherSideConditionsModel;
+  class SurfacePropertySurroundingSurfaces;
   class SwimmingPoolIndoor;
   class TableMultiVariableLookup;
   class TemperingValve;
@@ -1392,6 +1394,10 @@ namespace energyplus {
 
     boost::optional<IdfObject> translateSurfacePropertyOtherSideConditionsModel(model::SurfacePropertyOtherSideConditionsModel& modelObject);
 
+    boost::optional<IdfObject> translateSurfacePropertyLocalEnvironment(model::SurfacePropertyLocalEnvironment& modelObject);
+
+    boost::optional<IdfObject> translateSurfacePropertySurroundingSurfaces(model::SurfacePropertySurroundingSurfaces& modelObject);
+
     boost::optional<IdfObject> translateSwimmingPoolIndoor(model::SwimmingPoolIndoor& modelObject);
 
     boost::optional<IdfObject> translateTableMultiVariableLookup(model::TableMultiVariableLookup& modelObject);
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp
index ba60fd10d8f..beb9a389b43 100644
--- a/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp
@@ -41,6 +41,7 @@
 #include "../../model/SurfacePropertyOtherSideCoefficients.hpp"
 #include "../../model/SurfacePropertyOtherSideConditionsModel.hpp"
 #include "../../model/SurfacePropertyConvectionCoefficients.hpp"
+#include "../../model/SurfacePropertyLocalEnvironment.hpp"
 
 #include "../../utilities/idf/IdfExtensibleGroup.hpp"
 
@@ -129,6 +130,10 @@ namespace energyplus {
       translateAndMapModelObject(_sCoefs.get());
     }
 
+    if (boost::optional<SurfacePropertyLocalEnvironment> localEnv_ = modelObject.surfacePropertyLocalEnvironment()) {
+      translateAndMapModelObject(localEnv_.get());
+    }
+
     boost::optional<double> viewFactortoGround = modelObject.viewFactortoGround();
     if (viewFactortoGround) {
       idfObject.setDouble(FenestrationSurface_DetailedFields::ViewFactortoGround, *viewFactortoGround);
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateSurface.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateSurface.cpp
index 681dfa8736c..843f8917f9e 100644
--- a/src/energyplus/ForwardTranslator/ForwardTranslateSurface.cpp
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateSurface.cpp
@@ -45,6 +45,7 @@
 #include "../../model/SurfacePropertyOtherSideCoefficients.hpp"
 #include "../../model/SurfacePropertyOtherSideConditionsModel.hpp"
 #include "../../model/SurfacePropertyConvectionCoefficients.hpp"
+#include "../../model/SurfacePropertyLocalEnvironment.hpp"
 #include "../../model/PlanarSurface.hpp"
 #include "../../model/FoundationKiva.hpp"
 #include "../../model/FoundationKiva_Impl.hpp"
@@ -211,6 +212,10 @@ namespace energyplus {
       translateAndMapModelObject(_sCoefs.get());
     }
 
+    if (boost::optional<SurfacePropertyLocalEnvironment> localEnv_ = modelObject.surfacePropertyLocalEnvironment()) {
+      translateAndMapModelObject(localEnv_.get());
+    }
+
     if (boost::optional<SurfacePropertyExposedFoundationPerimeter> _sProps = modelObject.surfacePropertyExposedFoundationPerimeter()) {
       translateAndMapModelObject(_sProps.get());
     } else {
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertyLocalEnvironment.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertyLocalEnvironment.cpp
new file mode 100644
index 00000000000..9ef79f54c47
--- /dev/null
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertyLocalEnvironment.cpp
@@ -0,0 +1,89 @@
+/***********************************************************************************************************************
+*  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/SurfacePropertyLocalEnvironment.hpp"
+
+#include "../../model/PlanarSurface.hpp"
+
+#include "../../model/SurfacePropertySurroundingSurfaces.hpp"
+#include "../../model/SurfacePropertySurroundingSurfaces_Impl.hpp"
+
+//#include "../../model/OutdoorAirNode.hpp"
+//#include "../../model/OutdoorAirNode_Impl.hpp"
+
+#include <utilities/idd/SurfaceProperty_LocalEnvironment_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::model;
+
+namespace openstudio {
+
+namespace energyplus {
+
+  boost::optional<IdfObject> ForwardTranslator::translateSurfacePropertyLocalEnvironment(model::SurfacePropertyLocalEnvironment& modelObject) {
+
+    // Instantiate an IdfObject of the class to store the values,
+    IdfObject idfObject = createRegisterAndNameIdfObject(openstudio::IddObjectType::SurfaceProperty_LocalEnvironment, modelObject);
+
+    // Exterior Surface Name: Optional Object
+    if (boost::optional<PlanarSurface> _exteriorSurface = modelObject.exteriorSurface()) {
+      if (boost::optional<IdfObject> _owo = translateAndMapModelObject(_exteriorSurface.get())) {
+        idfObject.setString(SurfaceProperty_LocalEnvironmentFields::ExteriorSurfaceName, _owo->nameString());
+      }
+    }
+
+    // External Shading Fraction Schedule Name: Optional Object
+    if (boost::optional<Schedule> _externalShadingFractionSchedule = modelObject.externalShadingFractionSchedule()) {
+      if (boost::optional<IdfObject> _owo = translateAndMapModelObject(_externalShadingFractionSchedule.get())) {
+        idfObject.setString(SurfaceProperty_LocalEnvironmentFields::ExternalShadingFractionScheduleName, _owo->nameString());
+      }
+    }
+
+    // Surrounding Surfaces Object Name: Optional Object
+    if (boost::optional<SurfacePropertySurroundingSurfaces> sp_ = modelObject.surfacePropertySurroundingSurfaces()) {
+      if (boost::optional<IdfObject> _owo = translateAndMapModelObject(sp_.get())) {
+        idfObject.setString(SurfaceProperty_LocalEnvironmentFields::SurroundingSurfacesObjectName, _owo->nameString());
+      }
+    }
+
+    // Outdoor Air Node Name: Optional Object
+    // if (boost::optional<OutdoorAirNode> _outdoorAirNode = modelObject.outdoorAirNode()) {
+    //   if (boost::optional<IdfObject> _owo = translateAndMapModelObject(_outdoorAirNode.get())) {
+    //     idfObject.setString(SurfaceProperty_LocalEnvironmentFields::OutdoorAirNodeName, _owo->nameString());
+    //   }
+    // }
+
+    return idfObject;
+  }  // End of translate function
+
+}  // end namespace energyplus
+}  // end namespace openstudio
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertySurroundingSurfaces.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertySurroundingSurfaces.cpp
new file mode 100644
index 00000000000..65a9685402b
--- /dev/null
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateSurfacePropertySurroundingSurfaces.cpp
@@ -0,0 +1,96 @@
+/***********************************************************************************************************************
+*  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/SurfacePropertySurroundingSurfaces.hpp"
+
+#include "../../model/Schedule.hpp"
+
+#include "../../utilities/idf/IdfExtensibleGroup.hpp"
+
+#include <utilities/idd/SurfaceProperty_SurroundingSurfaces_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::model;
+
+namespace openstudio {
+
+namespace energyplus {
+
+  boost::optional<IdfObject> ForwardTranslator::translateSurfacePropertySurroundingSurfaces(model::SurfacePropertySurroundingSurfaces& modelObject) {
+
+    if (modelObject.numberofSurroundingSurfaceGroups() == 0) {
+      return boost::none;
+    }
+
+    // Instantiate an IdfObject of the class to store the values,
+    IdfObject idfObject = createRegisterAndNameIdfObject(openstudio::IddObjectType::SurfaceProperty_SurroundingSurfaces, modelObject);
+
+    // Sky View Factor: Optional Double
+    if (boost::optional<double> skyViewFactor_ = modelObject.skyViewFactor()) {
+      idfObject.setDouble(SurfaceProperty_SurroundingSurfacesFields::SkyViewFactor, skyViewFactor_.get());
+    }
+
+    // Sky Temperature Schedule Name: Optional Object
+    if (boost::optional<Schedule> _skyTemperatureSchedule = modelObject.skyTemperatureSchedule()) {
+      if (boost::optional<IdfObject> _owo = translateAndMapModelObject(_skyTemperatureSchedule.get())) {
+        idfObject.setString(SurfaceProperty_SurroundingSurfacesFields::SkyTemperatureScheduleName, _owo->nameString());
+      }
+    }
+
+    // Ground View Factor: Optional Double
+    if (boost::optional<double> groundViewFactor_ = modelObject.groundViewFactor()) {
+      idfObject.setDouble(SurfaceProperty_SurroundingSurfacesFields::GroundViewFactor, groundViewFactor_.get());
+    }
+
+    // Ground Temperature Schedule Name: Optional Object
+    if (boost::optional<Schedule> _groundTemperatureSchedule = modelObject.groundTemperatureSchedule()) {
+      if (boost::optional<IdfObject> _owo = translateAndMapModelObject(_groundTemperatureSchedule.get())) {
+        idfObject.setString(SurfaceProperty_SurroundingSurfacesFields::GroundTemperatureScheduleName, _owo->nameString());
+      }
+    }
+
+    for (const auto& group : modelObject.surroundingSurfaceGroups()) {
+
+      IdfExtensibleGroup eg = idfObject.pushExtensibleGroup();
+      eg.setString(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceName, group.surroundingSurfaceName());
+      eg.setDouble(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceViewFactor, group.viewFactor());
+      auto sch = group.temperatureSchedule();
+      if (boost::optional<IdfObject> _owo = translateAndMapModelObject(sch)) {
+        eg.setString(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceTemperatureScheduleName, _owo->nameString());
+      }  // TODO: handle failure?
+    }
+
+    return idfObject;
+  }  // End of translate function
+
+}  // end namespace energyplus
+}  // end namespace openstudio
diff --git a/src/energyplus/ReverseTranslator.cpp b/src/energyplus/ReverseTranslator.cpp
index 8d5289c1fef..1c03ffc8221 100644
--- a/src/energyplus/ReverseTranslator.cpp
+++ b/src/energyplus/ReverseTranslator.cpp
@@ -881,6 +881,14 @@ namespace energyplus {
       case openstudio::IddObjectType::SurfaceProperty_ExposedFoundationPerimeter: {
         modelObject = translateSurfacePropertyExposedFoundationPerimeter(workspaceObject);
         break;
+      }
+      case openstudio::IddObjectType::SurfaceProperty_LocalEnvironment: {
+        modelObject = translateSurfacePropertyLocalEnvironment(workspaceObject);
+        break;
+      }
+      case openstudio::IddObjectType::SurfaceProperty_SurroundingSurfaces: {
+        modelObject = translateSurfacePropertySurroundingSurfaces(workspaceObject);
+        break;
       }
         //case openstudio::IddObjectType::SwimmingPool_Indoor :
         //{
diff --git a/src/energyplus/ReverseTranslator.hpp b/src/energyplus/ReverseTranslator.hpp
index 0d43bbca13d..c88884b6f32 100644
--- a/src/energyplus/ReverseTranslator.hpp
+++ b/src/energyplus/ReverseTranslator.hpp
@@ -349,6 +349,10 @@ namespace energyplus {
 
     boost::optional<model::ModelObject> translateSurfacePropertyExposedFoundationPerimeter(const WorkspaceObject& workspaceObject);
 
+    boost::optional<model::ModelObject> translateSurfacePropertyLocalEnvironment(const WorkspaceObject& workspaceObject);
+
+    boost::optional<model::ModelObject> translateSurfacePropertySurroundingSurfaces(const WorkspaceObject& workspaceObject);
+
     boost::optional<model::ModelObject> translateSwimmingPoolIndoor(const WorkspaceObject& workspaceObject);
 
     boost::optional<model::ModelObject> translateThermostatSetpointDualSetpoint(const WorkspaceObject& workspaceObject);
diff --git a/src/energyplus/ReverseTranslator/ReverseTranslateSurfacePropertyLocalEnvironment.cpp b/src/energyplus/ReverseTranslator/ReverseTranslateSurfacePropertyLocalEnvironment.cpp
new file mode 100644
index 00000000000..f3013628d86
--- /dev/null
+++ b/src/energyplus/ReverseTranslator/ReverseTranslateSurfacePropertyLocalEnvironment.cpp
@@ -0,0 +1,126 @@
+/***********************************************************************************************************************
+*  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/SurfacePropertyLocalEnvironment.hpp"
+
+#include "../../model/Surface.hpp"
+#include "../../model/Surface_Impl.hpp"
+#include "../../model/SubSurface.hpp"
+#include "../../model/SubSurface_Impl.hpp"
+
+#include "../../model/Schedule.hpp"
+#include "../../model/Schedule_Impl.hpp"
+
+#include "../../model/SurfacePropertySurroundingSurfaces.hpp"
+#include "../../model/SurfacePropertySurroundingSurfaces_Impl.hpp"
+
+// #include "../../model/OutdoorAirNode.hpp"
+// #include "../../model/OutdoorAirNode_Impl.hpp"
+
+#include <utilities/idd/SurfaceProperty_LocalEnvironment_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::model;
+
+namespace openstudio {
+
+namespace energyplus {
+
+  boost::optional<ModelObject> ReverseTranslator::translateSurfacePropertyLocalEnvironment(const WorkspaceObject& workspaceObject) {
+    boost::optional<WorkspaceObject> wo_;
+    boost::optional<ModelObject> mo_;
+
+    boost::optional<ModelObject> mo_planarSurface;
+
+    boost::optional<SurfacePropertyLocalEnvironment> localEnv_;
+    // Exterior Surface Name: Optional Object
+    if ((wo_ = workspaceObject.getTarget(SurfaceProperty_LocalEnvironmentFields::ExteriorSurfaceName))) {
+      if ((mo_ = translateAndMapWorkspaceObject(wo_.get()))) {
+        if (boost::optional<Surface> _exteriorSurface = mo_->optionalCast<Surface>()) {
+          localEnv_ = openstudio::model::SurfacePropertyLocalEnvironment(_exteriorSurface.get());
+        } else if (boost::optional<SubSurface> _exteriorSurface = mo_->optionalCast<SubSurface>()) {
+          localEnv_ = openstudio::model::SurfacePropertyLocalEnvironment(_exteriorSurface.get());
+        } else {
+          LOG(Error, workspaceObject.briefDescription()
+                       << " has a wrong type for 'Exterior Surface Name', expected Surface or SubSurface, got " << mo_->briefDescription());
+          return boost::none;
+        }
+      } else {
+        LOG(Error, workspaceObject.briefDescription() << " has a wrong type for 'Exterior Surface Name'");
+        return boost::none;
+      }
+    } else {
+      LOG(Error, workspaceObject.briefDescription() << " does not have an 'Exterior Surface Name' attached.");
+      return boost::none;
+    }
+
+    SurfacePropertyLocalEnvironment modelObject = localEnv_.get();
+
+    // Name
+    modelObject.setName(workspaceObject.nameString());
+
+    // External Shading Fraction Schedule Name: Optional Object
+    if ((wo_ = workspaceObject.getTarget(SurfaceProperty_LocalEnvironmentFields::ExternalShadingFractionScheduleName))) {
+      if ((mo_ = translateAndMapWorkspaceObject(wo_.get()))) {
+        if (auto externalShadingFractionSchedule_ = mo_->optionalCast<Schedule>()) {
+          modelObject.setExternalShadingFractionSchedule(externalShadingFractionSchedule_.get());
+        } else {
+          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'External Shading Fraction Schedule Name'");
+        }
+      }
+    }
+    // Surrounding Surfaces Object Name: Optional Object
+    if ((wo_ = workspaceObject.getTarget(SurfaceProperty_LocalEnvironmentFields::SurroundingSurfacesObjectName))) {
+      if ((mo_ = translateAndMapWorkspaceObject(wo_.get()))) {
+        if (auto sp_ = mo_->optionalCast<SurfacePropertySurroundingSurfaces>()) {
+          modelObject.setSurfacePropertySurroundingSurfaces(sp_.get());
+        } else {
+          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'Surrounding Surfaces Object Name'");
+        }
+      }
+    }
+
+    // Outdoor Air Node Name: Optional Object
+    // if ((wo_ = workspaceObject.getTarget(SurfaceProperty_LocalEnvironmentFields::OutdoorAirNodeName))) {
+    //   if ((mo_ = translateAndMapWorkspaceObject(wo_.get()))) {
+    //     if (boost::optional<OutdoorAirNode> _outdoorAirNode = mo_->optionalCast<OutdoorAirNode>()) {
+    //       modelObject.setOutdoorAirNode(_outdoorAirNode.get());
+    //     } else {
+    //       LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'Outdoor Air Node Name'");
+    //     }
+    //   }
+    // }
+
+    return modelObject;
+  }  // End of translate function
+
+}  // end namespace energyplus
+}  // end namespace openstudio
diff --git a/src/energyplus/ReverseTranslator/ReverseTranslateSurfacePropertySurroundingSurfaces.cpp b/src/energyplus/ReverseTranslator/ReverseTranslateSurfacePropertySurroundingSurfaces.cpp
new file mode 100644
index 00000000000..d1e028f50c6
--- /dev/null
+++ b/src/energyplus/ReverseTranslator/ReverseTranslateSurfacePropertySurroundingSurfaces.cpp
@@ -0,0 +1,121 @@
+/***********************************************************************************************************************
+*  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/SurfacePropertySurroundingSurfaces.hpp"
+
+#include "../../model/Schedule.hpp"
+#include "../../model/Schedule_Impl.hpp"
+
+#include "../../utilities/idf/IdfExtensibleGroup.hpp"
+#include "../../utilities/idf/WorkspaceExtensibleGroup.hpp"
+
+#include <utilities/idd/SurfaceProperty_SurroundingSurfaces_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::model;
+
+namespace openstudio {
+
+namespace energyplus {
+
+  boost::optional<ModelObject> ReverseTranslator::translateSurfacePropertySurroundingSurfaces(const WorkspaceObject& workspaceObject) {
+    boost::optional<WorkspaceObject> wo_;
+    boost::optional<ModelObject> mo_;
+
+    openstudio::model::SurfacePropertySurroundingSurfaces modelObject(m_model);
+
+    // Name
+    modelObject.setName(workspaceObject.nameString());
+
+    // Sky View Factor: Optional Double
+    if (boost::optional<double> skyViewFactor_ = workspaceObject.getDouble(SurfaceProperty_SurroundingSurfacesFields::SkyViewFactor)) {
+      modelObject.setSkyViewFactor(skyViewFactor_.get());
+    }
+
+    // Sky Temperature Schedule Name: Optional Object
+    if ((wo_ = workspaceObject.getTarget(SurfaceProperty_SurroundingSurfacesFields::SkyTemperatureScheduleName))) {
+      if ((mo_ = translateAndMapWorkspaceObject(wo_.get()))) {
+        if (auto skyTemperatureSchedule_ = mo_->optionalCast<Schedule>()) {
+          modelObject.setSkyTemperatureSchedule(skyTemperatureSchedule_.get());
+        } else {
+          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'Sky Temperature Schedule Name'");
+        }
+      }
+    }
+    // Ground View Factor: Optional Double
+    if (boost::optional<double> groundViewFactor_ = workspaceObject.getDouble(SurfaceProperty_SurroundingSurfacesFields::GroundViewFactor)) {
+      modelObject.setGroundViewFactor(groundViewFactor_.get());
+    }
+
+    // Ground Temperature Schedule Name: Optional Object
+    if ((wo_ = workspaceObject.getTarget(SurfaceProperty_SurroundingSurfacesFields::GroundTemperatureScheduleName))) {
+      if ((mo_ = translateAndMapWorkspaceObject(wo_.get()))) {
+        if (boost::optional<Schedule> _groundTemperatureSchedule = mo_->optionalCast<Schedule>()) {
+          modelObject.setGroundTemperatureSchedule(_groundTemperatureSchedule.get());
+        } else {
+          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'Ground Temperature Schedule Name'");
+        }
+      }
+    }
+
+    // Extensible groups
+    for (const IdfExtensibleGroup& eg : workspaceObject.extensibleGroups()) {
+      auto weg = eg.cast<WorkspaceExtensibleGroup>();
+
+      auto surroundingSurfaceName = weg.getString(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceName).get();
+      if (surroundingSurfaceName.empty()) {
+        LOG(Warn, "Extensible group " << eg.groupIndex() << "(0-indexed) has an empty Surrounding Surface Name field, skipping group");
+      }
+
+      // This has a default of 0, so roll with it
+      auto viewFactor = weg.getDouble(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceViewFactor).get();
+
+      if ((wo_ = weg.getTarget(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceTemperatureScheduleName))) {
+        if ((mo_ = translateAndMapWorkspaceObject(wo_.get()))) {
+          if (boost::optional<Schedule> tempSch_ = mo_->optionalCast<Schedule>()) {
+            modelObject.addSurroundingSurfaceGroup(surroundingSurfaceName, viewFactor, tempSch_.get());
+          } 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());
+        }
+      } else {
+        LOG(Warn, "Extensible group " << eg.groupIndex() << "(0-indexed) is missed the Temperature Schedule");
+      }
+    }
+
+    return modelObject;
+  }  // End of translate function
+
+}  // end namespace energyplus
+}  // end namespace openstudio
diff --git a/src/energyplus/Test/SurfacePropertyLocalEnvironment_GTest.cpp b/src/energyplus/Test/SurfacePropertyLocalEnvironment_GTest.cpp
new file mode 100644
index 00000000000..7bdacea8633
--- /dev/null
+++ b/src/energyplus/Test/SurfacePropertyLocalEnvironment_GTest.cpp
@@ -0,0 +1,252 @@
+/***********************************************************************************************************************
+*  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/SurfacePropertyLocalEnvironment_Impl.hpp"
+#include "../../model/SurfacePropertySurroundingSurfaces.hpp"
+#include "../../model/SurfacePropertySurroundingSurfaces_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_SurroundingSurfaces_FieldEnums.hxx>
+#include <utilities/idd/BuildingSurface_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_SurfacePropertyLocalEnvironment) {
+
+  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, 1, 0},
+    {0, 0, 0},
+    {1, 0, 0},
+    {1, 1, 0},
+  };
+
+  SubSurface subSurface(ssPoints, m);
+  subSurface.setSurface(surface);
+  subSurface.assignDefaultSubSurfaceType();
+
+  SurfacePropertyLocalEnvironment localEnv(surface);
+  localEnv.setName(surface.nameString() + " LocalEnv");
+  EXPECT_EQ(surface, localEnv.exteriorSurface());
+  ASSERT_TRUE(localEnv.exteriorSurfaceAsSurface());
+  EXPECT_EQ(surface, localEnv.exteriorSurfaceAsSurface().get());
+
+  ScheduleConstant shadingSch(m);
+  shadingSch.setName("External Shading Fraction Schedule");
+  shadingSch.setValue(0.5);
+  EXPECT_TRUE(localEnv.setExternalShadingFractionSchedule(shadingSch));
+  ASSERT_TRUE(localEnv.externalShadingFractionSchedule());
+  EXPECT_EQ(shadingSch, localEnv.externalShadingFractionSchedule().get());
+
+  SurfacePropertySurroundingSurfaces sp(m);
+  sp.setName("SurfaceProperty Surrounding Surfaces");
+
+  EXPECT_TRUE(localEnv.setSurfacePropertySurroundingSurfaces(sp));
+  ASSERT_TRUE(localEnv.surfacePropertySurroundingSurfaces());
+  EXPECT_EQ(sp, localEnv.surfacePropertySurroundingSurfaces().get());
+  ScheduleConstant tempSch(m);
+  tempSch.setName("External Surface Temperature Schedule");
+  tempSch.setValue(23.5);
+  EXPECT_TRUE(sp.addSurroundingSurfaceGroup("External Surface 1", 0.4, tempSch));
+  EXPECT_EQ(1, sp.numberofSurroundingSurfaceGroups());
+
+  ForwardTranslator ft;
+
+  {
+    // Assigned to a Surface
+    Workspace w = ft.translateModel(m);
+
+    std::vector<WorkspaceObject> idfObjs = w.getObjectsByType(IddObjectType::SurfaceProperty_LocalEnvironment);
+    ASSERT_EQ(1, idfObjs.size());
+    auto& wo_localEnv = idfObjs[0];
+    EXPECT_EQ(localEnv.nameString(), wo_localEnv.nameString());
+
+    auto wo_extSf_ = wo_localEnv.getTarget(SurfaceProperty_LocalEnvironmentFields::ExteriorSurfaceName);
+    ASSERT_TRUE(wo_extSf_);
+    EXPECT_EQ(wo_extSf_->iddObject().type(), IddObjectType::BuildingSurface_Detailed);
+
+    EXPECT_EQ(shadingSch.nameString(), wo_localEnv.getString(SurfaceProperty_LocalEnvironmentFields::ExternalShadingFractionScheduleName).get());
+
+    EXPECT_EQ(sp.nameString(), wo_localEnv.getString(SurfaceProperty_LocalEnvironmentFields::SurroundingSurfacesObjectName).get());
+    auto wo_sp_ = wo_localEnv.getTarget(SurfaceProperty_LocalEnvironmentFields::SurroundingSurfacesObjectName);
+    ASSERT_TRUE(wo_sp_);
+    EXPECT_EQ(wo_sp_->iddObject().type(), IddObjectType::SurfaceProperty_SurroundingSurfaces);
+  }
+
+  EXPECT_TRUE(localEnv.setExteriorSurface(subSurface));
+  EXPECT_EQ(subSurface, localEnv.exteriorSurface());
+  ASSERT_TRUE(localEnv.exteriorSurfaceAsSubSurface());
+  EXPECT_EQ(subSurface, localEnv.exteriorSurfaceAsSubSurface().get());
+
+  {
+    // Assigned to a SubSurface
+    Workspace w = ft.translateModel(m);
+
+    std::vector<WorkspaceObject> idfObjs = w.getObjectsByType(IddObjectType::SurfaceProperty_LocalEnvironment);
+    ASSERT_EQ(1, idfObjs.size());
+    auto& wo_localEnv = idfObjs[0];
+    EXPECT_EQ(localEnv.nameString(), wo_localEnv.nameString());
+
+    auto wo_extSf_ = wo_localEnv.getTarget(SurfaceProperty_LocalEnvironmentFields::ExteriorSurfaceName);
+    ASSERT_TRUE(wo_extSf_);
+    EXPECT_EQ(wo_extSf_->iddObject().type(), IddObjectType::FenestrationSurface_Detailed);
+
+    EXPECT_EQ(shadingSch.nameString(), wo_localEnv.getString(SurfaceProperty_LocalEnvironmentFields::ExternalShadingFractionScheduleName).get());
+
+    EXPECT_EQ(sp.nameString(), wo_localEnv.getString(SurfaceProperty_LocalEnvironmentFields::SurroundingSurfacesObjectName).get());
+    auto wo_sp_ = wo_localEnv.getTarget(SurfaceProperty_LocalEnvironmentFields::SurroundingSurfacesObjectName);
+    ASSERT_TRUE(wo_sp_);
+    EXPECT_EQ(wo_sp_->iddObject().type(), IddObjectType::SurfaceProperty_SurroundingSurfaces);
+  }
+}
+
+TEST_F(EnergyPlusFixture, ReverseTranslator_SurfacePropertyLocalEnvironment) {
+
+  ReverseTranslator rt;
+
+  Workspace w(StrictnessLevel::None, 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_sp = w.addObject(IdfObject(IddObjectType::SurfaceProperty_SurroundingSurfaces)).get();
+  wo_sp.setName("SfProps");
+
+  EXPECT_TRUE(wo_sp.setDouble(SurfaceProperty_SurroundingSurfacesFields::SkyViewFactor, 0.5));
+  EXPECT_TRUE(wo_sp.setDouble(SurfaceProperty_SurroundingSurfacesFields::GroundViewFactor, 0.2));
+
+  auto w_eg = wo_sp.pushExtensibleGroup().cast<WorkspaceExtensibleGroup>();
+  EXPECT_TRUE(w_eg.setString(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceName, "External Surface 1"));
+  EXPECT_TRUE(w_eg.setDouble(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceViewFactor, 0.25));
+
+  auto tempSch1 = w.addObject(IdfObject(IddObjectType::Schedule_Constant)).get();
+  tempSch1.setName("tempSch1");
+  EXPECT_TRUE(tempSch1.setDouble(Schedule_ConstantFields::HourlyValue, 13.5));
+  EXPECT_TRUE(w_eg.setPointer(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceTemperatureScheduleName, tempSch1.handle()));
+
+  auto wo_localEnv = w.addObject(IdfObject(IddObjectType::SurfaceProperty_LocalEnvironment)).get();
+  wo_localEnv.setName("LocalEnv");
+
+  auto externalShadingSch = w.addObject(IdfObject(IddObjectType::Schedule_Constant)).get();
+  externalShadingSch.setName("externalShadingSch");
+  EXPECT_TRUE(externalShadingSch.setDouble(Schedule_ConstantFields::HourlyValue, 0.5));
+  EXPECT_TRUE(wo_localEnv.setPointer(SurfaceProperty_LocalEnvironmentFields::ExternalShadingFractionScheduleName, externalShadingSch.handle()));
+
+  EXPECT_TRUE(wo_localEnv.setPointer(SurfaceProperty_LocalEnvironmentFields::ExteriorSurfaceName, wo_sf.handle()));
+
+  EXPECT_TRUE(wo_localEnv.setPointer(SurfaceProperty_LocalEnvironmentFields::SurroundingSurfacesObjectName, wo_sp.handle()));
+
+  // RT
+  Model m = rt.translateWorkspace(w);
+
+  ASSERT_EQ(1, m.getConcreteModelObjects<SurfacePropertySurroundingSurfaces>().size());
+  ASSERT_EQ(1, m.getConcreteModelObjects<SurfacePropertyLocalEnvironment>().size());
+  auto surfaces = m.getConcreteModelObjects<Surface>();
+  ASSERT_EQ(1, surfaces.size());
+  auto& surface = surfaces[0];
+
+  ASSERT_TRUE(surface.surfacePropertyLocalEnvironment());
+  auto localEnv = surface.surfacePropertyLocalEnvironment().get();
+  EXPECT_EQ("LocalEnv", localEnv.nameString());
+  EXPECT_EQ(surface, localEnv.exteriorSurface());
+
+  ASSERT_TRUE(localEnv.externalShadingFractionSchedule());
+  EXPECT_EQ("externalShadingSch", localEnv.externalShadingFractionSchedule()->nameString());
+
+  ASSERT_TRUE(localEnv.surfacePropertySurroundingSurfaces());
+  EXPECT_EQ("SfProps", localEnv.surfacePropertySurroundingSurfaces()->nameString());
+}
diff --git a/src/energyplus/Test/SurfacePropertySurroundingSurfaces_GTest.cpp b/src/energyplus/Test/SurfacePropertySurroundingSurfaces_GTest.cpp
new file mode 100644
index 00000000000..f2e7f5fbcf8
--- /dev/null
+++ b/src/energyplus/Test/SurfacePropertySurroundingSurfaces_GTest.cpp
@@ -0,0 +1,322 @@
+/***********************************************************************************************************************
+*  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/SurfacePropertySurroundingSurfaces.hpp"
+#include "../../model/SurfacePropertySurroundingSurfaces_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_SurroundingSurfaces_FieldEnums.hxx>
+#include <utilities/idd/BuildingSurface_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_SurfacePropertySurroundingSurfaces) {
+
+  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);
+
+  SurfacePropertySurroundingSurfaces sp(m);
+  sp.setName("SurfaceProperty Surrounding 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_SurroundingSurfaces).size());
+  }
+
+  SurfacePropertyLocalEnvironment localEnv(surface);
+  localEnv.setName(surface.nameString() + " LocalEnv");
+  EXPECT_TRUE(localEnv.setSurfacePropertySurroundingSurfaces(sp));
+  ASSERT_TRUE(localEnv.surfacePropertySurroundingSurfaces());
+  EXPECT_EQ(sp, localEnv.surfacePropertySurroundingSurfaces().get());
+
+  // Create 5 groups
+  for (int i = 1; i <= 5; ++i) {
+    ScheduleConstant tempSch(m);
+    tempSch.setName("tempSch" + 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.addSurroundingSurfaceGroup(sfName, viewFactor, tempSch));
+    } else {
+      SurroundingSurfaceGroup group(sfName, viewFactor, tempSch);
+      EXPECT_TRUE(sp.addSurroundingSurfaceGroup(group));
+    }
+    EXPECT_EQ(i, sp.numberofSurroundingSurfaceGroups());
+  }
+  EXPECT_EQ(5, sp.numberofSurroundingSurfaceGroups());
+
+  std::vector<SurroundingSurfaceGroup> groups = sp.surroundingSurfaceGroups();
+
+  {
+    // 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_SurroundingSurfaces);
+    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::SurroundingSurfacesObjectName).get());
+    auto& woSp = woSps[0];
+    EXPECT_EQ(sp.nameString(), woSp.nameString());
+
+    EXPECT_TRUE(woSp.isEmpty(SurfaceProperty_SurroundingSurfacesFields::SkyViewFactor));
+    EXPECT_TRUE(woSp.isEmpty(SurfaceProperty_SurroundingSurfacesFields::SkyTemperatureScheduleName));
+    EXPECT_TRUE(woSp.isEmpty(SurfaceProperty_SurroundingSurfacesFields::GroundViewFactor));
+    EXPECT_TRUE(woSp.isEmpty(SurfaceProperty_SurroundingSurfacesFields::GroundTemperatureScheduleName));
+
+    ASSERT_EQ(5, woSp.numExtensibleGroups());
+    for (const auto& idf_eg : woSp.extensibleGroups()) {
+      auto& group = groups[idf_eg.groupIndex()];
+
+      EXPECT_EQ(group.surroundingSurfaceName(), idf_eg.getString(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceName).get());
+      EXPECT_EQ(group.viewFactor(), idf_eg.getDouble(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceViewFactor));
+      EXPECT_EQ(group.temperatureSchedule().nameString(),
+                idf_eg.getString(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceTemperatureScheduleName).get());
+    }
+  }
+
+  EXPECT_TRUE(sp.setSkyViewFactor(0.06));
+  EXPECT_EQ(0.06, sp.skyViewFactor());
+
+  ScheduleConstant skyTempSch(m);
+  skyTempSch.setName("Sky Temperature Schedule");
+  EXPECT_TRUE(sp.setSkyTemperatureSchedule(skyTempSch));
+  EXPECT_EQ(skyTempSch, sp.skyTemperatureSchedule().get());
+
+  EXPECT_TRUE(sp.setGroundViewFactor(0.07));
+  EXPECT_EQ(0.07, sp.groundViewFactor());
+
+  ScheduleConstant groundTempSch(m);
+  groundTempSch.setName("Ground Temperature Schedule");
+  EXPECT_TRUE(sp.setGroundTemperatureSchedule(groundTempSch));
+  EXPECT_EQ(groundTempSch, sp.groundTemperatureSchedule().get());
+
+  {
+    // 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_SurroundingSurfaces);
+    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::SurroundingSurfacesObjectName).get());
+    auto& woSp = woSps[0];
+    EXPECT_EQ(sp.nameString(), woSp.nameString());
+
+    EXPECT_EQ(0.06, woSp.getDouble(SurfaceProperty_SurroundingSurfacesFields::SkyViewFactor).get());
+    EXPECT_EQ("Sky Temperature Schedule", woSp.getString(SurfaceProperty_SurroundingSurfacesFields::SkyTemperatureScheduleName).get());
+    EXPECT_EQ(0.07, woSp.getDouble(SurfaceProperty_SurroundingSurfacesFields::GroundViewFactor).get());
+    EXPECT_EQ("Ground Temperature Schedule", woSp.getString(SurfaceProperty_SurroundingSurfacesFields::GroundTemperatureScheduleName).get());
+
+    ASSERT_EQ(5, woSp.numExtensibleGroups());
+    for (const auto& idf_eg : woSp.extensibleGroups()) {
+      auto& group = groups[idf_eg.groupIndex()];
+
+      EXPECT_EQ(group.surroundingSurfaceName(), idf_eg.getString(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceName).get());
+      EXPECT_EQ(group.viewFactor(), idf_eg.getDouble(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceViewFactor));
+      EXPECT_EQ(group.temperatureSchedule().nameString(),
+                idf_eg.getString(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceTemperatureScheduleName).get());
+    }
+  }
+}
+
+TEST_F(EnergyPlusFixture, ReverseTranslator_SurfacePropertySurroundingSurfaces) {
+
+  ReverseTranslator rt;
+
+  Workspace w(StrictnessLevel::None, 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_sp = w.addObject(IdfObject(IddObjectType::SurfaceProperty_SurroundingSurfaces)).get();
+
+  EXPECT_TRUE(wo_sp.setDouble(SurfaceProperty_SurroundingSurfacesFields::SkyViewFactor, 0.5));
+
+  auto skyTempSch = w.addObject(IdfObject(IddObjectType::Schedule_Constant)).get();
+  skyTempSch.setName("skyTempSch");
+  EXPECT_TRUE(skyTempSch.setDouble(Schedule_ConstantFields::HourlyValue, 23.5));
+  EXPECT_TRUE(wo_sp.setPointer(SurfaceProperty_SurroundingSurfacesFields::SkyTemperatureScheduleName, skyTempSch.handle()));
+
+  EXPECT_TRUE(wo_sp.setDouble(SurfaceProperty_SurroundingSurfacesFields::GroundViewFactor, 0.2));
+
+  auto groundTempSch = w.addObject(IdfObject(IddObjectType::Schedule_Constant)).get();
+  groundTempSch.setName("groundTempSch");
+  EXPECT_TRUE(groundTempSch.setDouble(Schedule_ConstantFields::HourlyValue, 25.5));
+  EXPECT_TRUE(wo_sp.setPointer(SurfaceProperty_SurroundingSurfacesFields::GroundTemperatureScheduleName, groundTempSch.handle()));
+
+  auto tempSch1 = w.addObject(IdfObject(IddObjectType::Schedule_Constant)).get();
+  tempSch1.setName("tempSch1");
+  EXPECT_TRUE(tempSch1.setDouble(Schedule_ConstantFields::HourlyValue, 13.5));
+
+  auto tempSch2 = w.addObject(IdfObject(IddObjectType::Schedule_Constant)).get();
+  tempSch2.setName("tempSch2");
+  EXPECT_TRUE(tempSch2.setDouble(Schedule_ConstantFields::HourlyValue, 33.5));
+
+  struct Group
+  {
+    Group(std::string s, double v, std::string sch) : surroundingSurfaceName(std::move(s)), viewFactor(v), scheduleName(std::move(sch)) {}
+
+    std::string surroundingSurfaceName;
+    double viewFactor;
+    std::string scheduleName;
+  };
+
+  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_SurroundingSurfacesExtensibleFields::SurroundingSurfaceName, sfName));
+
+    double viewFactor = 0.01 * i;
+    EXPECT_TRUE(w_eg.setDouble(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceViewFactor, viewFactor));
+
+    if (i % 2 == 0) {
+      EXPECT_TRUE(w_eg.setPointer(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceTemperatureScheduleName, tempSch1.handle()));
+      check_groups.emplace_back(sfName, viewFactor, tempSch1.nameString());
+    } else {
+      EXPECT_TRUE(w_eg.setPointer(SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceTemperatureScheduleName, tempSch2.handle()));
+      check_groups.emplace_back(sfName, viewFactor, tempSch2.nameString());
+    }
+  }
+
+  Model m = rt.translateWorkspace(w);
+
+  EXPECT_EQ(1, m.getConcreteModelObjects<Surface>().size());
+
+  auto sps = m.getConcreteModelObjects<SurfacePropertySurroundingSurfaces>();
+  ASSERT_EQ(1, sps.size());
+  auto& sp = sps[0];
+
+  ASSERT_TRUE(sp.skyViewFactor());
+  EXPECT_EQ(0.5, sp.skyViewFactor());
+  ASSERT_TRUE(sp.skyTemperatureSchedule());
+  EXPECT_EQ("skyTempSch", sp.skyTemperatureSchedule()->nameString());
+
+  ASSERT_TRUE(sp.groundViewFactor());
+  EXPECT_EQ(0.2, sp.groundViewFactor());
+  ASSERT_TRUE(sp.groundTemperatureSchedule());
+  EXPECT_EQ("groundTempSch", sp.groundTemperatureSchedule()->nameString());
+
+  ASSERT_EQ(5, sp.numberofSurroundingSurfaceGroups());
+  auto groups = sp.surroundingSurfaceGroups();
+  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.surroundingSurfaceName, group.surroundingSurfaceName());
+    EXPECT_EQ(check_group.viewFactor, group.viewFactor());
+    EXPECT_EQ(check_group.scheduleName, group.temperatureSchedule().nameString());
+  }
+}
diff --git a/src/model/CMakeLists.txt b/src/model/CMakeLists.txt
index f2365c3641d..360f01f7666 100644
--- a/src/model/CMakeLists.txt
+++ b/src/model/CMakeLists.txt
@@ -1502,12 +1502,18 @@ set(${target_name}_src
   SurfacePropertyExposedFoundationPerimeter.cpp
   SurfacePropertyExposedFoundationPerimeter.hpp
   SurfacePropertyExposedFoundationPerimeter_Impl.hpp
+  SurfacePropertyLocalEnvironment.cpp
+  SurfacePropertyLocalEnvironment.hpp
+  SurfacePropertyLocalEnvironment_Impl.hpp
   SurfacePropertyOtherSideCoefficients.cpp
   SurfacePropertyOtherSideCoefficients.hpp
   SurfacePropertyOtherSideCoefficients_Impl.hpp
   SurfacePropertyOtherSideConditionsModel.cpp
   SurfacePropertyOtherSideConditionsModel.hpp
   SurfacePropertyOtherSideConditionsModel_Impl.hpp
+  SurfacePropertySurroundingSurfaces.cpp
+  SurfacePropertySurroundingSurfaces.hpp
+  SurfacePropertySurroundingSurfaces_Impl.hpp
   SwimmingPoolIndoor.cpp
   SwimmingPoolIndoor.hpp
   SwimmingPoolIndoor_Impl.hpp
@@ -2186,8 +2192,10 @@ set(${target_name}_test_src
   test/SurfacePropertyConvectionCoefficients_GTest.cpp
   test/SurfacePropertyConvectionCoefficientsMultipleSurface_GTest.cpp
   test/SurfacePropertyConvectionCoefficients_GTest.cpp
+  test/SurfacePropertyLocalEnvironment_GTest.cpp
   test/SurfacePropertyOtherSideCoefficients_GTest.cpp
   test/SurfacePropertyExposedFoundationPerimeter_GTest.cpp
+  test/SurfacePropertySurroundingSurfaces_GTest.cpp
   test/SwimmingPoolIndoor_GTest.cpp
   test/TableMultiVariableLookup_GTest.cpp
   test/ThermalZone_GTest.cpp
diff --git a/src/model/ConcreteModelObjects.hpp b/src/model/ConcreteModelObjects.hpp
index 368a7107bdb..14665687b75 100644
--- a/src/model/ConcreteModelObjects.hpp
+++ b/src/model/ConcreteModelObjects.hpp
@@ -477,8 +477,10 @@
 #include "SurfacePropertyConvectionCoefficients.hpp"
 #include "SurfacePropertyConvectionCoefficientsMultipleSurface.hpp"
 #include "SurfacePropertyExposedFoundationPerimeter.hpp"
+#include "SurfacePropertyLocalEnvironment.hpp"
 #include "SurfacePropertyOtherSideCoefficients.hpp"
 #include "SurfacePropertyOtherSideConditionsModel.hpp"
+#include "SurfacePropertySurroundingSurfaces.hpp"
 #include "SwimmingPoolIndoor.hpp"
 #include "TableMultiVariableLookup.hpp"
 #include "TemperingValve.hpp"
@@ -996,8 +998,10 @@
 #include "SurfacePropertyConvectionCoefficients_Impl.hpp"
 #include "SurfacePropertyConvectionCoefficientsMultipleSurface_Impl.hpp"
 #include "SurfacePropertyExposedFoundationPerimeter_Impl.hpp"
+#include "SurfacePropertyLocalEnvironment_Impl.hpp"
 #include "SurfacePropertyOtherSideCoefficients_Impl.hpp"
 #include "SurfacePropertyOtherSideConditionsModel_Impl.hpp"
+#include "SurfacePropertySurroundingSurfaces_Impl.hpp"
 #include "SwimmingPoolIndoor_Impl.hpp"
 #include "TableMultiVariableLookup_Impl.hpp"
 #include "TemperingValve_Impl.hpp"
diff --git a/src/model/Model.cpp b/src/model/Model.cpp
index 50cde0add2e..84bed1ab6a4 100644
--- a/src/model/Model.cpp
+++ b/src/model/Model.cpp
@@ -3044,8 +3044,10 @@ namespace model {
     REGISTER_CONSTRUCTOR(SurfacePropertyConvectionCoefficients);
     REGISTER_CONSTRUCTOR(SurfacePropertyConvectionCoefficientsMultipleSurface);
     REGISTER_CONSTRUCTOR(SurfacePropertyExposedFoundationPerimeter);
+    REGISTER_CONSTRUCTOR(SurfacePropertyLocalEnvironment);
     REGISTER_CONSTRUCTOR(SurfacePropertyOtherSideCoefficients);
     REGISTER_CONSTRUCTOR(SurfacePropertyOtherSideConditionsModel);
+    REGISTER_CONSTRUCTOR(SurfacePropertySurroundingSurfaces);
     REGISTER_CONSTRUCTOR(SwimmingPoolIndoor);
     REGISTER_CONSTRUCTOR(TableMultiVariableLookup);
     REGISTER_CONSTRUCTOR(TemperingValve);
@@ -3571,8 +3573,10 @@ namespace model {
     REGISTER_COPYCONSTRUCTORS(SurfacePropertyConvectionCoefficients);
     REGISTER_COPYCONSTRUCTORS(SurfacePropertyConvectionCoefficientsMultipleSurface);
     REGISTER_COPYCONSTRUCTORS(SurfacePropertyExposedFoundationPerimeter);
+    REGISTER_COPYCONSTRUCTORS(SurfacePropertyLocalEnvironment);
     REGISTER_COPYCONSTRUCTORS(SurfacePropertyOtherSideCoefficients);
     REGISTER_COPYCONSTRUCTORS(SurfacePropertyOtherSideConditionsModel);
+    REGISTER_COPYCONSTRUCTORS(SurfacePropertySurroundingSurfaces);
     REGISTER_COPYCONSTRUCTORS(SwimmingPoolIndoor);
     REGISTER_COPYCONSTRUCTORS(TableMultiVariableLookup);
     REGISTER_COPYCONSTRUCTORS(TemperingValve);
diff --git a/src/model/ModelGeometry.i b/src/model/ModelGeometry.i
index 98c10fb4cc0..85e2d124f4c 100644
--- a/src/model/ModelGeometry.i
+++ b/src/model/ModelGeometry.i
@@ -164,6 +164,15 @@ class ExteriorLoadInstance;
   }
 };
 
+%extend openstudio::model::SurroundingSurfaceGroup {
+  // 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);
@@ -187,6 +196,9 @@ MODELOBJECT_TEMPLATES(InteriorPartitionSurface);
 MODELOBJECT_TEMPLATES(SurfaceControlMovableInsulation);
 MODELOBJECT_TEMPLATES(SurfacePropertyOtherSideCoefficients);
 MODELOBJECT_TEMPLATES(SurfacePropertyOtherSideConditionsModel);
+MODELOBJECT_TEMPLATES(SurfacePropertyLocalEnvironment);
+MODELOBJECT_TEMPLATES(SurroundingSurfaceGroup); // helper for extensible fields for SurfacePropertySurroundingSurfaces
+MODELOBJECT_TEMPLATES(SurfacePropertySurroundingSurfaces);
 MODELOBJECT_TEMPLATES(SurfacePropertyConvectionCoefficients);
 MODELOBJECT_TEMPLATES(People);
 MODELOBJECT_TEMPLATES(Luminaire);
@@ -241,6 +253,8 @@ SWIG_MODELOBJECT(InteriorPartitionSurface, 1);
 SWIG_MODELOBJECT(SurfaceControlMovableInsulation, 1);
 SWIG_MODELOBJECT(SurfacePropertyOtherSideCoefficients, 1);
 SWIG_MODELOBJECT(SurfacePropertyOtherSideConditionsModel, 1);
+SWIG_MODELOBJECT(SurfacePropertyLocalEnvironment, 1);
+SWIG_MODELOBJECT(SurfacePropertySurroundingSurfaces, 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 697f42261d3..062633e04fe 100644
--- a/src/model/ScheduleTypeRegistry.cpp
+++ b/src/model/ScheduleTypeRegistry.cpp
@@ -395,6 +395,10 @@ namespace model {
        OptionalDouble(), OptionalDouble()},
       {"SurfacePropertyConvectionCoefficientsMultipleSurface", "Convection Coefficient 2", "convectionCoefficient2Schedule", true, "",
        OptionalDouble(), OptionalDouble()},
+      {"SurfacePropertySurroundingSurfaces", "Sky Temperature", "skyTemperatureSchedule", true, "Temperature", OptionalDouble(), OptionalDouble()},
+      {"SurfacePropertySurroundingSurfaces", "Ground Temperature", "groundTemperatureSchedule", true, "Temperature", OptionalDouble(),
+       OptionalDouble()},
+      {"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()},
       {"SwimmingPoolIndoor", "Cover", "coverSchedule", true, "", 0.0, 1.0},
diff --git a/src/model/SubSurface.cpp b/src/model/SubSurface.cpp
index a0559c2db78..d790b9e37ea 100644
--- a/src/model/SubSurface.cpp
+++ b/src/model/SubSurface.cpp
@@ -54,12 +54,14 @@
 #include "DaylightingDeviceLightWell_Impl.hpp"
 #include "WindowPropertyFrameAndDivider.hpp"
 #include "WindowPropertyFrameAndDivider_Impl.hpp"
-#include "SurfacePropertyConvectionCoefficients.hpp"
 #include "SurfacePropertyOtherSideCoefficients.hpp"
 #include "SurfacePropertyOtherSideCoefficients_Impl.hpp"
 #include "SurfacePropertyOtherSideConditionsModel.hpp"
 #include "SurfacePropertyOtherSideConditionsModel_Impl.hpp"
+#include "SurfacePropertyConvectionCoefficients.hpp"
 #include "SurfacePropertyConvectionCoefficients_Impl.hpp"
+#include "SurfacePropertyLocalEnvironment.hpp"
+#include "SurfacePropertyLocalEnvironment_Impl.hpp"
 #include "AirflowNetworkSurface.hpp"
 #include "AirflowNetworkSurface_Impl.hpp"
 #include "AirflowNetworkDetailedOpening.hpp"
@@ -894,6 +896,26 @@ namespace model {
       }
     }
 
+    boost::optional<SurfacePropertyLocalEnvironment> SubSurface_Impl::surfacePropertyLocalEnvironment() const {
+
+      std::vector<SurfacePropertyLocalEnvironment> result;
+      for (auto& localEnv : model().getConcreteModelObjects<SurfacePropertyLocalEnvironment>()) {
+        if (auto subSurface_ = localEnv.exteriorSurfaceAsSubSurface()) {
+          if (subSurface_->handle() == handle()) {
+            result.push_back(localEnv);
+          }
+        }
+      }
+      if (result.empty()) {
+        return boost::none;
+      } else if (result.size() == 1) {
+        return result.at(0);
+      } else {
+        LOG(Error, "More than one SurfacePropertyLocalEnvironment points to this SubSurface");
+        return boost::none;
+      }
+    }
+
     boost::optional<SurfacePropertyOtherSideCoefficients> SubSurface_Impl::surfacePropertyOtherSideCoefficients() const {
       return getObject<SubSurface>().getModelObjectTarget<SurfacePropertyOtherSideCoefficients>(OS_SubSurfaceFields::OutsideBoundaryConditionObject);
     }
@@ -1493,6 +1515,10 @@ namespace model {
     return getImpl<detail::SubSurface_Impl>()->surfacePropertyConvectionCoefficients();
   }
 
+  boost::optional<SurfacePropertyLocalEnvironment> SubSurface::surfacePropertyLocalEnvironment() const {
+    return getImpl<detail::SubSurface_Impl>()->surfacePropertyLocalEnvironment();
+  }
+
   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 476a8dcf789..4985c49d369 100644
--- a/src/model/SubSurface.hpp
+++ b/src/model/SubSurface.hpp
@@ -48,6 +48,7 @@ namespace model {
   class SurfacePropertyOtherSideCoefficients;
   class SurfacePropertyOtherSideConditionsModel;
   class SurfacePropertyConvectionCoefficients;
+  class SurfacePropertyLocalEnvironment;
   class AirflowNetworkSurface;
   class AirflowNetworkDetailedOpening;
   class AirflowNetworkSimpleOpening;
@@ -189,6 +190,9 @@ namespace model {
     /** Returns the SurfacePropertyConvectionCoefficients, if it exists. */
     boost::optional<SurfacePropertyConvectionCoefficients> surfacePropertyConvectionCoefficients() const;
 
+    /** Returns the SurfacePropertyLocalEnvironment, if it exists. */
+    boost::optional<SurfacePropertyLocalEnvironment> surfacePropertyLocalEnvironment() 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 5e0d4c9727d..d6d4c37f9cc 100644
--- a/src/model/SubSurface_Impl.hpp
+++ b/src/model/SubSurface_Impl.hpp
@@ -49,7 +49,8 @@ namespace model {
   class WindowPropertyFrameAndDivider;
   class SurfacePropertyOtherSideCoefficients;
   class SurfacePropertyOtherSideConditionsModel;
-  class SurfacePropertyConfectionCoefficients;
+  class SurfacePropertyConvectionCoefficients;
+  class SurfacePropertyLocalEnvironment;
 
   namespace detail {
 
@@ -226,6 +227,8 @@ namespace model {
       /** Returns the surface property convection coefficients */
       boost::optional<SurfacePropertyConvectionCoefficients> surfacePropertyConvectionCoefficients() const;
 
+      boost::optional<SurfacePropertyLocalEnvironment> surfacePropertyLocalEnvironment() const;
+
       /** Returns the adjacent SurfaceSurfacePropertyOtherSideCoefficients, if it exists. */
       boost::optional<SurfacePropertyOtherSideCoefficients> surfacePropertyOtherSideCoefficients() const;
 
diff --git a/src/model/Surface.cpp b/src/model/Surface.cpp
index 56a17743496..d6c7cb9d116 100644
--- a/src/model/Surface.cpp
+++ b/src/model/Surface.cpp
@@ -55,6 +55,8 @@
 #include "SurfacePropertyOtherSideConditionsModel_Impl.hpp"
 #include "SurfacePropertyConvectionCoefficients.hpp"
 #include "SurfacePropertyConvectionCoefficients_Impl.hpp"
+#include "SurfacePropertyLocalEnvironment.hpp"
+#include "SurfacePropertyLocalEnvironment_Impl.hpp"
 #include "AirflowNetworkSurface.hpp"
 #include "AirflowNetworkSurface_Impl.hpp"
 #include "AirflowNetworkDetailedOpening.hpp"
@@ -169,6 +171,8 @@ namespace model {
         coefficientsClone.setSurface(newParentAsModelObject);
       }
 
+      // TODO: do we clone the SurfacePropertyLocalEnvironment?
+
       auto foundation = adjacentFoundation();
       if (foundation) {
         auto foundationClone = foundation->clone(model).cast<FoundationKiva>();
@@ -946,6 +950,26 @@ namespace model {
       }
     }
 
+    boost::optional<SurfacePropertyLocalEnvironment> Surface_Impl::surfacePropertyLocalEnvironment() const {
+
+      std::vector<SurfacePropertyLocalEnvironment> result;
+      for (auto& localEnv : model().getConcreteModelObjects<SurfacePropertyLocalEnvironment>()) {
+        if (auto surface_ = localEnv.exteriorSurfaceAsSurface()) {
+          if (surface_->handle() == handle()) {
+            result.push_back(localEnv);
+          }
+        }
+      }
+      if (result.empty()) {
+        return boost::none;
+      } else if (result.size() == 1) {
+        return result.at(0);
+      } else {
+        LOG(Error, "More than one SurfacePropertyLocalEnvironment points to this Surface");
+        return boost::none;
+      }
+    }
+
     boost::optional<SurfacePropertyOtherSideCoefficients> Surface_Impl::surfacePropertyOtherSideCoefficients() const {
       return getObject<Surface>().getModelObjectTarget<SurfacePropertyOtherSideCoefficients>(OS_SurfaceFields::OutsideBoundaryConditionObject);
     }
@@ -2292,6 +2316,10 @@ namespace model {
     return getImpl<detail::Surface_Impl>()->surfacePropertyConvectionCoefficients();
   }
 
+  boost::optional<SurfacePropertyLocalEnvironment> Surface::surfacePropertyLocalEnvironment() const {
+    return getImpl<detail::Surface_Impl>()->surfacePropertyLocalEnvironment();
+  }
+
   boost::optional<SurfacePropertyOtherSideCoefficients> Surface::surfacePropertyOtherSideCoefficients() const {
     return getImpl<detail::Surface_Impl>()->surfacePropertyOtherSideCoefficients();
   }
diff --git a/src/model/Surface.hpp b/src/model/Surface.hpp
index ac9999ccf3c..6be172cb87e 100644
--- a/src/model/Surface.hpp
+++ b/src/model/Surface.hpp
@@ -49,6 +49,7 @@ namespace model {
   class SurfacePropertyOtherSideCoefficients;
   class SurfacePropertyOtherSideConditionsModel;
   class SurfacePropertyConvectionCoefficients;
+  class SurfacePropertyLocalEnvironment;
   class AirflowNetworkSurface;
   class AirflowNetworkDetailedOpening;
   class AirflowNetworkSimpleOpening;
@@ -181,6 +182,9 @@ namespace model {
     /** Returns the SurfacePropertyConvectionCoefficients, if it exists. */
     boost::optional<SurfacePropertyConvectionCoefficients> surfacePropertyConvectionCoefficients() const;
 
+    /** Returns the SurfacePropertyLocalEnvironment, if it exists. */
+    boost::optional<SurfacePropertyLocalEnvironment> surfacePropertyLocalEnvironment() const;
+
     /** Returns the adjacent SurfaceSurfacePropertyOtherSideCoefficients, if it exists. */
     boost::optional<SurfacePropertyOtherSideCoefficients> surfacePropertyOtherSideCoefficients() const;
 
diff --git a/src/model/SurfacePropertyLocalEnvironment.cpp b/src/model/SurfacePropertyLocalEnvironment.cpp
new file mode 100644
index 00000000000..218e242e40f
--- /dev/null
+++ b/src/model/SurfacePropertyLocalEnvironment.cpp
@@ -0,0 +1,276 @@
+/***********************************************************************************************************************
+*  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 "SurfacePropertyLocalEnvironment.hpp"
+#include "SurfacePropertyLocalEnvironment_Impl.hpp"
+
+#include "PlanarSurface.hpp"
+#include "PlanarSurface_Impl.hpp"
+#include "Surface.hpp"
+#include "Surface_Impl.hpp"
+#include "SubSurface.hpp"
+#include "SubSurface_Impl.hpp"
+#include "Schedule.hpp"
+#include "Schedule_Impl.hpp"
+#include "Model.hpp"
+
+#include "SurfacePropertySurroundingSurfaces.hpp"
+#include "SurfacePropertySurroundingSurfaces_Impl.hpp"
+//#include "OutdoorAirNode.hpp"
+// #include "OutdoorAirNode_Impl.hpp"
+#include "ScheduleTypeLimits.hpp"
+#include "ScheduleTypeRegistry.hpp"
+
+#include <utilities/idd/IddEnums.hxx>
+#include <utilities/idd/OS_SurfaceProperty_LocalEnvironment_FieldEnums.hxx>
+
+#include "../utilities/core/Assert.hpp"
+
+namespace openstudio {
+namespace model {
+
+  namespace detail {
+
+    SurfacePropertyLocalEnvironment_Impl::SurfacePropertyLocalEnvironment_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle)
+      : ModelObject_Impl(idfObject, model, keepHandle) {
+      OS_ASSERT(idfObject.iddObject().type() == SurfacePropertyLocalEnvironment::iddObjectType());
+    }
+
+    SurfacePropertyLocalEnvironment_Impl::SurfacePropertyLocalEnvironment_Impl(const openstudio::detail::WorkspaceObject_Impl& other,
+                                                                               Model_Impl* model, bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {
+      OS_ASSERT(other.iddObject().type() == SurfacePropertyLocalEnvironment::iddObjectType());
+    }
+
+    SurfacePropertyLocalEnvironment_Impl::SurfacePropertyLocalEnvironment_Impl(const SurfacePropertyLocalEnvironment_Impl& other, Model_Impl* model,
+                                                                               bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {}
+
+    const std::vector<std::string>& SurfacePropertyLocalEnvironment_Impl::outputVariableNames() const {
+      static std::vector<std::string> result;
+      if (result.empty()) {
+      }
+      return result;
+    }
+
+    IddObjectType SurfacePropertyLocalEnvironment_Impl::iddObjectType() const {
+      return SurfacePropertyLocalEnvironment::iddObjectType();
+    }
+
+    std::vector<ScheduleTypeKey> SurfacePropertyLocalEnvironment_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_LocalEnvironmentFields::ExternalShadingFractionScheduleName) != e) {
+        result.emplace_back("SurfacePropertyLocalEnvironment", "External Shading Fraction");
+      }
+      return result;
+    }
+
+    boost::optional<PlanarSurface> SurfacePropertyLocalEnvironment_Impl::optionalExteriorSurface() const {
+      if (auto mo_ = getObject<ModelObject>().getModelObjectTarget<ModelObject>(OS_SurfaceProperty_LocalEnvironmentFields::ExteriorSurfaceName)) {
+        return mo_->cast<PlanarSurface>();
+      }
+      return boost::none;
+    }
+
+    PlanarSurface SurfacePropertyLocalEnvironment_Impl::exteriorSurface() const {
+      boost::optional<PlanarSurface> value = optionalExteriorSurface();
+      if (!value) {
+        LOG_AND_THROW(briefDescription() << " does not have an Exterior Surface attached.");
+      }
+      return value.get();
+    }
+
+    boost::optional<Surface> SurfacePropertyLocalEnvironment_Impl::exteriorSurfaceAsSurface() const {
+      return getObject<ModelObject>().getModelObjectTarget<Surface>(OS_SurfaceProperty_LocalEnvironmentFields::ExteriorSurfaceName);
+    }
+
+    boost::optional<SubSurface> SurfacePropertyLocalEnvironment_Impl::exteriorSurfaceAsSubSurface() const {
+      return getObject<ModelObject>().getModelObjectTarget<SubSurface>(OS_SurfaceProperty_LocalEnvironmentFields::ExteriorSurfaceName);
+    }
+
+    boost::optional<Schedule> SurfacePropertyLocalEnvironment_Impl::externalShadingFractionSchedule() const {
+      return getObject<ModelObject>().getModelObjectTarget<Schedule>(OS_SurfaceProperty_LocalEnvironmentFields::ExternalShadingFractionScheduleName);
+    }
+
+    boost::optional<SurfacePropertySurroundingSurfaces> SurfacePropertyLocalEnvironment_Impl::surfacePropertySurroundingSurfaces() const {
+      return getObject<ModelObject>().getModelObjectTarget<SurfacePropertySurroundingSurfaces>(
+        OS_SurfaceProperty_LocalEnvironmentFields::SurroundingSurfacesObjectName);
+    }
+
+    bool SurfacePropertyLocalEnvironment_Impl::setExteriorSurface(const PlanarSurface& surface) {
+
+      boost::optional<SurfacePropertyLocalEnvironment> currentLocalEnv;
+      if (auto s_ = surface.optionalCast<Surface>()) {
+        currentLocalEnv = s_->surfacePropertyLocalEnvironment();
+      } else if (auto s_ = surface.optionalCast<SubSurface>()) {
+        currentLocalEnv = s_->surfacePropertyLocalEnvironment();
+      } else {
+        LOG(Error,
+            "SurfacePropertyLocalEnvironment currently only accepts Surface and SubSurface, object isn't accepted: " << surface.briefDescription());
+        return false;
+      }
+      if (currentLocalEnv) {
+        if (currentLocalEnv->handle() == this->handle()) {
+          return true;
+        }
+        LOG(Warn, "Surface " << surface.nameString()
+                             << " already has a SurfacePropertyLocalEnvironment attached, and it will be **removed**. Please check your inputs.");
+
+        currentLocalEnv->remove();
+      }
+      return setPointer(OS_SurfaceProperty_LocalEnvironmentFields::ExteriorSurfaceName, surface.handle());
+    }
+
+    bool SurfacePropertyLocalEnvironment_Impl::setExternalShadingFractionSchedule(Schedule& schedule) {
+      bool result = setSchedule(OS_SurfaceProperty_LocalEnvironmentFields::ExternalShadingFractionScheduleName, "SurfacePropertyLocalEnvironment",
+                                "External Shading Fraction", schedule);
+      return result;
+    }
+
+    void SurfacePropertyLocalEnvironment_Impl::resetExternalShadingFractionSchedule() {
+      bool result = setString(OS_SurfaceProperty_LocalEnvironmentFields::ExternalShadingFractionScheduleName, "");
+      OS_ASSERT(result);
+    }
+
+    bool SurfacePropertyLocalEnvironment_Impl::setSurfacePropertySurroundingSurfaces(
+      const SurfacePropertySurroundingSurfaces& surfacePropertySurroundingSurfaces) {
+      bool result = setPointer(OS_SurfaceProperty_LocalEnvironmentFields::SurroundingSurfacesObjectName, surfacePropertySurroundingSurfaces.handle());
+      return result;
+    }
+
+    void SurfacePropertyLocalEnvironment_Impl::resetSurfacePropertySurroundingSurfaces() {
+      bool result = setString(OS_SurfaceProperty_LocalEnvironmentFields::SurroundingSurfacesObjectName, "");
+      OS_ASSERT(result);
+    }
+
+    //boost::optional<OutdoorAirNode> SurfacePropertyLocalEnvironment_Impl::outdoorAirNode() const {
+    //return getObject<ModelObject>().getModelObjectTarget<OutdoorAirNode>(OS_SurfaceProperty_LocalEnvironmentFields::OutdoorAirNodeName);
+    //}
+
+    //bool SurfacePropertyLocalEnvironment_Impl::setOutdoorAirNode(const OutdoorAirNode& outdoorAirNode) {
+    //bool result = setPointer(OS_SurfaceProperty_LocalEnvironmentFields::OutdoorAirNodeName, outdoorAirNode.handle());
+    //return result;
+    //}
+
+    //void SurfacePropertyLocalEnvironment_Impl::resetOutdoorAirNode() {
+    //bool result = setString(OS_SurfaceProperty_LocalEnvironmentFields::OutdoorAirNodeName, "");
+    //OS_ASSERT(result);
+    //}
+
+  }  // namespace detail
+
+  SurfacePropertyLocalEnvironment::SurfacePropertyLocalEnvironment(const Surface& surface)
+    : ModelObject(SurfacePropertyLocalEnvironment::iddObjectType(), surface.model()) {
+    OS_ASSERT(getImpl<detail::SurfacePropertyLocalEnvironment_Impl>());
+
+    bool ok = setExteriorSurface(surface);
+    if (!ok) {
+      this->remove();
+      LOG_AND_THROW("Cannot create a SurfacePropertyLocalEnvironment pointing to " << surface.briefDescription());
+    }
+  }
+
+  SurfacePropertyLocalEnvironment::SurfacePropertyLocalEnvironment(const SubSurface& subSurface)
+    : ModelObject(SurfacePropertyLocalEnvironment::iddObjectType(), subSurface.model()) {
+    OS_ASSERT(getImpl<detail::SurfacePropertyLocalEnvironment_Impl>());
+
+    bool ok = setExteriorSurface(subSurface);
+    if (!ok) {
+      this->remove();
+      LOG_AND_THROW("Cannot create a SurfacePropertyLocalEnvironment pointing to " << subSurface.briefDescription());
+    }
+  }
+
+  IddObjectType SurfacePropertyLocalEnvironment::iddObjectType() {
+    return {IddObjectType::OS_SurfaceProperty_LocalEnvironment};
+  }
+
+  PlanarSurface SurfacePropertyLocalEnvironment::exteriorSurface() const {
+    return getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->exteriorSurface();
+  }
+
+  boost::optional<Surface> SurfacePropertyLocalEnvironment::exteriorSurfaceAsSurface() const {
+    return getImpl<ImplType>()->exteriorSurfaceAsSurface();
+  }
+
+  boost::optional<SubSurface> SurfacePropertyLocalEnvironment::exteriorSurfaceAsSubSurface() const {
+    return getImpl<ImplType>()->exteriorSurfaceAsSubSurface();
+  }
+
+  boost::optional<Schedule> SurfacePropertyLocalEnvironment::externalShadingFractionSchedule() const {
+    return getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->externalShadingFractionSchedule();
+  }
+
+  boost::optional<SurfacePropertySurroundingSurfaces> SurfacePropertyLocalEnvironment::surfacePropertySurroundingSurfaces() const {
+    return getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->surfacePropertySurroundingSurfaces();
+  }
+
+  bool SurfacePropertyLocalEnvironment::setExteriorSurface(const PlanarSurface& surface) {
+    return getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->setExteriorSurface(surface);
+  }
+
+  bool SurfacePropertyLocalEnvironment::setExternalShadingFractionSchedule(Schedule& schedule) {
+    return getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->setExternalShadingFractionSchedule(schedule);
+  }
+
+  void SurfacePropertyLocalEnvironment::resetExternalShadingFractionSchedule() {
+    getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->resetExternalShadingFractionSchedule();
+  }
+
+  bool SurfacePropertyLocalEnvironment::setSurfacePropertySurroundingSurfaces(
+    const SurfacePropertySurroundingSurfaces& surfacePropertySurroundingSurfaces) {
+    return getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->setSurfacePropertySurroundingSurfaces(surfacePropertySurroundingSurfaces);
+  }
+
+  void SurfacePropertyLocalEnvironment::resetSurfacePropertySurroundingSurfaces() {
+    getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->resetSurfacePropertySurroundingSurfaces();
+  }
+
+  //boost::optional<OutdoorAirNode> SurfacePropertyLocalEnvironment::outdoorAirNode() const {
+  //return getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->outdoorAirNode();
+  //}
+
+  //bool SurfacePropertyLocalEnvironment::setOutdoorAirNode(const OutdoorAirNode& outdoorAirNode) {
+  //return getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->setOutdoorAirNode(outdoorAirNode);
+  //}
+
+  //void SurfacePropertyLocalEnvironment::resetOutdoorAirNode() {
+  //getImpl<detail::SurfacePropertyLocalEnvironment_Impl>()->resetOutdoorAirNode();
+  //}
+
+  /// @cond
+  SurfacePropertyLocalEnvironment::SurfacePropertyLocalEnvironment(std::shared_ptr<detail::SurfacePropertyLocalEnvironment_Impl> impl)
+    : ModelObject(std::move(impl)) {}
+  /// @endcond
+
+}  // namespace model
+}  // namespace openstudio
diff --git a/src/model/SurfacePropertyLocalEnvironment.hpp b/src/model/SurfacePropertyLocalEnvironment.hpp
new file mode 100644
index 00000000000..a609d88614c
--- /dev/null
+++ b/src/model/SurfacePropertyLocalEnvironment.hpp
@@ -0,0 +1,127 @@
+/***********************************************************************************************************************
+*  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_SURFACEPROPERTYLOCALENVIRONMENT_HPP
+#define MODEL_SURFACEPROPERTYLOCALENVIRONMENT_HPP
+
+#include <model/ModelAPI.hpp>
+#include "ModelObject.hpp"
+
+namespace openstudio {
+namespace model {
+
+  class Surface;
+  class SubSurface;
+  class PlanarSurface;
+  class Schedule;
+  class SurfacePropertySurroundingSurfaces;
+  // class OutdoorAirNode;
+
+  namespace detail {
+
+    class SurfacePropertyLocalEnvironment_Impl;
+
+  }  // namespace detail
+
+  /** SurfacePropertyLocalEnvironment is a ModelObject that wraps the OpenStudio IDD object 'OS:SurfaceProperty:LocalEnvironment'. */
+  class MODEL_API SurfacePropertyLocalEnvironment : public ModelObject
+  {
+   public:
+    /** @name Constructors and Destructors */
+    //@{
+
+    explicit SurfacePropertyLocalEnvironment(const Surface& surface);
+    explicit SurfacePropertyLocalEnvironment(const SubSurface& surface);
+
+    virtual ~SurfacePropertyLocalEnvironment() {}
+
+    //@}
+
+    static IddObjectType iddObjectType();
+
+    /** @name Getters */
+    //@{
+
+    PlanarSurface exteriorSurface() const;
+    boost::optional<Surface> exteriorSurfaceAsSurface() const;
+    boost::optional<SubSurface> exteriorSurfaceAsSubSurface() const;
+
+    boost::optional<Schedule> externalShadingFractionSchedule() const;
+
+    boost::optional<SurfacePropertySurroundingSurfaces> surfacePropertySurroundingSurfaces() const;
+
+    // boost::optional<OutdoorAirNode> outdoorAirNode() const;
+
+    //@}
+    /** @name Setters */
+    //@{
+
+    // Note that unicity is enforced: if the surface to point to already has a SurfacePropertyLocalEnvironment object attached, it will be removed
+    // first
+    bool setExteriorSurface(const PlanarSurface& surface);
+
+    bool setExternalShadingFractionSchedule(Schedule& schedule);
+    void resetExternalShadingFractionSchedule();
+
+    bool setSurfacePropertySurroundingSurfaces(const SurfacePropertySurroundingSurfaces& surfacePropertySurroundingSurfaces);
+    void resetSurfacePropertySurroundingSurfaces();
+
+    // bool setOutdoorAirNode(const OutdoorAirNode& outdoorAirNode);
+    // void resetOutdoorAirNode();
+
+    //@}
+    /** @name Other */
+    //@{
+
+    //@}
+   protected:
+    /// @cond
+    using ImplType = detail::SurfacePropertyLocalEnvironment_Impl;
+
+    explicit SurfacePropertyLocalEnvironment(std::shared_ptr<detail::SurfacePropertyLocalEnvironment_Impl> impl);
+
+    friend class detail::SurfacePropertyLocalEnvironment_Impl;
+    friend class Model;
+    friend class IdfObject;
+    friend class openstudio::detail::IdfObject_Impl;
+    /// @endcond
+   private:
+    REGISTER_LOGGER("openstudio.model.SurfacePropertyLocalEnvironment");
+  };
+
+  /** \relates SurfacePropertyLocalEnvironment*/
+  using OptionalSurfacePropertyLocalEnvironment = boost::optional<SurfacePropertyLocalEnvironment>;
+
+  /** \relates SurfacePropertyLocalEnvironment*/
+  using SurfacePropertyLocalEnvironmentVector = std::vector<SurfacePropertyLocalEnvironment>;
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_SURFACEPROPERTYLOCALENVIRONMENT_HPP
diff --git a/src/model/SurfacePropertyLocalEnvironment_Impl.hpp b/src/model/SurfacePropertyLocalEnvironment_Impl.hpp
new file mode 100644
index 00000000000..99df20e6ff7
--- /dev/null
+++ b/src/model/SurfacePropertyLocalEnvironment_Impl.hpp
@@ -0,0 +1,119 @@
+/***********************************************************************************************************************
+*  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_SURFACEPROPERTYLOCALENVIRONMENT_IMPL_HPP
+#define MODEL_SURFACEPROPERTYLOCALENVIRONMENT_IMPL_HPP
+
+#include <model/ModelAPI.hpp>
+#include "ModelObject_Impl.hpp"
+
+namespace openstudio {
+namespace model {
+
+  class PlanarSurface;
+  class Surface;
+  class SubSurface;
+  class Schedule;
+  class SurfacePropertySurroundingSurfaces;
+  // class OutdoorAirNode;
+
+  namespace detail {
+
+    /** SurfacePropertyLocalEnvironment_Impl is a ModelObject_Impl that is the implementation class for SurfacePropertyLocalEnvironment.*/
+    class MODEL_API SurfacePropertyLocalEnvironment_Impl : public ModelObject_Impl
+    {
+     public:
+      /** @name Constructors and Destructors */
+      //@{
+
+      SurfacePropertyLocalEnvironment_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle);
+
+      SurfacePropertyLocalEnvironment_Impl(const openstudio::detail::WorkspaceObject_Impl& other, Model_Impl* model, bool keepHandle);
+
+      SurfacePropertyLocalEnvironment_Impl(const SurfacePropertyLocalEnvironment_Impl& other, Model_Impl* model, bool keepHandle);
+
+      virtual ~SurfacePropertyLocalEnvironment_Impl() {}
+
+      //@}
+      /** @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 */
+      //@{
+
+      PlanarSurface exteriorSurface() const;
+      boost::optional<Surface> exteriorSurfaceAsSurface() const;
+      boost::optional<SubSurface> exteriorSurfaceAsSubSurface() const;
+
+      boost::optional<Schedule> externalShadingFractionSchedule() const;
+
+      boost::optional<SurfacePropertySurroundingSurfaces> surfacePropertySurroundingSurfaces() const;
+
+      // boost::optional<OutdoorAirNode> outdoorAirNode() const;
+
+      //@}
+      /** @name Setters */
+      //@{
+
+      bool setExteriorSurface(const PlanarSurface& surface);
+
+      bool setExternalShadingFractionSchedule(Schedule& schedule);
+      void resetExternalShadingFractionSchedule();
+
+      bool setSurfacePropertySurroundingSurfaces(const SurfacePropertySurroundingSurfaces& surfacePropertySurroundingSurfaces);
+      void resetSurfacePropertySurroundingSurfaces();
+
+      // bool setOutdoorAirNode(const OutdoorAirNode& outdoorAirNode);
+      // void resetOutdoorAirNode();
+
+      //@}
+      /** @name Other */
+      //@{
+
+      //@}
+     protected:
+     private:
+      REGISTER_LOGGER("openstudio.model.SurfacePropertyLocalEnvironment");
+
+      boost::optional<PlanarSurface> optionalExteriorSurface() const;
+    };
+
+  }  // namespace detail
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_SURFACEPROPERTYLOCALENVIRONMENT_IMPL_HPP
diff --git a/src/model/SurfacePropertySurroundingSurfaces.cpp b/src/model/SurfacePropertySurroundingSurfaces.cpp
new file mode 100644
index 00000000000..6a46eadbe8d
--- /dev/null
+++ b/src/model/SurfacePropertySurroundingSurfaces.cpp
@@ -0,0 +1,518 @@
+/***********************************************************************************************************************
+*  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 "SurfacePropertySurroundingSurfaces.hpp"
+#include "SurfacePropertySurroundingSurfaces_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_SurroundingSurfaces_FieldEnums.hxx>
+
+#include "../utilities/units/Unit.hpp"
+
+#include "../utilities/core/Assert.hpp"
+#include "utilities/core/Compare.hpp"
+
+namespace openstudio {
+namespace model {
+
+  /***************************************************************************************************************************************************
+   *                                       S U R R O U N D I N G    S U R F A C E    G R O U P    W R A P P E R                                     *
+   **************************************************************************************************************************************************/
+
+  SurroundingSurfaceGroup::SurroundingSurfaceGroup(std::string surroundingSurfaceName, double viewFactor, const Schedule& temperatureSchedule)
+    : m_surroundingSurfaceName(std::move(surroundingSurfaceName)), m_viewFactor(viewFactor), m_tempSch(temperatureSchedule) {
+
+    // Matches the maximum value in IDD
+    if (m_viewFactor > 1) {
+      LOG_AND_THROW("Unable to create SurroundingSurfaceGroup, View Factor of " << m_viewFactor << " cannot be more than 1.");
+    } else if (m_viewFactor < 0) {
+      LOG_AND_THROW("Unable to create SurroundingSurfaceGroup, View Factor of " << m_viewFactor << " cannot be less than 0.");
+    }
+
+    if (m_surroundingSurfaceName.empty()) {
+      LOG_AND_THROW("Unable to create SurroundingSurfaceGroup, SurroundingSurfaceName cannot be empty.");
+    }
+  }
+
+  std::string SurroundingSurfaceGroup::surroundingSurfaceName() const {
+    return m_surroundingSurfaceName;
+  }
+
+  double SurroundingSurfaceGroup::viewFactor() const {
+    return m_viewFactor;
+  }
+
+  Schedule SurroundingSurfaceGroup::temperatureSchedule() const {
+    return m_tempSch;
+  }
+
+  std::ostream& operator<<(std::ostream& out, const openstudio::model::SurroundingSurfaceGroup& surroundingSurfaceGroup) {
+    out << "(Surface = '" << surroundingSurfaceGroup.surroundingSurfaceName() << "', "
+        << "View Factor = " << surroundingSurfaceGroup.viewFactor() << ", "
+        << "Schedule = '" << surroundingSurfaceGroup.temperatureSchedule().nameString() << "')";
+    return out;
+  }
+
+  namespace detail {
+
+    SurfacePropertySurroundingSurfaces_Impl::SurfacePropertySurroundingSurfaces_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle)
+      : ModelObject_Impl(idfObject, model, keepHandle) {
+      OS_ASSERT(idfObject.iddObject().type() == SurfacePropertySurroundingSurfaces::iddObjectType());
+    }
+
+    SurfacePropertySurroundingSurfaces_Impl::SurfacePropertySurroundingSurfaces_Impl(const openstudio::detail::WorkspaceObject_Impl& other,
+                                                                                     Model_Impl* model, bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {
+      OS_ASSERT(other.iddObject().type() == SurfacePropertySurroundingSurfaces::iddObjectType());
+    }
+
+    SurfacePropertySurroundingSurfaces_Impl::SurfacePropertySurroundingSurfaces_Impl(const SurfacePropertySurroundingSurfaces_Impl& other,
+                                                                                     Model_Impl* model, bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {}
+
+    const std::vector<std::string>& SurfacePropertySurroundingSurfaces_Impl::outputVariableNames() const {
+      static std::vector<std::string> result;
+      if (result.empty()) {
+      }
+      return result;
+    }
+
+    IddObjectType SurfacePropertySurroundingSurfaces_Impl::iddObjectType() const {
+      return SurfacePropertySurroundingSurfaces::iddObjectType();
+    }
+
+    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");
+      }
+      if (std::find(b, e, OS_SurfaceProperty_SurroundingSurfacesFields::GroundTemperatureScheduleName) != e) {
+        result.emplace_back("SurfacePropertySurroundingSurfaces", "Ground Temperature");
+      }
+      return result;
+    }
+
+    boost::optional<double> SurfacePropertySurroundingSurfaces_Impl::skyViewFactor() const {
+      return getDouble(OS_SurfaceProperty_SurroundingSurfacesFields::SkyViewFactor, true);
+    }
+
+    bool SurfacePropertySurroundingSurfaces_Impl::isSkyViewFactorAutocalculated() const {
+      bool result = false;
+      boost::optional<std::string> value = getString(OS_SurfaceProperty_SurroundingSurfacesFields::SkyViewFactor, true);
+      if (value) {
+        result = openstudio::istringEqual(value.get(), "autocalculate");
+      }
+      return result;
+    }
+
+    boost::optional<Schedule> SurfacePropertySurroundingSurfaces_Impl::skyTemperatureSchedule() const {
+      return getObject<ModelObject>().getModelObjectTarget<Schedule>(OS_SurfaceProperty_SurroundingSurfacesFields::SkyTemperatureScheduleName);
+    }
+
+    boost::optional<double> SurfacePropertySurroundingSurfaces_Impl::groundViewFactor() const {
+      return getDouble(OS_SurfaceProperty_SurroundingSurfacesFields::GroundViewFactor, true);
+    }
+
+    bool SurfacePropertySurroundingSurfaces_Impl::isGroundViewFactorAutocalculated() const {
+      bool result = false;
+      boost::optional<std::string> value = getString(OS_SurfaceProperty_SurroundingSurfacesFields::GroundViewFactor, true);
+      if (value) {
+        result = openstudio::istringEqual(value.get(), "autocalculate");
+      }
+      return result;
+    }
+
+    boost::optional<Schedule> SurfacePropertySurroundingSurfaces_Impl::groundTemperatureSchedule() const {
+      return getObject<ModelObject>().getModelObjectTarget<Schedule>(OS_SurfaceProperty_SurroundingSurfacesFields::GroundTemperatureScheduleName);
+    }
+
+    bool SurfacePropertySurroundingSurfaces_Impl::setSkyViewFactor(double skyViewFactor) {
+      bool result = setDouble(OS_SurfaceProperty_SurroundingSurfacesFields::SkyViewFactor, skyViewFactor);
+      return result;
+    }
+
+    void SurfacePropertySurroundingSurfaces_Impl::autocalculateSkyViewFactor() {
+      bool result = setString(OS_SurfaceProperty_SurroundingSurfacesFields::SkyViewFactor, "autocalculate");
+      OS_ASSERT(result);
+    }
+
+    bool SurfacePropertySurroundingSurfaces_Impl::setSkyTemperatureSchedule(Schedule& schedule) {
+      bool result = setSchedule(OS_SurfaceProperty_SurroundingSurfacesFields::SkyTemperatureScheduleName, "SurfacePropertySurroundingSurfaces",
+                                "Sky Temperature", schedule);
+      return result;
+    }
+
+    void SurfacePropertySurroundingSurfaces_Impl::resetSkyTemperatureSchedule() {
+      bool result = setString(OS_SurfaceProperty_SurroundingSurfacesFields::SkyTemperatureScheduleName, "");
+      OS_ASSERT(result);
+    }
+
+    bool SurfacePropertySurroundingSurfaces_Impl::setGroundViewFactor(double groundViewFactor) {
+      bool result = setDouble(OS_SurfaceProperty_SurroundingSurfacesFields::GroundViewFactor, groundViewFactor);
+      return result;
+    }
+
+    void SurfacePropertySurroundingSurfaces_Impl::autocalculateGroundViewFactor() {
+      bool result = setString(OS_SurfaceProperty_SurroundingSurfacesFields::GroundViewFactor, "autocalculate");
+      OS_ASSERT(result);
+    }
+
+    bool SurfacePropertySurroundingSurfaces_Impl::setGroundTemperatureSchedule(Schedule& schedule) {
+      bool result = setSchedule(OS_SurfaceProperty_SurroundingSurfacesFields::GroundTemperatureScheduleName, "SurfacePropertySurroundingSurfaces",
+                                "Ground Temperature", schedule);
+      return result;
+    }
+
+    void SurfacePropertySurroundingSurfaces_Impl::resetGroundTemperatureSchedule() {
+      bool result = setString(OS_SurfaceProperty_SurroundingSurfacesFields::GroundTemperatureScheduleName, "");
+      OS_ASSERT(result);
+    }
+
+    // Extensible groups
+
+    unsigned int SurfacePropertySurroundingSurfaces_Impl::numberofSurroundingSurfaceGroups() const {
+      return numExtensibleGroups();
+    }
+
+    boost::optional<unsigned> SurfacePropertySurroundingSurfaces_Impl::surroundingSurfaceGroupIndex(const std::string& surroundingSurfaceName) 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 surroundingSurfaceGroups()) and getString to avoid overhead
+      // of manipulating actual model objects (getTarget, then create a SurroundingSurfaceGroups 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(), [&surroundingSurfaceName](const WorkspaceExtensibleGroup& eg) {
+        return openstudio::istringEqual(eg.getField(OS_SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceName).get(),
+                                        surroundingSurfaceName);
+      });
+
+      // 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>
+      SurfacePropertySurroundingSurfaces_Impl::surroundingSurfaceGroupIndex(const SurroundingSurfaceGroup& surroundingSurfaceGroup) const {
+      return surroundingSurfaceGroupIndex(surroundingSurfaceGroup.surroundingSurfaceName());
+    }
+
+    boost::optional<SurroundingSurfaceGroup> SurfacePropertySurroundingSurfaces_Impl::getSurroundingSurfaceGroup(unsigned groupIndex) const {
+
+      boost::optional<SurroundingSurfaceGroup> result;
+
+      if (groupIndex >= numberofSurroundingSurfaceGroups()) {
+        LOG(Error, "Asked to get SurroundingSurfaceGroup with index " << groupIndex << ", but " << briefDescription() << " has just "
+                                                                      << numberofSurroundingSurfaceGroups() << " SurroundingSurfaceGroups.");
+        return result;
+      }
+
+      auto group = getExtensibleGroup(groupIndex).cast<ModelExtensibleGroup>();
+
+      boost::optional<std::string> surfaceName_ = group.getString(OS_SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceName);
+      boost::optional<double> viewFactor_ = group.getDouble(OS_SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceViewFactor);
+      boost::optional<Schedule> tempSch_ =
+        group.getModelObjectTarget<Schedule>(OS_SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceTemperatureScheduleName);
+
+      if (!surfaceName_) {
+        LOG(Error, "Could not retrieve SurroundingSurfaceName for extensible group " << group.groupIndex() << ".");
+      }
+      if (!viewFactor_) {
+        LOG(Error, "Could not retrieve SurroundingSurfaceViewFactor for extensible group " << group.groupIndex() << ".");
+      }
+      if (!tempSch_) {
+        LOG(Error, "Could not retrieve SurroundingSurfaceTemperatureScheduleName for extensible group " << group.groupIndex() << ".");
+      }
+
+      result = SurroundingSurfaceGroup(surfaceName_.get(), viewFactor_.get(), tempSch_.get());
+
+      return result;
+    }
+
+    bool SurfacePropertySurroundingSurfaces_Impl::addSurroundingSurfaceGroup(const SurroundingSurfaceGroup& surroundingSurfaceGroup) {
+
+      // Bounds checking happens in the SurroundingSurfaceGroup ctor
+
+      // Check if viewFactor already exists
+      boost::optional<unsigned> _existingIndex = surroundingSurfaceGroupIndex(surroundingSurfaceGroup);
+      if (_existingIndex) {
+        boost::optional<SurroundingSurfaceGroup> _group = getSurroundingSurfaceGroup(_existingIndex.get());
+        OS_ASSERT(_group);
+        LOG(Warn, "For " << briefDescription() << ", SurroundingSurfaceGroup already exists, will be modified in place from " << _group.get()
+                         << " to " << surroundingSurfaceGroup << ".");
+      }
+
+      // 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_SurroundingSurfacesExtensibleFields::SurroundingSurfaceName,
+                                        surroundingSurfaceGroup.surroundingSurfaceName());
+
+      bool viewFactorOk =
+        eg.setDouble(OS_SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceViewFactor, surroundingSurfaceGroup.viewFactor());
+
+      auto sch = surroundingSurfaceGroup.temperatureSchedule();
+      bool schOk =
+        eg.setPointer(OS_SurfaceProperty_SurroundingSurfacesExtensibleFields::SurroundingSurfaceTemperatureScheduleName, sch.handle(), false);
+      if (!schOk) {
+        LOG(Error, "Unable to add View Factor which has an incompatible toSurface object to " << briefDescription());
+        OS_ASSERT(false);
+      }
+
+      if (surfaceNameOk && viewFactorOk && schOk) {
+        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 SurroundingSurfaceGroup wrapper, then call `addSurroundingSurfaceGroup(const SurroundingSurfaceGroup& surroundingSurfaceGroup)`
+    bool SurfacePropertySurroundingSurfaces_Impl::addSurroundingSurfaceGroup(const std::string& surroundingSurfaceName, double viewFactor,
+                                                                             const Schedule& temperatureSchedule) {
+      SurroundingSurfaceGroup surroundingSurfaceGroup(surroundingSurfaceName, viewFactor, temperatureSchedule);
+      return addSurroundingSurfaceGroup(surroundingSurfaceGroup);
+    }
+
+    bool SurfacePropertySurroundingSurfaces_Impl::addSurroundingSurfaceGroups(const std::vector<SurroundingSurfaceGroup>& surroundingSurfaceGroups) {
+      bool result = true;
+
+      for (const auto& surroundingSurfaceGroup : surroundingSurfaceGroups) {
+        bool thisResult = addSurroundingSurfaceGroup(surroundingSurfaceGroup);
+        if (!thisResult) {
+          LOG(Error,
+              "Could not add surroundingSurfaceGroup " << surroundingSurfaceGroup << " to " << briefDescription() << ". Continuing with others.");
+          // OS_ASSERT(false);
+          // result = false;
+        }
+      }
+
+      return result;
+    }
+
+    bool SurfacePropertySurroundingSurfaces_Impl::removeSurroundingSurfaceGroup(unsigned groupIndex) {
+      bool result = false;
+
+      unsigned int num = numberofSurroundingSurfaceGroups();
+      if (groupIndex < num) {
+        getObject<ModelObject>().eraseExtensibleGroup(groupIndex);
+        result = true;
+      }
+      return result;
+    }
+
+    void SurfacePropertySurroundingSurfaces_Impl::removeAllSurroundingSurfaceGroups() {
+      getObject<ModelObject>().clearExtensibleGroups();
+    }
+
+    std::vector<SurroundingSurfaceGroup> SurfacePropertySurroundingSurfaces_Impl::surroundingSurfaceGroups() const {
+      std::vector<SurroundingSurfaceGroup> result;
+
+      for (unsigned i = 0; i < numberofSurroundingSurfaceGroups(); ++i) {
+
+        boost::optional<SurroundingSurfaceGroup> group_ = getSurroundingSurfaceGroup(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 SurroundingSurfaceGroup group at index " << i);
+        }
+      }
+
+      return result;
+    }
+
+    // Helper
+    boost::optional<SurfacePropertyLocalEnvironment> SurfacePropertySurroundingSurfaces_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 SurfacePropertySurroundingSurfaces");
+        return boost::none;
+      }
+    }
+
+  }  // namespace detail
+
+  SurfacePropertySurroundingSurfaces::SurfacePropertySurroundingSurfaces(const Model& model)
+    : ModelObject(SurfacePropertySurroundingSurfaces::iddObjectType(), model) {
+    OS_ASSERT(getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>());
+
+    autocalculateSkyViewFactor();
+    autocalculateGroundViewFactor();
+    // TODO: Appropriately handle the following required object-list fields.
+  }
+
+  IddObjectType SurfacePropertySurroundingSurfaces::iddObjectType() {
+    return {IddObjectType::OS_SurfaceProperty_SurroundingSurfaces};
+  }
+
+  boost::optional<double> SurfacePropertySurroundingSurfaces::skyViewFactor() const {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->skyViewFactor();
+  }
+
+  bool SurfacePropertySurroundingSurfaces::isSkyViewFactorAutocalculated() const {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->isSkyViewFactorAutocalculated();
+  }
+
+  boost::optional<Schedule> SurfacePropertySurroundingSurfaces::skyTemperatureSchedule() const {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->skyTemperatureSchedule();
+  }
+
+  boost::optional<double> SurfacePropertySurroundingSurfaces::groundViewFactor() const {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->groundViewFactor();
+  }
+
+  bool SurfacePropertySurroundingSurfaces::isGroundViewFactorAutocalculated() const {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->isGroundViewFactorAutocalculated();
+  }
+
+  boost::optional<Schedule> SurfacePropertySurroundingSurfaces::groundTemperatureSchedule() const {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->groundTemperatureSchedule();
+  }
+
+  bool SurfacePropertySurroundingSurfaces::setSkyViewFactor(double skyViewFactor) {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->setSkyViewFactor(skyViewFactor);
+  }
+
+  void SurfacePropertySurroundingSurfaces::autocalculateSkyViewFactor() {
+    getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->autocalculateSkyViewFactor();
+  }
+
+  bool SurfacePropertySurroundingSurfaces::setSkyTemperatureSchedule(Schedule& schedule) {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->setSkyTemperatureSchedule(schedule);
+  }
+
+  void SurfacePropertySurroundingSurfaces::resetSkyTemperatureSchedule() {
+    getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->resetSkyTemperatureSchedule();
+  }
+
+  bool SurfacePropertySurroundingSurfaces::setGroundViewFactor(double groundViewFactor) {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->setGroundViewFactor(groundViewFactor);
+  }
+
+  void SurfacePropertySurroundingSurfaces::autocalculateGroundViewFactor() {
+    getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->autocalculateGroundViewFactor();
+  }
+
+  bool SurfacePropertySurroundingSurfaces::setGroundTemperatureSchedule(Schedule& schedule) {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->setGroundTemperatureSchedule(schedule);
+  }
+
+  void SurfacePropertySurroundingSurfaces::resetGroundTemperatureSchedule() {
+    getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->resetGroundTemperatureSchedule();
+  }
+
+  boost::optional<SurfacePropertyLocalEnvironment> SurfacePropertySurroundingSurfaces::surfacePropertyLocalEnvironment() const {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->surfacePropertyLocalEnvironment();
+  }
+
+  // Extensible fields
+
+  std::vector<SurroundingSurfaceGroup> SurfacePropertySurroundingSurfaces::surroundingSurfaceGroups() const {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->surroundingSurfaceGroups();
+  }
+
+  unsigned int SurfacePropertySurroundingSurfaces::numberofSurroundingSurfaceGroups() const {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->numberofSurroundingSurfaceGroups();
+  }
+
+  boost::optional<unsigned>
+    SurfacePropertySurroundingSurfaces::surroundingSurfaceGroupIndex(const SurroundingSurfaceGroup& surroundingSurfaceGroup) const {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->surroundingSurfaceGroupIndex(surroundingSurfaceGroup);
+  }
+  boost::optional<unsigned> SurfacePropertySurroundingSurfaces::surroundingSurfaceGroupIndex(const std::string& surroundingSurfaceName) const {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->surroundingSurfaceGroupIndex(surroundingSurfaceName);
+  }
+
+  boost::optional<SurroundingSurfaceGroup> SurfacePropertySurroundingSurfaces::getSurroundingSurfaceGroup(unsigned groupIndex) const {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->getSurroundingSurfaceGroup(groupIndex);
+  }
+
+  bool SurfacePropertySurroundingSurfaces::addSurroundingSurfaceGroup(const SurroundingSurfaceGroup& surroundingSurfaceGroup) {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->addSurroundingSurfaceGroup(surroundingSurfaceGroup);
+  }
+
+  // Overloads, it creates a SurroundingSurfaceGroup wrapper, then call `addSurroundingSurfaceGroup(const SurroundingSurfaceGroup& surroundingSurfaceGroup)`
+  bool SurfacePropertySurroundingSurfaces::addSurroundingSurfaceGroup(const std::string& surroundingSurfaceName, double viewFactor,
+                                                                      const Schedule& temperatureSchedule) {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->addSurroundingSurfaceGroup(surroundingSurfaceName, viewFactor,
+                                                                                                  temperatureSchedule);
+  }
+
+  bool SurfacePropertySurroundingSurfaces::addSurroundingSurfaceGroups(const std::vector<SurroundingSurfaceGroup>& surroundingSurfaceGroups) {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->addSurroundingSurfaceGroups(surroundingSurfaceGroups);
+  }
+
+  bool SurfacePropertySurroundingSurfaces::removeSurroundingSurfaceGroup(unsigned groupIndex) {
+    return getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->removeSurroundingSurfaceGroup(groupIndex);
+  }
+
+  void SurfacePropertySurroundingSurfaces::removeAllSurroundingSurfaceGroups() {
+    getImpl<detail::SurfacePropertySurroundingSurfaces_Impl>()->removeAllSurroundingSurfaceGroups();
+  }
+
+  /// @cond
+  SurfacePropertySurroundingSurfaces::SurfacePropertySurroundingSurfaces(std::shared_ptr<detail::SurfacePropertySurroundingSurfaces_Impl> impl)
+    : ModelObject(std::move(impl)) {}
+  /// @endcond
+
+}  // namespace model
+}  // namespace openstudio
diff --git a/src/model/SurfacePropertySurroundingSurfaces.hpp b/src/model/SurfacePropertySurroundingSurfaces.hpp
new file mode 100644
index 00000000000..0a5e88ef6e9
--- /dev/null
+++ b/src/model/SurfacePropertySurroundingSurfaces.hpp
@@ -0,0 +1,171 @@
+/***********************************************************************************************************************
+*  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_SURFACEPROPERTYSURROUNDINGSURFACES_HPP
+#define MODEL_SURFACEPROPERTYSURROUNDINGSURFACES_HPP
+
+#include "ModelAPI.hpp"
+#include "ModelObject.hpp"
+#include "Schedule.hpp"
+
+namespace openstudio {
+
+namespace model {
+
+  class SurfacePropertyLocalEnvironment;
+
+  namespace detail {
+
+    class SurfacePropertySurroundingSurfaces_Impl;
+
+  }  // namespace detail
+
+  /** This class implements an extensible group */
+  class MODEL_API SurroundingSurfaceGroup
+  {
+   public:
+    SurroundingSurfaceGroup(std::string surroundingSurfaceName, double viewFactor, const Schedule& temperatureSchedule);
+
+    std::string surroundingSurfaceName() const;
+    double viewFactor() const;
+    Schedule temperatureSchedule() const;
+
+   private:
+    // From
+    std::string m_surroundingSurfaceName;
+    double m_viewFactor;
+    Schedule m_tempSch;
+    REGISTER_LOGGER("openstudio.model.SurroundingSurfaceGroup");
+  };
+
+  // Overload operator<<
+  MODEL_API std::ostream& operator<<(std::ostream& out, const openstudio::model::SurroundingSurfaceGroup& surroundingSurfaceGroup);
+
+  /** SurfacePropertySurroundingSurfaces is a ModelObject that wraps the OpenStudio IDD object 'OS:SurfaceProperty:SurroundingSurfaces'. */
+  class MODEL_API SurfacePropertySurroundingSurfaces : public ModelObject
+  {
+   public:
+    /** @name Constructors and Destructors */
+    //@{
+
+    explicit SurfacePropertySurroundingSurfaces(const Model& model);
+
+    virtual ~SurfacePropertySurroundingSurfaces() {}
+
+    //@}
+
+    static IddObjectType iddObjectType();
+
+    /** @name Getters */
+    //@{
+
+    boost::optional<double> skyViewFactor() const;
+
+    bool isSkyViewFactorAutocalculated() const;
+
+    boost::optional<Schedule> skyTemperatureSchedule() const;
+
+    boost::optional<double> groundViewFactor() const;
+
+    bool isGroundViewFactorAutocalculated() const;
+
+    boost::optional<Schedule> groundTemperatureSchedule() const;
+
+    //@}
+    /** @name Setters */
+    //@{
+
+    bool setSkyViewFactor(double skyViewFactor);
+    void autocalculateSkyViewFactor();
+
+    bool setSkyTemperatureSchedule(Schedule& schedule);
+    void resetSkyTemperatureSchedule();
+
+    bool setGroundViewFactor(double groundViewFactor);
+    void autocalculateGroundViewFactor();
+
+    bool setGroundTemperatureSchedule(Schedule& schedule);
+    void resetGroundTemperatureSchedule();
+
+    //@}
+    /** @name Other */
+    //@{
+
+    // Helper to get the parent SurfaceProperty:LocalEnvironment object
+    boost::optional<SurfacePropertyLocalEnvironment> surfacePropertyLocalEnvironment() const;
+
+    // Handle this object's extensible fields.
+    std::vector<SurroundingSurfaceGroup> surroundingSurfaceGroups() const;
+
+    unsigned int numberofSurroundingSurfaceGroups() const;
+
+    /** Looks up by Surface Name (case-insensitive)  */
+    boost::optional<unsigned> surroundingSurfaceGroupIndex(const SurroundingSurfaceGroup& surroundingSurfaceGroup) const;
+    boost::optional<unsigned> surroundingSurfaceGroupIndex(const std::string& surroundingSurfaceName) const;
+
+    boost::optional<SurroundingSurfaceGroup> getSurroundingSurfaceGroup(unsigned groupIndex) const;
+
+    /** If a surroundingSurfaceGroup group is already present (cf `surroundingSurfaceGroupIndex()`), it will Warn and override the surroundingSurfaceGroup value */
+    bool addSurroundingSurfaceGroup(const SurroundingSurfaceGroup& surroundingSurfaceGroup);
+
+    // Overloads, it creates a SurroundingSurfaceGroup wrapper, then call `addSurroundingSurfaceGroup(const SurroundingSurfaceGroup& surroundingSurfaceGroup)`
+    bool addSurroundingSurfaceGroup(const std::string& surroundingSurfaceName, double viewFactor, const Schedule& temperatureSchedule);
+
+    bool addSurroundingSurfaceGroups(const std::vector<SurroundingSurfaceGroup>& surroundingSurfaceGroups);
+
+    bool removeSurroundingSurfaceGroup(unsigned groupIndex);
+
+    void removeAllSurroundingSurfaceGroups();
+
+    //@}
+   protected:
+    /// @cond
+    using ImplType = detail::SurfacePropertySurroundingSurfaces_Impl;
+
+    explicit SurfacePropertySurroundingSurfaces(std::shared_ptr<detail::SurfacePropertySurroundingSurfaces_Impl> impl);
+
+    friend class detail::SurfacePropertySurroundingSurfaces_Impl;
+    friend class Model;
+    friend class IdfObject;
+    friend class openstudio::detail::IdfObject_Impl;
+    /// @endcond
+   private:
+    REGISTER_LOGGER("openstudio.model.SurfacePropertySurroundingSurfaces");
+  };
+
+  /** \relates SurfacePropertySurroundingSurfaces*/
+  using OptionalSurfacePropertySurroundingSurfaces = boost::optional<SurfacePropertySurroundingSurfaces>;
+
+  /** \relates SurfacePropertySurroundingSurfaces*/
+  using SurfacePropertySurroundingSurfacesVector = std::vector<SurfacePropertySurroundingSurfaces>;
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_SURFACEPROPERTYSURROUNDINGSURFACES_HPP
diff --git a/src/model/SurfacePropertySurroundingSurfaces_Impl.hpp b/src/model/SurfacePropertySurroundingSurfaces_Impl.hpp
new file mode 100644
index 00000000000..28d00084451
--- /dev/null
+++ b/src/model/SurfacePropertySurroundingSurfaces_Impl.hpp
@@ -0,0 +1,139 @@
+/***********************************************************************************************************************
+*  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_SURFACEPROPERTYSURROUNDINGSURFACES_IMPL_HPP
+#define MODEL_SURFACEPROPERTYSURROUNDINGSURFACES_IMPL_HPP
+
+#include "ModelAPI.hpp"
+#include "ModelObject_Impl.hpp"
+
+namespace openstudio {
+namespace model {
+
+  class Schedule;
+  class SurroundingSurfaceGroup;
+  class SurfacePropertyLocalEnvironment;
+
+  namespace detail {
+
+    /** SurfacePropertySurroundingSurfaces_Impl is a ModelObject_Impl that is the implementation class for SurfacePropertySurroundingSurfaces.*/
+    class MODEL_API SurfacePropertySurroundingSurfaces_Impl : public ModelObject_Impl
+    {
+     public:
+      /** @name Constructors and Destructors */
+      //@{
+
+      SurfacePropertySurroundingSurfaces_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle);
+
+      SurfacePropertySurroundingSurfaces_Impl(const openstudio::detail::WorkspaceObject_Impl& other, Model_Impl* model, bool keepHandle);
+
+      SurfacePropertySurroundingSurfaces_Impl(const SurfacePropertySurroundingSurfaces_Impl& other, Model_Impl* model, bool keepHandle);
+
+      virtual ~SurfacePropertySurroundingSurfaces_Impl() {}
+
+      //@}
+      /** @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 */
+      //@{
+
+      boost::optional<double> skyViewFactor() const;
+      bool isSkyViewFactorAutocalculated() const;
+
+      boost::optional<Schedule> skyTemperatureSchedule() const;
+
+      boost::optional<double> groundViewFactor() const;
+      bool isGroundViewFactorAutocalculated() const;
+
+      boost::optional<Schedule> groundTemperatureSchedule() const;
+
+      //@}
+      /** @name Setters */
+      //@{
+
+      bool setSkyViewFactor(double skyViewFactor);
+      void autocalculateSkyViewFactor();
+
+      bool setSkyTemperatureSchedule(Schedule& schedule);
+      void resetSkyTemperatureSchedule();
+
+      bool setGroundViewFactor(double groundViewFactor);
+      void autocalculateGroundViewFactor();
+
+      bool setGroundTemperatureSchedule(Schedule& schedule);
+      void resetGroundTemperatureSchedule();
+
+      //@}
+      /** @name Other */
+      //@{
+
+      boost::optional<SurfacePropertyLocalEnvironment> surfacePropertyLocalEnvironment() const;
+
+      std::vector<SurroundingSurfaceGroup> surroundingSurfaceGroups() const;
+
+      unsigned int numberofSurroundingSurfaceGroups() const;
+
+      /** Looks up by Surface Name (case-insensitive)  */
+      boost::optional<unsigned> surroundingSurfaceGroupIndex(const SurroundingSurfaceGroup& surroundingSurfaceGroup) const;
+      boost::optional<unsigned> surroundingSurfaceGroupIndex(const std::string& surroundingSurfaceName) const;
+
+      boost::optional<SurroundingSurfaceGroup> getSurroundingSurfaceGroup(unsigned groupIndex) const;
+
+      /** If a surroundingSurfaceGroup group is already present (cf `surroundingSurfaceGroupIndex()`), it will Warn and override the surroundingSurfaceGroup value */
+      bool addSurroundingSurfaceGroup(const SurroundingSurfaceGroup& surroundingSurfaceGroup);
+
+      // Overloads, it creates a SurroundingSurfaceGroup wrapper, then call `addSurroundingSurfaceGroup(const SurroundingSurfaceGroup& surroundingSurfaceGroup)`
+      bool addSurroundingSurfaceGroup(const std::string& surroundingSurfaceName, double viewFactor, const Schedule& temperatureSchedule);
+
+      bool addSurroundingSurfaceGroups(const std::vector<SurroundingSurfaceGroup>& surroundingSurfaceGroups);
+
+      bool removeSurroundingSurfaceGroup(unsigned groupIndex);
+
+      void removeAllSurroundingSurfaceGroups();
+
+      //@}
+     protected:
+     private:
+      REGISTER_LOGGER("openstudio.model.SurfacePropertySurroundingSurfaces");
+    };
+
+  }  // namespace detail
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_SURFACEPROPERTYSURROUNDINGSURFACES_IMPL_HPP
diff --git a/src/model/Surface_Impl.hpp b/src/model/Surface_Impl.hpp
index d2a00f0f969..54c15ef8657 100644
--- a/src/model/Surface_Impl.hpp
+++ b/src/model/Surface_Impl.hpp
@@ -49,6 +49,7 @@ namespace model {
   class SurfacePropertyOtherSideCoefficients;
   class SurfacePropertyOtherSideConditionsModel;
   class SurfacePropertyConfectionCoefficients;
+  class SurfacePropertyLocalEnvironment;
   class FoundationKiva;
 
   namespace detail {
@@ -206,6 +207,8 @@ namespace model {
 
       boost::optional<SurfacePropertyConvectionCoefficients> surfacePropertyConvectionCoefficients() const;
 
+      boost::optional<SurfacePropertyLocalEnvironment> surfacePropertyLocalEnvironment() const;
+
       boost::optional<SurfacePropertyOtherSideCoefficients> surfacePropertyOtherSideCoefficients() const;
 
       bool setSurfacePropertyOtherSideCoefficients(SurfacePropertyOtherSideCoefficients& otherSideCoefficients);


Test patch:
diff --git a/src/model/test/SurfacePropertyLocalEnvironment_GTest.cpp b/src/model/test/SurfacePropertyLocalEnvironment_GTest.cpp
new file mode 100644
index 00000000000..091d4df42fd
--- /dev/null
+++ b/src/model/test/SurfacePropertyLocalEnvironment_GTest.cpp
@@ -0,0 +1,132 @@
+/***********************************************************************************************************************
+*  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 "../SurfacePropertyLocalEnvironment.hpp"
+#include "../SurfacePropertyLocalEnvironment_Impl.hpp"
+#include "../Surface.hpp"
+#include "../SubSurface.hpp"
+#include "../Schedule.hpp"
+#include "../ScheduleConstant.hpp"
+#include "../SurfacePropertySurroundingSurfaces.hpp"
+
+#include "../../utilities/geometry/Point3d.hpp"
+
+using namespace openstudio;
+using namespace openstudio::model;
+
+TEST_F(ModelFixture, SurfacePropertyLocalEnvironment_GettersSetters) {
+  Model m;
+
+  double w = 10.0;
+  std::vector<Point3d> points{
+    {0, 0, 0},
+    {0, w, 0},
+    {w, w, 0},
+    {w, 0, 0},
+  };
+
+  Surface surface(points, m);
+
+  SurfacePropertyLocalEnvironment surfacePropertyLocalEnvironment(surface);
+  surfacePropertyLocalEnvironment.setName("My SurfacePropertyLocalEnvironment");
+
+  // Exterior Surface Name: Required Object
+  EXPECT_EQ(surface, surfacePropertyLocalEnvironment.exteriorSurface());
+  std::vector<Point3d> points2{
+    {0, 0, 2},
+    {0, w, 2},
+    {w, w, 2},
+    {w, 0, 2},
+  };
+  Surface surface2(points2, m);
+  EXPECT_FALSE(surface2.surfacePropertyLocalEnvironment());
+
+  EXPECT_TRUE(surfacePropertyLocalEnvironment.setExteriorSurface(surface2));
+  EXPECT_EQ(surface2, surfacePropertyLocalEnvironment.exteriorSurface());
+  ASSERT_TRUE(surfacePropertyLocalEnvironment.exteriorSurfaceAsSurface());
+  EXPECT_EQ(surface2, surfacePropertyLocalEnvironment.exteriorSurfaceAsSurface().get());
+  EXPECT_FALSE(surfacePropertyLocalEnvironment.exteriorSurfaceAsSubSurface());
+
+  ASSERT_TRUE(surface2.surfacePropertyLocalEnvironment());
+  EXPECT_EQ(surfacePropertyLocalEnvironment, surface2.surfacePropertyLocalEnvironment().get());
+
+  // External Shading Fraction Schedule Name: Optional Object
+  EXPECT_FALSE(surfacePropertyLocalEnvironment.externalShadingFractionSchedule());
+  ScheduleConstant shadingSch(m);
+  EXPECT_TRUE(surfacePropertyLocalEnvironment.setExternalShadingFractionSchedule(shadingSch));
+  ASSERT_TRUE(surfacePropertyLocalEnvironment.externalShadingFractionSchedule());
+  EXPECT_EQ(shadingSch, surfacePropertyLocalEnvironment.externalShadingFractionSchedule().get());
+  surfacePropertyLocalEnvironment.resetExternalShadingFractionSchedule();
+  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());
+
+  surfacePropertyLocalEnvironment.resetSurfacePropertySurroundingSurfaces();
+  EXPECT_FALSE(surfacePropertyLocalEnvironment.surfacePropertySurroundingSurfaces());
+
+  // It should also accept a SubSurface
+  SubSurface subSurface(points2, m);
+  EXPECT_TRUE(surface2.surfacePropertyLocalEnvironment());
+  EXPECT_FALSE(subSurface.surfacePropertyLocalEnvironment());
+
+  EXPECT_TRUE(surfacePropertyLocalEnvironment.setExteriorSurface(subSurface));
+
+  EXPECT_EQ(subSurface, surfacePropertyLocalEnvironment.exteriorSurface());
+  ASSERT_TRUE(surfacePropertyLocalEnvironment.exteriorSurfaceAsSubSurface());
+  EXPECT_EQ(subSurface, surfacePropertyLocalEnvironment.exteriorSurfaceAsSubSurface().get());
+  EXPECT_FALSE(surfacePropertyLocalEnvironment.exteriorSurfaceAsSurface());
+
+  EXPECT_FALSE(surface2.surfacePropertyLocalEnvironment());
+  ASSERT_TRUE(subSurface.surfacePropertyLocalEnvironment());
+  EXPECT_EQ(surfacePropertyLocalEnvironment, subSurface.surfacePropertyLocalEnvironment().get());
+
+  // Try to create a **second** LocalEnv for the **same** object: it should delete the initial one, to enforce unicity
+  EXPECT_EQ(1, m.getConcreteModelObjects<SurfacePropertyLocalEnvironment>().size());
+  SurfacePropertyLocalEnvironment surfacePropertyLocalEnvironment2(subSurface);
+  EXPECT_EQ(1, m.getConcreteModelObjects<SurfacePropertyLocalEnvironment>().size());
+  EXPECT_EQ(surfacePropertyLocalEnvironment2, m.getConcreteModelObjects<SurfacePropertyLocalEnvironment>()[0]);
+
+  // Outdoor Air Node Name: Optional Object
+  // boost::optional<OutdoorAirNode> obj(m);
+  // EXPECT_TRUE(surfacePropertyLocalEnvironment.setOutdoorAirNode(obj));
+  // ASSERT_TRUE(surfacePropertyLocalEnvironment.outdoorAirNode());
+  // EXPECT_EQ(obj, surfacePropertyLocalEnvironment.outdoorAirNode().get());
+}
diff --git a/src/model/test/SurfacePropertySurroundingSurfaces_GTest.cpp b/src/model/test/SurfacePropertySurroundingSurfaces_GTest.cpp
new file mode 100644
index 00000000000..c1230d4ec6c
--- /dev/null
+++ b/src/model/test/SurfacePropertySurroundingSurfaces_GTest.cpp
@@ -0,0 +1,211 @@
+/***********************************************************************************************************************
+*  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 "../SurfacePropertySurroundingSurfaces.hpp"
+#include "../SurfacePropertySurroundingSurfaces_Impl.hpp"
+
+#include "../ScheduleConstant.hpp"
+
+using namespace openstudio;
+using namespace openstudio::model;
+
+TEST_F(ModelFixture, SurfacePropertySurroundingSurfaces_GettersSetters) {
+  Model m;
+
+  SurfacePropertySurroundingSurfaces surfacePropertySurroundingSurfaces(m);
+
+  surfacePropertySurroundingSurfaces.setName("My SurfacePropertySurroundingSurfaces");
+
+  // Sky View Factor: Optional Double
+  EXPECT_TRUE(surfacePropertySurroundingSurfaces.isSkyViewFactorAutocalculated());
+
+  EXPECT_TRUE(surfacePropertySurroundingSurfaces.setSkyViewFactor(0.5));
+  ASSERT_TRUE(surfacePropertySurroundingSurfaces.skyViewFactor());
+  EXPECT_EQ(0.5, surfacePropertySurroundingSurfaces.skyViewFactor().get());
+  // Bad Value
+  EXPECT_FALSE(surfacePropertySurroundingSurfaces.setSkyViewFactor(-10.0));
+  ASSERT_TRUE(surfacePropertySurroundingSurfaces.skyViewFactor());
+  EXPECT_EQ(0.5, surfacePropertySurroundingSurfaces.skyViewFactor().get());
+  EXPECT_FALSE(surfacePropertySurroundingSurfaces.isSkyViewFactorAutocalculated());
+
+  surfacePropertySurroundingSurfaces.autocalculateSkyViewFactor();
+  EXPECT_TRUE(surfacePropertySurroundingSurfaces.isSkyViewFactorAutocalculated());
+
+  // Sky Temperature Schedule Name: Optional Object
+  EXPECT_FALSE(surfacePropertySurroundingSurfaces.skyTemperatureSchedule());
+  ScheduleConstant skyTemp(m);
+  skyTemp.setValue(25.0);
+  EXPECT_TRUE(surfacePropertySurroundingSurfaces.setSkyTemperatureSchedule(skyTemp));
+  ASSERT_TRUE(surfacePropertySurroundingSurfaces.skyTemperatureSchedule());
+  EXPECT_EQ(skyTemp, surfacePropertySurroundingSurfaces.skyTemperatureSchedule().get());
+  surfacePropertySurroundingSurfaces.resetSkyTemperatureSchedule();
+  EXPECT_FALSE(surfacePropertySurroundingSurfaces.skyTemperatureSchedule());
+
+  // Ground View Factor: Optional Double
+  EXPECT_TRUE(surfacePropertySurroundingSurfaces.isGroundViewFactorAutocalculated());
+
+  EXPECT_TRUE(surfacePropertySurroundingSurfaces.setGroundViewFactor(0.65));
+  ASSERT_TRUE(surfacePropertySurroundingSurfaces.groundViewFactor());
+  EXPECT_EQ(0.65, surfacePropertySurroundingSurfaces.groundViewFactor().get());
+  // Bad Value
+  EXPECT_FALSE(surfacePropertySurroundingSurfaces.setGroundViewFactor(-10.0));
+  ASSERT_TRUE(surfacePropertySurroundingSurfaces.groundViewFactor());
+  EXPECT_EQ(0.65, surfacePropertySurroundingSurfaces.groundViewFactor().get());
+  EXPECT_FALSE(surfacePropertySurroundingSurfaces.isGroundViewFactorAutocalculated());
+
+  surfacePropertySurroundingSurfaces.autocalculateGroundViewFactor();
+  EXPECT_TRUE(surfacePropertySurroundingSurfaces.isGroundViewFactorAutocalculated());
+
+  // Ground Temperature Schedule Name: Optional Object
+  EXPECT_FALSE(surfacePropertySurroundingSurfaces.skyTemperatureSchedule());
+  ScheduleConstant groundTemp(m);
+  groundTemp.setValue(25.0);
+  EXPECT_TRUE(surfacePropertySurroundingSurfaces.setGroundTemperatureSchedule(groundTemp));
+  ASSERT_TRUE(surfacePropertySurroundingSurfaces.groundTemperatureSchedule());
+  EXPECT_EQ(groundTemp, surfacePropertySurroundingSurfaces.groundTemperatureSchedule().get());
+  surfacePropertySurroundingSurfaces.resetGroundTemperatureSchedule();
+  EXPECT_FALSE(surfacePropertySurroundingSurfaces.skyTemperatureSchedule());
+}
+
+TEST_F(ModelFixture, SurfacePropertySurroundingSurfaces_SurroundingSurfaceGroups) {
+
+  Model m;
+  ScheduleConstant surfaceTempSch(m);
+  surfaceTempSch.setValue(25.0);
+
+  // Wrong viewFactor (0 to 1)
+  EXPECT_THROW(SurroundingSurfaceGroup("External Surface", 1.2, surfaceTempSch), openstudio::Exception);
+
+  // Name can't ve empty
+  EXPECT_THROW(SurroundingSurfaceGroup("External Surface", 1.2, surfaceTempSch), openstudio::Exception);
+
+  EXPECT_NO_THROW(SurroundingSurfaceGroup("External Surface", 0.2, surfaceTempSch));
+
+  SurfacePropertySurroundingSurfaces sp(m);
+
+  EXPECT_EQ(0, sp.numberofSurroundingSurfaceGroups());
+  EXPECT_TRUE(sp.addSurroundingSurfaceGroup("External Surface 1", 0.2, surfaceTempSch));
+  EXPECT_EQ(1, sp.numberofSurroundingSurfaceGroups());
+
+  auto group2 = SurroundingSurfaceGroup("External Surface 2", 0.3, surfaceTempSch);
+  EXPECT_TRUE(sp.addSurroundingSurfaceGroup(group2));
+  EXPECT_EQ(2, sp.numberofSurroundingSurfaceGroups());
+
+  ScheduleConstant surfaceTempSch2(m);
+  surfaceTempSch.setValue(35.0);
+  auto group3 = SurroundingSurfaceGroup("External Surface 3", 0.4, surfaceTempSch2);
+  EXPECT_TRUE(sp.addSurroundingSurfaceGroup(group3));
+  EXPECT_EQ(3, sp.numberofSurroundingSurfaceGroups());
+
+  boost::optional<SurroundingSurfaceGroup> group_ = sp.getSurroundingSurfaceGroup(1U);
+  ASSERT_TRUE(group_);
+  EXPECT_EQ("External Surface 2", group_->surroundingSurfaceName());
+  EXPECT_EQ(0.3, group_->viewFactor());
+  EXPECT_EQ(surfaceTempSch, group_->temperatureSchedule());
+
+  // Test that you cannot add the same group twice (based on Surface Name), but that instead it'll overwrite the values
+  auto group2bis = SurroundingSurfaceGroup("External Surface 2", 0.45, surfaceTempSch2);
+  // Test that we can locate an existing ViewFactor correctly (comparing on to/from only, not viewFactor value)
+  boost::optional<unsigned> _existingIndex = sp.surroundingSurfaceGroupIndex(group2bis);
+  ASSERT_TRUE(_existingIndex);
+  EXPECT_EQ(1U, _existingIndex.get());
+  // Test with the std::string version
+  _existingIndex = sp.surroundingSurfaceGroupIndex("External Surface 2");
+  ASSERT_TRUE(_existingIndex);
+  EXPECT_EQ(1U, _existingIndex.get());
+
+  // Now call add, which should jut override it
+  EXPECT_TRUE(sp.addSurroundingSurfaceGroup(group2bis));
+  // Should still have the same number
+  EXPECT_EQ(3, sp.numberofSurroundingSurfaceGroups());
+
+  // Retrieve it again, making sure it changed only the values viewFactor and Schedule
+  boost::optional<SurroundingSurfaceGroup> group2_ = sp.getSurroundingSurfaceGroup(1U);
+  ASSERT_TRUE(group2_);
+  EXPECT_EQ("External Surface 2", group2_->surroundingSurfaceName());
+  EXPECT_EQ(0.45, group2_->viewFactor());
+  EXPECT_EQ(surfaceTempSch2, group2_->temperatureSchedule());
+
+  // Via the overloaded method
+  EXPECT_TRUE(sp.addSurroundingSurfaceGroup("External Surface 2", 0.32, surfaceTempSch));
+  boost::optional<SurroundingSurfaceGroup> group3_ = sp.getSurroundingSurfaceGroup(1U);
+  ASSERT_TRUE(group3_);
+  EXPECT_EQ("External Surface 2", group3_->surroundingSurfaceName());
+  EXPECT_EQ(0.32, group3_->viewFactor());
+  EXPECT_EQ(surfaceTempSch, group3_->temperatureSchedule());
+
+  // Test that you cannot get a group by an index that's too high
+  EXPECT_FALSE(sp.getSurroundingSurfaceGroup(sp.numberofSurroundingSurfaceGroups()));
+
+  // Test that you cannot find a group if it doesn't exist
+  auto groupother = SurroundingSurfaceGroup("Another surface", 0.45, surfaceTempSch2);
+  EXPECT_FALSE(sp.surroundingSurfaceGroupIndex(groupother));
+
+  // Remove a viewFactor
+  EXPECT_FALSE(sp.removeSurroundingSurfaceGroup(1000));
+  EXPECT_EQ(3, sp.numberofSurroundingSurfaceGroups());
+
+  EXPECT_TRUE(sp.removeSurroundingSurfaceGroup(1));
+  EXPECT_EQ(2, sp.numberofSurroundingSurfaceGroups());
+
+  // check that remaining blocks moved correctly
+  std::vector<SurroundingSurfaceGroup> groups = sp.surroundingSurfaceGroups();
+  EXPECT_EQ(2U, groups.size());
+  EXPECT_EQ("External Surface 1", groups[0].surroundingSurfaceName());
+  EXPECT_EQ(0.2, groups[0].viewFactor());
+  EXPECT_EQ(surfaceTempSch, groups[0].temperatureSchedule());
+
+  EXPECT_EQ("External Surface 3", groups[1].surroundingSurfaceName());
+  EXPECT_EQ(0.4, groups[1].viewFactor());
+  EXPECT_EQ(surfaceTempSch2, groups[1].temperatureSchedule());
+
+  // more remove checking
+  sp.removeAllSurroundingSurfaceGroups();
+  EXPECT_EQ(0, sp.numberofSurroundingSurfaceGroups());
+  EXPECT_FALSE(sp.removeSurroundingSurfaceGroup(0));
+  EXPECT_EQ(0, sp.numberofSurroundingSurfaceGroups());
+
+  // Via a vector
+  EXPECT_TRUE(sp.addSurroundingSurfaceGroups({group2bis, groupother, group3}));
+  groups = sp.surroundingSurfaceGroups();
+  EXPECT_EQ(3U, groups.size());
+  EXPECT_EQ(group2bis.surroundingSurfaceName(), groups[0].surroundingSurfaceName());
+  EXPECT_EQ(group2bis.viewFactor(), groups[0].viewFactor());
+  EXPECT_EQ(group2bis.temperatureSchedule(), groups[0].temperatureSchedule());
+
+  EXPECT_EQ(groupother.surroundingSurfaceName(), groups[1].surroundingSurfaceName());
+  EXPECT_EQ(groupother.viewFactor(), groups[1].viewFactor());
+  EXPECT_EQ(groupother.temperatureSchedule(), groups[1].temperatureSchedule());
+
+  EXPECT_EQ(group3.surroundingSurfaceName(), groups[2].surroundingSurfaceName());
+  EXPECT_EQ(group3.viewFactor(), groups[2].viewFactor());
+  EXPECT_EQ(group3.temperatureSchedule(), groups[2].temperatureSchedule());
+}