Repository: NREL/OpenStudio (language: python)

Issue:
Support undisturbed ground temperature models on GroundHeatExchangerVertical
Enhancement Request
--------------
Do for `GroundHeatExchanger:Vertical` what was done for `GroundHeatExchanger:HorizontalTrench` in https://github.com/NREL/OpenStudio/pull/4717: add "Undisturbed Ground Temperature Model" field for which either the `Site:GroundTemperature:Undisturbed:KusudaAchenbach` or `Site:GroundTemperature:Undisturbed:Xing` object could be referenced.



Discussion / hints:

Fix patch:
diff --git a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_7_0_TDB.md b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_7_0_TDB.md
index 0f0bed8d4a0..3b1265716db 100644
--- a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_7_0_TDB.md
+++ b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_7_0_TDB.md
@@ -78,6 +78,9 @@ You can also refer to the [OpenStudio SDK Python Binding Version Compatibility M
     * Fix #4695 - AirLoopHVACUnitarySystem: Supply Air Flow Rate Method During <XXX> Operation should be set via related setters/autosize
     * Breaks the return of `supplyAirFlowRateMethodDuringCoolingOperation` and `supplyAirFlowRateMethodDuringHeatingOperation`: now returns `std::string` instead of `boost::optional<std::string>`
     * Deprecates many set/reset methods
+* [#4932](https://github.com/NREL/OpenStudio/pull/4932) - Support undisturbed ground temperature models on GroundHeatExchangerVertical
+    * Fix #4930 - Support undisturbed ground temperature models on GroundHeatExchangerVertical
+    * Update `GroundHeatExchanger:Vertical` to actually use the Ground Temeprature Model field
 
 ## Minor changes and bug fixes
 
diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd
index 6efd3a1187c..fb2b16ebe12 100644
--- a/resources/model/OpenStudio.idd
+++ b/resources/model/OpenStudio.idd
@@ -16671,8 +16671,8 @@ OS:DistrictHeating,
 
 OS:GroundHeatExchanger:Vertical,
         \extensible:2
-        \min-fields 21
-        \max-fields 219
+        \min-fields 22
+        \max-fields 220
         \memo Variable short time step vertical ground heat exchanger model based on
         \memo Yavuztruk, C., J.D.Spitler. 1999. A Short Time Step response Factor Model for
         \memo Vertical Ground Loop Heat Exchangers
@@ -16750,6 +16750,10 @@ OS:GroundHeatExchanger:Vertical,
   N13,  \field Maximum Length of Simulation
         \type real
         \minimum> 0.0
+  A5,   \field Undisturbed Ground Temperature Model
+        \required-field
+        \type object-list
+        \object-list UndisturbedGroundTempModels
   N14,  \field G-Function Reference Ratio
         \type real
         \units dimensionless
diff --git a/src/energyplus/CMakeLists.txt b/src/energyplus/CMakeLists.txt
index 1da5afc5462..c6430334ea3 100644
--- a/src/energyplus/CMakeLists.txt
+++ b/src/energyplus/CMakeLists.txt
@@ -735,6 +735,7 @@ set(${target_name}_test_src
   Test/GeneratorMicroTurbine_GTest.cpp
   Test/GeneratorWindTurbine_GTest.cpp
   Test/GroundHeatExchangerHorizontalTrench_GTest.cpp
+  Test/GroundHeatExchangerVertical_GTest.cpp
   Test/HeatExchangerDesiccantBalancedFlow_GTest.cpp
   Test/HeatExchangerDesiccantBalancedFlowPerformanceDataType1_GTest.cpp
   Test/HeatPumpAirToWaterFuelFired_GTest.cpp
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateGroundHeatExchangerVertical.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateGroundHeatExchangerVertical.cpp
index c7a817f066a..d573a1c6794 100644
--- a/src/energyplus/ForwardTranslator/ForwardTranslateGroundHeatExchangerVertical.cpp
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateGroundHeatExchangerVertical.cpp
@@ -15,7 +15,6 @@
 #include <utilities/idd/GroundHeatExchanger_System_FieldEnums.hxx>
 #include <utilities/idd/GroundHeatExchanger_Vertical_Properties_FieldEnums.hxx>
 #include <utilities/idd/GroundHeatExchanger_ResponseFactors_FieldEnums.hxx>
-#include <utilities/idd/Site_GroundTemperature_Undisturbed_KusudaAchenbach_FieldEnums.hxx>
 #include "../../utilities/idd/IddEnums.hpp"
 #include <utilities/idd/IddEnums.hxx>
 #include <utilities/idd/IddFactory.hxx>
@@ -91,6 +90,17 @@ namespace energyplus {
     // 1  { GroundHeatExchanger_ResponseFactorsExtensibleFields::gFunctionLn_T_Ts_Value, "gFunctionLn_T_Ts_Value", "g-Function Ln(T/Ts) Value"},
     // 2  { GroundHeatExchanger_ResponseFactorsExtensibleFields::gFunctiongValue, "gFunctiongValue", "g-Function g Value"},
 
+    // UndisturbedGroundTemperatureModelName, is required, so start by that
+    ModelObject undisturbedGroundTemperatureModel = modelObject.undisturbedGroundTemperatureModel();
+    boost::optional<IdfObject> _undisturbedGroundTemperatureModel = translateAndMapModelObject(undisturbedGroundTemperatureModel);
+    if (_undisturbedGroundTemperatureModel) {
+      s = _undisturbedGroundTemperatureModel->name().get();
+    } else {
+      LOG(Warn, modelObject.briefDescription() << " cannot be translated as its undisturbed ground temperature model object cannot be translated: "
+                                               << undisturbedGroundTemperatureModel.briefDescription() << ".");
+      return boost::none;
+    }
+
     // Name
     IdfObject idfObject = createRegisterAndNameIdfObject(openstudio::IddObjectType::GroundHeatExchanger_System, modelObject);
 
@@ -104,25 +114,29 @@ namespace energyplus {
       idfObject.setString(GroundHeatExchanger_SystemFields::OutletNodeName, temp->name().get());
     }
 
-    // Maximum Flow Rate
+    // Design Flow Rate
     if ((value = modelObject.designFlowRate())) {
       idfObject.setDouble(GroundHeatExchanger_SystemFields::DesignFlowRate, value.get());
     }
 
+    // Undisturbed Ground Temperature Model Type
     idfObject.setString(GroundHeatExchanger_SystemFields::UndisturbedGroundTemperatureModelType,
-                        "Site:GroundTemperature:Undisturbed:KusudaAchenbach");
+                        _undisturbedGroundTemperatureModel->iddObject().name());
 
-    auto groundModelName = modelObject.nameString() + " Ground Temps";
-    idfObject.setString(GroundHeatExchanger_SystemFields::UndisturbedGroundTemperatureModelName, groundModelName);
+    // Undisturbed Ground Temperature Model Name
+    idfObject.setString(GroundHeatExchanger_SystemFields::UndisturbedGroundTemperatureModelName, s.get());
 
+    // Ground Thermal Conductivity
     if ((value = modelObject.groundThermalConductivity())) {
       idfObject.setDouble(GroundHeatExchanger_SystemFields::GroundThermalConductivity, value.get());
     }
 
+    // Ground Thermal Heat Capacity
     if ((value = modelObject.groundThermalHeatCapacity())) {
       idfObject.setDouble(GroundHeatExchanger_SystemFields::GroundThermalHeatCapacity, value.get());
     }
 
+    // GHE:Vertical:ResponseFactors Object Name
     auto responseFactorsObjectName = modelObject.nameString() + " Response Factors";
     idfObject.setString(GroundHeatExchanger_SystemFields::GHE_Vertical_ResponseFactorsObjectName, responseFactorsObjectName);
 
@@ -166,29 +180,6 @@ namespace energyplus {
       propertiesIdfObject.setDouble(GroundHeatExchanger_Vertical_PropertiesFields::UTubeDistance, value.get());
     }
 
-    IdfObject groundIdfObject(IddObjectType::Site_GroundTemperature_Undisturbed_KusudaAchenbach);
-    m_idfObjects.push_back(groundIdfObject);
-
-    groundIdfObject.setName(groundModelName);
-
-    if ((value = modelObject.groundThermalConductivity())) {
-      groundIdfObject.setDouble(Site_GroundTemperature_Undisturbed_KusudaAchenbachFields::SoilThermalConductivity, value.get());
-    }
-
-    groundIdfObject.setDouble(Site_GroundTemperature_Undisturbed_KusudaAchenbachFields::SoilDensity, 920.0);
-
-    if ((value = modelObject.groundThermalHeatCapacity())) {
-      groundIdfObject.setDouble(Site_GroundTemperature_Undisturbed_KusudaAchenbachFields::SoilSpecificHeat, value.get() / 920.0);
-    }
-
-    if ((value = modelObject.groundTemperature())) {
-      groundIdfObject.setDouble(Site_GroundTemperature_Undisturbed_KusudaAchenbachFields::AverageSoilSurfaceTemperature, value.get());
-    }
-
-    groundIdfObject.setDouble(Site_GroundTemperature_Undisturbed_KusudaAchenbachFields::AverageAmplitudeofSurfaceTemperature, 3.2);
-
-    groundIdfObject.setDouble(Site_GroundTemperature_Undisturbed_KusudaAchenbachFields::PhaseShiftofMinimumSurfaceTemperature, 8.0);
-
     IdfObject rfIdfObject(IddObjectType::GroundHeatExchanger_ResponseFactors);
     m_idfObjects.push_back(rfIdfObject);
 
diff --git a/src/energyplus/Test/GroundHeatExchangerVertical_GTest.cpp b/src/energyplus/Test/GroundHeatExchangerVertical_GTest.cpp
new file mode 100644
index 00000000000..f7f3b7e853f
--- /dev/null
+++ b/src/energyplus/Test/GroundHeatExchangerVertical_GTest.cpp
@@ -0,0 +1,121 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
+*  See also https://openstudio.net/license
+***********************************************************************************************************************/
+
+#include <gtest/gtest.h>
+#include "EnergyPlusFixture.hpp"
+
+#include "../ForwardTranslator.hpp"
+#include "../ReverseTranslator.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/GroundHeatExchangerVertical.hpp"
+#include "../../model/GroundHeatExchangerVertical_Impl.hpp"
+#include "../../model/PlantLoop.hpp"
+#include "../../model/Node.hpp"
+#include "../../model/Node_Impl.hpp"
+
+#include "../../utilities/idf/IdfFile.hpp"
+#include "../../utilities/idf/Workspace.hpp"
+#include "../../utilities/idf/IdfObject.hpp"
+#include "../../utilities/idf/WorkspaceObject.hpp"
+
+#include <utilities/idd/GroundHeatExchanger_System_FieldEnums.hxx>
+#include <utilities/idd/Site_GroundTemperature_Undisturbed_KusudaAchenbach_FieldEnums.hxx>
+#include <utilities/idd/GroundHeatExchanger_ResponseFactors_FieldEnums.hxx>
+#include <utilities/idd/GroundHeatExchanger_Vertical_Properties_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::energyplus;
+using namespace openstudio::model;
+using namespace openstudio;
+
+TEST_F(EnergyPlusFixture, ForwardTranslator_GroundHeatExchangerVertical) {
+
+  ForwardTranslator ft;
+
+  // Create a model
+  Model m;
+
+  GroundHeatExchangerVertical ghx(m);
+
+  EXPECT_TRUE(ghx.setDesignFlowRate(0.004));
+  EXPECT_TRUE(ghx.setNumberofBoreHoles(100));
+  EXPECT_TRUE(ghx.setBoreHoleLength(80.0));
+  EXPECT_TRUE(ghx.setBoreHoleRadius(0.7E-01));
+  EXPECT_TRUE(ghx.setGroundThermalConductivity(0.7));
+  EXPECT_TRUE(ghx.setGroundThermalHeatCapacity(0.3E+07));
+  EXPECT_TRUE(ghx.setGroundTemperature(14.0));
+  EXPECT_TRUE(ghx.setGroutThermalConductivity(0.7));
+  EXPECT_TRUE(ghx.setPipeThermalConductivity(0.4));
+  EXPECT_TRUE(ghx.setPipeOutDiameter(2.7E-02));
+  EXPECT_TRUE(ghx.setUTubeDistance(2.6E-02));
+  EXPECT_TRUE(ghx.setPipeThickness(2.5E-03));
+  EXPECT_TRUE(ghx.setMaximumLengthofSimulation(3));
+  EXPECT_TRUE(ghx.setGFunctionReferenceRatio(0.001));
+
+  PlantLoop p(m);
+  EXPECT_TRUE(p.addSupplyBranchForComponent(ghx));
+
+  ASSERT_TRUE(ghx.inletModelObject());
+  ASSERT_TRUE(ghx.inletModelObject()->optionalCast<Node>());
+  ghx.inletModelObject()->cast<Node>().setName("GHX Inlet Node");
+
+  ASSERT_TRUE(ghx.outletModelObject());
+  ASSERT_TRUE(ghx.outletModelObject()->optionalCast<Node>());
+  ghx.outletModelObject()->cast<Node>().setName("GHX Outlet Node");
+
+  const Workspace w = ft.translateModel(m);
+
+  WorkspaceObjectVector idfObjs = w.getObjectsByType(IddObjectType::GroundHeatExchanger_System);
+  ASSERT_EQ(1u, idfObjs.size());
+  auto idfObject = idfObjs.front();
+
+  EXPECT_EQ("Ground Heat Exchanger Vertical 1", idfObject.getString(GroundHeatExchanger_SystemFields::Name).get());
+  EXPECT_EQ("GHX Inlet Node", idfObject.getString(GroundHeatExchanger_SystemFields::InletNodeName).get());
+  EXPECT_EQ("GHX Outlet Node", idfObject.getString(GroundHeatExchanger_SystemFields::OutletNodeName).get());
+  EXPECT_EQ(0.004, idfObject.getDouble(GroundHeatExchanger_SystemFields::DesignFlowRate).get());
+
+  EXPECT_EQ("Site:GroundTemperature:Undisturbed:KusudaAchenbach",
+            idfObject.getString(GroundHeatExchanger_SystemFields::UndisturbedGroundTemperatureModelType).get());
+
+  ASSERT_TRUE(idfObject.getTarget(GroundHeatExchanger_SystemFields::UndisturbedGroundTemperatureModelName));
+  const WorkspaceObject kusuda = idfObject.getTarget(GroundHeatExchanger_SystemFields::UndisturbedGroundTemperatureModelName).get();
+  EXPECT_EQ(IddObjectType{IddObjectType::Site_GroundTemperature_Undisturbed_KusudaAchenbach}, kusuda.iddObject().type());
+
+  EXPECT_EQ(0.7, idfObject.getDouble(GroundHeatExchanger_SystemFields::GroundThermalConductivity).get());
+  EXPECT_EQ(0.3E+07, idfObject.getDouble(GroundHeatExchanger_SystemFields::GroundThermalHeatCapacity).get());
+
+  ASSERT_TRUE(idfObject.getTarget(GroundHeatExchanger_SystemFields::GHE_Vertical_ResponseFactorsObjectName));
+  const WorkspaceObject response = idfObject.getTarget(GroundHeatExchanger_SystemFields::GHE_Vertical_ResponseFactorsObjectName).get();
+  EXPECT_EQ(IddObjectType{IddObjectType::GroundHeatExchanger_ResponseFactors}, response.iddObject().type());
+
+  EXPECT_TRUE(idfObject.isEmpty(GroundHeatExchanger_SystemFields::gFunctionCalculationMethod));
+  ASSERT_FALSE(idfObject.getTarget(GroundHeatExchanger_SystemFields::GHE_Vertical_ArrayObjectName));
+
+  EXPECT_EQ(0.692626, kusuda.getDouble(Site_GroundTemperature_Undisturbed_KusudaAchenbachFields::SoilThermalConductivity).get());
+  EXPECT_EQ(920.0, kusuda.getDouble(Site_GroundTemperature_Undisturbed_KusudaAchenbachFields::SoilDensity).get());
+  EXPECT_DOUBLE_EQ(0.234700E+07 / 920.0, kusuda.getDouble(Site_GroundTemperature_Undisturbed_KusudaAchenbachFields::SoilSpecificHeat).get());
+  EXPECT_EQ(13.375, kusuda.getDouble(Site_GroundTemperature_Undisturbed_KusudaAchenbachFields::AverageSoilSurfaceTemperature).get());
+  EXPECT_EQ(3.2, kusuda.getDouble(Site_GroundTemperature_Undisturbed_KusudaAchenbachFields::AverageAmplitudeofSurfaceTemperature).get());
+  EXPECT_EQ(8.0, kusuda.getDouble(Site_GroundTemperature_Undisturbed_KusudaAchenbachFields::PhaseShiftofMinimumSurfaceTemperature).get());
+
+  ASSERT_TRUE(response.getTarget(GroundHeatExchanger_ResponseFactorsFields::GHE_Vertical_PropertiesObjectName));
+  const WorkspaceObject properties = response.getTarget(GroundHeatExchanger_ResponseFactorsFields::GHE_Vertical_PropertiesObjectName).get();
+  EXPECT_EQ(IddObjectType{IddObjectType::GroundHeatExchanger_Vertical_Properties}, properties.iddObject().type());
+
+  EXPECT_EQ(100, response.getDouble(GroundHeatExchanger_ResponseFactorsFields::NumberofBoreholes).get());
+  EXPECT_EQ(0.001, response.getDouble(GroundHeatExchanger_ResponseFactorsFields::GFunctionReferenceRatio).get());
+
+  EXPECT_EQ(1, properties.getDouble(GroundHeatExchanger_Vertical_PropertiesFields::DepthofTopofBorehole).get());
+  EXPECT_EQ(80.0, properties.getDouble(GroundHeatExchanger_Vertical_PropertiesFields::BoreholeLength).get());
+  EXPECT_EQ(0.7E-01 * 2, properties.getDouble(GroundHeatExchanger_Vertical_PropertiesFields::BoreholeDiameter).get());
+  EXPECT_EQ(0.7, properties.getDouble(GroundHeatExchanger_Vertical_PropertiesFields::GroutThermalConductivity).get());
+  EXPECT_EQ(3.90E+06, properties.getDouble(GroundHeatExchanger_Vertical_PropertiesFields::GroutThermalHeatCapacity).get());
+  EXPECT_EQ(0.4, properties.getDouble(GroundHeatExchanger_Vertical_PropertiesFields::PipeThermalConductivity).get());
+  EXPECT_EQ(1.77E+06, properties.getDouble(GroundHeatExchanger_Vertical_PropertiesFields::PipeThermalHeatCapacity).get());
+  EXPECT_EQ(2.7E-02, properties.getDouble(GroundHeatExchanger_Vertical_PropertiesFields::PipeOuterDiameter).get());
+  EXPECT_EQ(2.5E-03, properties.getDouble(GroundHeatExchanger_Vertical_PropertiesFields::PipeThickness).get());
+  EXPECT_EQ(2.6E-02, properties.getDouble(GroundHeatExchanger_Vertical_PropertiesFields::UTubeDistance).get());
+}
diff --git a/src/model/GroundHeatExchangerVertical.cpp b/src/model/GroundHeatExchangerVertical.cpp
index 4adba7f9b5a..75ffb69dd9f 100644
--- a/src/model/GroundHeatExchangerVertical.cpp
+++ b/src/model/GroundHeatExchangerVertical.cpp
@@ -9,6 +9,8 @@
 #include "Node_Impl.hpp"
 #include "Model.hpp"
 #include "Model_Impl.hpp"
+#include "SiteGroundTemperatureUndisturbedKusudaAchenbach.hpp"
+#include "SiteGroundTemperatureUndisturbedKusudaAchenbach_Impl.hpp"
 
 #include "../utilities/core/Assert.hpp"
 #include "../utilities/data/DataEnums.hpp"
@@ -113,6 +115,14 @@ namespace model {
       return isEmpty(OS_GroundHeatExchanger_VerticalFields::GFunctionReferenceRatio);
     }
 
+    ModelObject GroundHeatExchangerVertical_Impl::undisturbedGroundTemperatureModel() const {
+      boost::optional<ModelObject> modelObject;
+      modelObject =
+        getObject<ModelObject>().getModelObjectTarget<ModelObject>(OS_GroundHeatExchanger_VerticalFields::UndisturbedGroundTemperatureModel);
+      OS_ASSERT(modelObject);
+      return modelObject.get();
+    }
+
     bool GroundHeatExchangerVertical_Impl::setNumberofBoreHoles(boost::optional<int> numberofBoreHoles) {
       bool result(false);
       if (numberofBoreHoles) {
@@ -319,6 +329,11 @@ namespace model {
       OS_ASSERT(result);
     }
 
+    bool GroundHeatExchangerVertical_Impl::setUndisturbedGroundTemperatureModel(const ModelObject& undisturbedGroundTemperatureModel) {
+      bool result = setPointer(OS_GroundHeatExchanger_VerticalFields::UndisturbedGroundTemperatureModel, undisturbedGroundTemperatureModel.handle());
+      return result;
+    }
+
     unsigned GroundHeatExchangerVertical_Impl::inletPort() const {
       return OS_GroundHeatExchanger_VerticalFields::InletNodeName;
     }
@@ -476,6 +491,76 @@ namespace model {
     addGFunction(2.028, 71.361);
     addGFunction(2.275, 71.79);
     addGFunction(3.003, 72.511);
+
+    SiteGroundTemperatureUndisturbedKusudaAchenbach undisturbedGroundTemperatureModel(model);
+    undisturbedGroundTemperatureModel.setSoilThermalConductivity(groundThermalConductivity().get());
+    undisturbedGroundTemperatureModel.setSoilDensity(920.0);
+    undisturbedGroundTemperatureModel.setSoilSpecificHeat(groundThermalHeatCapacity().get() / 920.0);
+    undisturbedGroundTemperatureModel.setAverageSoilSurfaceTemperature(groundTemperature().get());
+    undisturbedGroundTemperatureModel.setAverageAmplitudeofSurfaceTemperature(3.2);
+    undisturbedGroundTemperatureModel.setPhaseShiftofMinimumSurfaceTemperature(8.0);
+    setUndisturbedGroundTemperatureModel(undisturbedGroundTemperatureModel);
+  }
+
+  GroundHeatExchangerVertical::GroundHeatExchangerVertical(const Model& model, const ModelObject& undisturbedGroundTemperatureModel)
+    : StraightComponent(GroundHeatExchangerVertical::iddObjectType(), model) {
+    OS_ASSERT(getImpl<detail::GroundHeatExchangerVertical_Impl>());
+
+    bool ok = setUndisturbedGroundTemperatureModel(undisturbedGroundTemperatureModel);
+    if (!ok) {
+      remove();
+      LOG_AND_THROW("Unable to set " << briefDescription() << "'s Undisturbed Ground Temperature Model to "
+                                     << undisturbedGroundTemperatureModel.briefDescription() << ".");
+    }
+    setNumberofBoreHoles(120);
+    setBoreHoleLength(76.2);
+    setBoreHoleRadius(0.635080E-01);
+    setGroundThermalConductivity(0.692626);
+    setGroundThermalHeatCapacity(0.234700E+07);
+    setGroundTemperature(13.375);
+    setDesignFlowRate(0.0033);
+    setGroutThermalConductivity(0.692626);
+    setPipeThermalConductivity(0.391312);
+    setPipeOutDiameter(2.66667E-02);
+    setUTubeDistance(2.53977E-02);
+    setPipeThickness(2.41285E-03);
+    setMaximumLengthofSimulation(2);
+    setGFunctionReferenceRatio(0.0005);
+    addGFunction(-15.2996, -0.348322);
+    addGFunction(-14.201, 0.022208);
+    addGFunction(-13.2202, 0.412345);
+    addGFunction(-12.2086, 0.867498);
+    addGFunction(-11.1888, 1.357839);
+    addGFunction(-10.1816, 1.852024);
+    addGFunction(-9.1815, 2.345656);
+    addGFunction(-8.6809, 2.593958);
+    addGFunction(-8.5, 2.679);
+    addGFunction(-7.8, 3.023);
+    addGFunction(-7.2, 3.32);
+    addGFunction(-6.5, 3.681);
+    addGFunction(-5.9, 4.071);
+    addGFunction(-5.2, 4.828);
+    addGFunction(-4.5, 6.253);
+    addGFunction(-3.963, 7.894);
+    addGFunction(-3.27, 11.82);
+    addGFunction(-2.864, 15.117);
+    addGFunction(-2.577, 18.006);
+    addGFunction(-2.171, 22.887);
+    addGFunction(-1.884, 26.924);
+    addGFunction(-1.191, 38.004);
+    addGFunction(-0.497, 49.919);
+    addGFunction(-0.274, 53.407);
+    addGFunction(-0.051, 56.632);
+    addGFunction(0.196, 59.825);
+    addGFunction(0.419, 62.349);
+    addGFunction(0.642, 64.524);
+    addGFunction(0.873, 66.412);
+    addGFunction(1.112, 67.993);
+    addGFunction(1.335, 69.162);
+    addGFunction(1.679, 70.476);
+    addGFunction(2.028, 71.361);
+    addGFunction(2.275, 71.79);
+    addGFunction(3.003, 72.511);
   }
 
   IddObjectType GroundHeatExchangerVertical::iddObjectType() {
@@ -567,6 +652,10 @@ namespace model {
     return getImpl<detail::GroundHeatExchangerVertical_Impl>()->isGFunctionReferenceRatioDefaulted();
   }
 
+  ModelObject GroundHeatExchangerVertical::undisturbedGroundTemperatureModel() const {
+    return getImpl<detail::GroundHeatExchangerVertical_Impl>()->undisturbedGroundTemperatureModel();
+  }
+
   bool GroundHeatExchangerVertical::setNumberofBoreHoles(int numberofBoreHoles) {
     return getImpl<detail::GroundHeatExchangerVertical_Impl>()->setNumberofBoreHoles(numberofBoreHoles);
   }
@@ -675,6 +764,10 @@ namespace model {
     getImpl<detail::GroundHeatExchangerVertical_Impl>()->resetGFunctionReferenceRatio();
   }
 
+  bool GroundHeatExchangerVertical::setUndisturbedGroundTemperatureModel(const ModelObject& undisturbedGroundTemperatureModel) {
+    return getImpl<detail::GroundHeatExchangerVertical_Impl>()->setUndisturbedGroundTemperatureModel(undisturbedGroundTemperatureModel);
+  }
+
   /// @cond
   GroundHeatExchangerVertical::GroundHeatExchangerVertical(std::shared_ptr<detail::GroundHeatExchangerVertical_Impl> impl)
     : StraightComponent(std::move(impl)) {}
diff --git a/src/model/GroundHeatExchangerVertical.hpp b/src/model/GroundHeatExchangerVertical.hpp
index 19b5edecf23..54eb7e2c703 100644
--- a/src/model/GroundHeatExchangerVertical.hpp
+++ b/src/model/GroundHeatExchangerVertical.hpp
@@ -39,6 +39,8 @@ namespace model {
 
     explicit GroundHeatExchangerVertical(const Model& model);
 
+    explicit GroundHeatExchangerVertical(const Model& model, const ModelObject& undisturbedGroundTemperatureModel);
+
     virtual ~GroundHeatExchangerVertical() = default;
     // Default the copy and move operators because the virtual dtor is explicit
     GroundHeatExchangerVertical(const GroundHeatExchangerVertical& other) = default;
@@ -93,6 +95,8 @@ namespace model {
 
     bool isGFunctionReferenceRatioDefaulted() const;
 
+    ModelObject undisturbedGroundTemperatureModel() const;
+
     //@}
     /** @name Setters */
 
@@ -152,6 +156,8 @@ namespace model {
 
     void resetGFunctionReferenceRatio();
 
+    bool setUndisturbedGroundTemperatureModel(const ModelObject& undisturbedGroundTemperatureModel);
+
     //@}
     /** @name Other */
     //@{
diff --git a/src/model/GroundHeatExchangerVertical_Impl.hpp b/src/model/GroundHeatExchangerVertical_Impl.hpp
index 2ea9d62a21c..20e318982bd 100644
--- a/src/model/GroundHeatExchangerVertical_Impl.hpp
+++ b/src/model/GroundHeatExchangerVertical_Impl.hpp
@@ -84,6 +84,8 @@ namespace model {
 
       bool isGFunctionReferenceRatioDefaulted() const;
 
+      ModelObject undisturbedGroundTemperatureModel() const;
+
       //@}
       /** @name Setters */
       //@{
@@ -142,6 +144,8 @@ namespace model {
 
       void resetGFunctionReferenceRatio();
 
+      bool setUndisturbedGroundTemperatureModel(const ModelObject& undisturbedGroundTemperatureModel);
+
       //@}
       /** @name Other */
       //@{
diff --git a/src/osversion/VersionTranslator.cpp b/src/osversion/VersionTranslator.cpp
index 996e94aefb9..74567e4c2d7 100644
--- a/src/osversion/VersionTranslator.cpp
+++ b/src/osversion/VersionTranslator.cpp
@@ -135,7 +135,8 @@ namespace osversion {
     m_updateMethods[VersionString("3.5.0")] = &VersionTranslator::update_3_4_0_to_3_5_0;
     m_updateMethods[VersionString("3.5.1")] = &VersionTranslator::update_3_5_0_to_3_5_1;
     m_updateMethods[VersionString("3.6.0")] = &VersionTranslator::update_3_5_1_to_3_6_0;
-    m_updateMethods[VersionString("3.7.0")] = &VersionTranslator::defaultUpdate;
+    m_updateMethods[VersionString("3.7.0")] = &VersionTranslator::update_3_6_1_to_3_7_0;
+    // m_updateMethods[VersionString("3.7.0")] = &VersionTranslator::defaultUpdate;
 
     // List of previous versions that may be updated to this one.
     //   - To increment the translator, add an entry for the version just released (branched for
@@ -7607,11 +7608,71 @@ namespace osversion {
 
   }  // end update_3_5_1_to_3_6_0
 
-  /*
-  std::string VersionTranslator::update_3_6_1_to_3_7_0(const IdfFile& idf_3_6_1, const IddFileAndFactoryWrapper& idd_3_7_0)
+  std::string VersionTranslator::update_3_6_1_to_3_7_0(const IdfFile& idf_3_6_1, const IddFileAndFactoryWrapper& idd_3_7_0) {
+    std::stringstream ss;
+    boost::optional<std::string> value;
+
+    ss << idf_3_6_1.header() << '\n' << '\n';
+    IdfFile targetIdf(idd_3_7_0.iddFile());
+    ss << targetIdf.versionObject().get();
+
+    for (const IdfObject& object : idf_3_6_1.objects()) {
+      auto iddname = object.iddObject().name();
+
+      if (iddname == "OS:GroundHeatExchanger:Vertical") {
+
+        // 1 Field has been added from 3.6.1 to 3.7.0:
+        // -------------------------------------------
+        // * Undisturbed Ground Temperature Model * 17
+        auto iddObject = idd_3_7_0.getObject(iddname);
+        IdfObject ghxObject(iddObject.get());
+        IdfObject kusudaObject(idd_3_7_0.getObject("OS:Site:GroundTemperature:Undisturbed:KusudaAchenbach").get());
+
+        for (size_t i = 0; i < object.numFields(); ++i) {
+          if (i < 17) {
+            if ((value = object.getString(i))) {
+              ghxObject.setString(i, value.get());
+              if (i == 8) {  // Soil Thermal Conductivity
+                kusudaObject.setString(i - 6, value.get());
+              }
+              if (i == 10) {  // Average Soil Surface Temperature
+                kusudaObject.setString(i - 5, value.get());
+              }
+            }
+            if (boost::optional<double> _value = object.getDouble(i)) {
+              if (i == 9) {  // Soil Specific Heat
+                kusudaObject.setDouble(i - 5, _value.get() / 920.0);
+              }
+            }
+          } else {
+            if (i == 17) {  // Undisturbed Ground Temperature Model
+              ghxObject.setString(i, kusudaObject.getString(0).get());
+            }
+            if ((value = object.getString(i))) {
+              ghxObject.setString(i + 1, value.get());
+            }
+          }
+        }
+
+        kusudaObject.setDouble(3, 920.0);  // Soil Density
+        kusudaObject.setDouble(6, 3.2);    // Average Amplitude of Surface Temperature
+        kusudaObject.setDouble(7, 8.0);    // Phase Shift of Minimum Surface Temperature
+
+        m_refactored.push_back(RefactoredObjectData(object, ghxObject));
+        m_new.push_back(kusudaObject);
+
+        ss << ghxObject;
+        ss << kusudaObject;
+
+        // No-op
+      } else {
+        ss << object;
+      }
+    }
+
+    return ss.str();
 
   }  // end update_3_6_1_to_3_7_0
-  */
 
 }  // namespace osversion
 }  // namespace openstudio
diff --git a/src/osversion/VersionTranslator.hpp b/src/osversion/VersionTranslator.hpp
index 258d4aafe69..ca4a4d3b8a6 100644
--- a/src/osversion/VersionTranslator.hpp
+++ b/src/osversion/VersionTranslator.hpp
@@ -234,7 +234,7 @@ namespace osversion {
     std::string update_3_4_0_to_3_5_0(const IdfFile& idf_3_4_0, const IddFileAndFactoryWrapper& idd_3_5_0);
     std::string update_3_5_0_to_3_5_1(const IdfFile& idf_3_5_0, const IddFileAndFactoryWrapper& idd_3_5_1);
     std::string update_3_5_1_to_3_6_0(const IdfFile& idf_3_5_1, const IddFileAndFactoryWrapper& idd_3_6_0);
-    // std::string update_3_6_1_to_3_7_0(const IdfFile& idf_3_6_1, const IddFileAndFactoryWrapper& idd_3_7_0);
+    std::string update_3_6_1_to_3_7_0(const IdfFile& idf_3_6_1, const IddFileAndFactoryWrapper& idd_3_7_0);
 
     IdfObject updateUrlField_0_7_1_to_0_7_2(const IdfObject& object, unsigned index);
 


Test patch:
diff --git a/src/model/test/GroundHeatExchangerVertical_GTest.cpp b/src/model/test/GroundHeatExchangerVertical_GTest.cpp
index c974f15e6da..71d4db28d52 100644
--- a/src/model/test/GroundHeatExchangerVertical_GTest.cpp
+++ b/src/model/test/GroundHeatExchangerVertical_GTest.cpp
@@ -7,6 +7,10 @@
 #include "ModelFixture.hpp"
 #include "../GroundHeatExchangerVertical.hpp"
 #include "../GroundHeatExchangerVertical_Impl.hpp"
+#include "../SiteGroundTemperatureUndisturbedKusudaAchenbach.hpp"
+#include "../SiteGroundTemperatureUndisturbedKusudaAchenbach_Impl.hpp"
+#include "../SiteGroundTemperatureUndisturbedXing.hpp"
+#include "../SiteGroundTemperatureUndisturbedXing_Impl.hpp"
 #include "../AirLoopHVAC.hpp"
 #include "../PlantLoop.hpp"
 #include "../Node.hpp"
@@ -17,7 +21,7 @@
 using namespace openstudio;
 using namespace openstudio::model;
 
-TEST_F(ModelFixture, GroundHeatExchangerVertical_DefaultConstructor) {
+TEST_F(ModelFixture, GroundHeatExchangerVertical_GroundHeatExchangerVertical) {
   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
 
   ASSERT_EXIT(
@@ -28,6 +32,177 @@ TEST_F(ModelFixture, GroundHeatExchangerVertical_DefaultConstructor) {
       exit(0);
     },
     ::testing::ExitedWithCode(0), "");
+
+  {
+    Model m;
+    GroundHeatExchangerVertical gh(m);
+
+    ASSERT_TRUE(gh.designFlowRate());
+    EXPECT_EQ(0.0033, gh.designFlowRate().get());
+    ASSERT_TRUE(gh.numberofBoreHoles());
+    EXPECT_EQ(120, gh.numberofBoreHoles().get());
+    ASSERT_TRUE(gh.boreHoleLength());
+    EXPECT_EQ(76.2, gh.boreHoleLength().get());
+    ASSERT_TRUE(gh.boreHoleRadius());
+    EXPECT_EQ(0.635080E-01, gh.boreHoleRadius().get());
+    ASSERT_TRUE(gh.groundThermalConductivity());
+    EXPECT_EQ(0.692626, gh.groundThermalConductivity().get());
+    ASSERT_TRUE(gh.groundThermalHeatCapacity());
+    EXPECT_EQ(0.234700E+07, gh.groundThermalHeatCapacity().get());
+    ASSERT_TRUE(gh.groundTemperature());
+    EXPECT_EQ(13.375, gh.groundTemperature().get());
+    ASSERT_TRUE(gh.groutThermalConductivity());
+    EXPECT_EQ(0.692626, gh.groutThermalConductivity().get());
+    ASSERT_TRUE(gh.pipeThermalConductivity());
+    EXPECT_EQ(0.391312, gh.pipeThermalConductivity().get());
+    ASSERT_TRUE(gh.pipeOutDiameter());
+    EXPECT_EQ(2.66667E-02, gh.pipeOutDiameter().get());
+    ASSERT_TRUE(gh.uTubeDistance());
+    EXPECT_EQ(2.53977E-02, gh.uTubeDistance().get());
+    ASSERT_TRUE(gh.pipeThickness());
+    EXPECT_EQ(2.41285E-03, gh.pipeThickness().get());
+    ASSERT_TRUE(gh.maximumLengthofSimulation());
+    EXPECT_EQ(2, gh.maximumLengthofSimulation().get());
+    EXPECT_EQ(0.0005, gh.gFunctionReferenceRatio());
+    EXPECT_FALSE(gh.isGFunctionReferenceRatioDefaulted());
+    ModelObject undisturbedGroundTemperatureModel = gh.undisturbedGroundTemperatureModel();
+    boost::optional<SiteGroundTemperatureUndisturbedKusudaAchenbach> uka =
+      undisturbedGroundTemperatureModel.optionalCast<SiteGroundTemperatureUndisturbedKusudaAchenbach>();
+    ASSERT_TRUE(uka);
+  }
+
+  {
+    Model m;
+    SiteGroundTemperatureUndisturbedKusudaAchenbach sgt(m);
+    GroundHeatExchangerVertical gh(m, sgt);
+
+    ASSERT_TRUE(gh.designFlowRate());
+    EXPECT_EQ(0.0033, gh.designFlowRate().get());
+    ASSERT_TRUE(gh.numberofBoreHoles());
+    EXPECT_EQ(120, gh.numberofBoreHoles().get());
+    ASSERT_TRUE(gh.boreHoleLength());
+    EXPECT_EQ(76.2, gh.boreHoleLength().get());
+    ASSERT_TRUE(gh.boreHoleRadius());
+    EXPECT_EQ(0.635080E-01, gh.boreHoleRadius().get());
+    ASSERT_TRUE(gh.groundThermalConductivity());
+    EXPECT_EQ(0.692626, gh.groundThermalConductivity().get());
+    ASSERT_TRUE(gh.groundThermalHeatCapacity());
+    EXPECT_EQ(0.234700E+07, gh.groundThermalHeatCapacity().get());
+    ASSERT_TRUE(gh.groundTemperature());
+    EXPECT_EQ(13.375, gh.groundTemperature().get());
+    ASSERT_TRUE(gh.groutThermalConductivity());
+    EXPECT_EQ(0.692626, gh.groutThermalConductivity().get());
+    ASSERT_TRUE(gh.pipeThermalConductivity());
+    EXPECT_EQ(0.391312, gh.pipeThermalConductivity().get());
+    ASSERT_TRUE(gh.pipeOutDiameter());
+    EXPECT_EQ(2.66667E-02, gh.pipeOutDiameter().get());
+    ASSERT_TRUE(gh.uTubeDistance());
+    EXPECT_EQ(2.53977E-02, gh.uTubeDistance().get());
+    ASSERT_TRUE(gh.pipeThickness());
+    EXPECT_EQ(2.41285E-03, gh.pipeThickness().get());
+    ASSERT_TRUE(gh.maximumLengthofSimulation());
+    EXPECT_EQ(2, gh.maximumLengthofSimulation().get());
+    EXPECT_EQ(0.0005, gh.gFunctionReferenceRatio());
+    EXPECT_FALSE(gh.isGFunctionReferenceRatioDefaulted());
+    ModelObject undisturbedGroundTemperatureModel = gh.undisturbedGroundTemperatureModel();
+    boost::optional<SiteGroundTemperatureUndisturbedKusudaAchenbach> uka =
+      undisturbedGroundTemperatureModel.optionalCast<SiteGroundTemperatureUndisturbedKusudaAchenbach>();
+    ASSERT_TRUE(uka);
+    EXPECT_EQ(sgt, uka.get());
+  }
+}
+
+TEST_F(ModelFixture, GroundHeatExchangerVertical_SetGetFields) {
+  Model m;
+  GroundHeatExchangerVertical gh(m);
+
+  EXPECT_TRUE(gh.setDesignFlowRate(0.004));
+  EXPECT_TRUE(gh.setNumberofBoreHoles(100));
+  EXPECT_TRUE(gh.setBoreHoleLength(80.0));
+  EXPECT_TRUE(gh.setBoreHoleRadius(0.7E-01));
+  EXPECT_TRUE(gh.setGroundThermalConductivity(0.7));
+  EXPECT_TRUE(gh.setGroundThermalHeatCapacity(0.3E+07));
+  EXPECT_TRUE(gh.setGroundTemperature(14.0));
+  EXPECT_TRUE(gh.setGroutThermalConductivity(0.7));
+  EXPECT_TRUE(gh.setPipeThermalConductivity(0.4));
+  EXPECT_TRUE(gh.setPipeOutDiameter(2.7E-02));
+  EXPECT_TRUE(gh.setUTubeDistance(2.6E-02));
+  EXPECT_TRUE(gh.setPipeThickness(2.5E-03));
+  EXPECT_TRUE(gh.setMaximumLengthofSimulation(3));
+  EXPECT_TRUE(gh.setGFunctionReferenceRatio(0.001));
+
+  SiteGroundTemperatureUndisturbedKusudaAchenbach sgt(m);
+  EXPECT_TRUE(gh.setUndisturbedGroundTemperatureModel(sgt));
+
+  ASSERT_TRUE(gh.designFlowRate());
+  EXPECT_EQ(0.004, gh.designFlowRate().get());
+  ASSERT_TRUE(gh.numberofBoreHoles());
+  EXPECT_EQ(100, gh.numberofBoreHoles().get());
+  ASSERT_TRUE(gh.boreHoleLength());
+  EXPECT_EQ(80.0, gh.boreHoleLength().get());
+  ASSERT_TRUE(gh.boreHoleRadius());
+  EXPECT_EQ(0.7E-01, gh.boreHoleRadius().get());
+  ASSERT_TRUE(gh.groundThermalConductivity());
+  EXPECT_EQ(0.7, gh.groundThermalConductivity().get());
+  ASSERT_TRUE(gh.groundThermalHeatCapacity());
+  EXPECT_EQ(0.3E+07, gh.groundThermalHeatCapacity().get());
+  ASSERT_TRUE(gh.groundTemperature());
+  EXPECT_EQ(14.0, gh.groundTemperature().get());
+  ASSERT_TRUE(gh.groutThermalConductivity());
+  EXPECT_EQ(0.7, gh.groutThermalConductivity().get());
+  ASSERT_TRUE(gh.pipeThermalConductivity());
+  EXPECT_EQ(0.4, gh.pipeThermalConductivity().get());
+  ASSERT_TRUE(gh.pipeOutDiameter());
+  EXPECT_EQ(2.7E-02, gh.pipeOutDiameter().get());
+  ASSERT_TRUE(gh.uTubeDistance());
+  EXPECT_EQ(2.6E-02, gh.uTubeDistance().get());
+  ASSERT_TRUE(gh.pipeThickness());
+  EXPECT_EQ(2.5E-03, gh.pipeThickness().get());
+  ASSERT_TRUE(gh.maximumLengthofSimulation());
+  EXPECT_EQ(3, gh.maximumLengthofSimulation().get());
+  EXPECT_EQ(0.001, gh.gFunctionReferenceRatio());
+  EXPECT_FALSE(gh.isGFunctionReferenceRatioDefaulted());
+  ModelObject undisturbedGroundTemperatureModel = gh.undisturbedGroundTemperatureModel();
+  boost::optional<SiteGroundTemperatureUndisturbedKusudaAchenbach> uka =
+    undisturbedGroundTemperatureModel.optionalCast<SiteGroundTemperatureUndisturbedKusudaAchenbach>();
+  ASSERT_TRUE(uka);
+  EXPECT_EQ(sgt, uka.get());
+
+  SiteGroundTemperatureUndisturbedXing sgt2(m);
+  EXPECT_TRUE(gh.setUndisturbedGroundTemperatureModel(sgt2));
+
+  ASSERT_TRUE(gh.designFlowRate());
+  EXPECT_EQ(0.004, gh.designFlowRate().get());
+  ASSERT_TRUE(gh.numberofBoreHoles());
+  EXPECT_EQ(100, gh.numberofBoreHoles().get());
+  ASSERT_TRUE(gh.boreHoleLength());
+  EXPECT_EQ(80.0, gh.boreHoleLength().get());
+  ASSERT_TRUE(gh.boreHoleRadius());
+  EXPECT_EQ(0.7E-01, gh.boreHoleRadius().get());
+  ASSERT_TRUE(gh.groundThermalConductivity());
+  EXPECT_EQ(0.7, gh.groundThermalConductivity().get());
+  ASSERT_TRUE(gh.groundThermalHeatCapacity());
+  EXPECT_EQ(0.3E+07, gh.groundThermalHeatCapacity().get());
+  ASSERT_TRUE(gh.groundTemperature());
+  EXPECT_EQ(14.0, gh.groundTemperature().get());
+  ASSERT_TRUE(gh.groutThermalConductivity());
+  EXPECT_EQ(0.7, gh.groutThermalConductivity().get());
+  ASSERT_TRUE(gh.pipeThermalConductivity());
+  EXPECT_EQ(0.4, gh.pipeThermalConductivity().get());
+  ASSERT_TRUE(gh.pipeOutDiameter());
+  EXPECT_EQ(2.7E-02, gh.pipeOutDiameter().get());
+  ASSERT_TRUE(gh.uTubeDistance());
+  EXPECT_EQ(2.6E-02, gh.uTubeDistance().get());
+  ASSERT_TRUE(gh.pipeThickness());
+  EXPECT_EQ(2.5E-03, gh.pipeThickness().get());
+  ASSERT_TRUE(gh.maximumLengthofSimulation());
+  EXPECT_EQ(3, gh.maximumLengthofSimulation().get());
+  EXPECT_EQ(0.001, gh.gFunctionReferenceRatio());
+  EXPECT_FALSE(gh.isGFunctionReferenceRatioDefaulted());
+  ModelObject undisturbedGroundTemperatureModel2 = gh.undisturbedGroundTemperatureModel();
+  boost::optional<SiteGroundTemperatureUndisturbedXing> ux = undisturbedGroundTemperatureModel2.optionalCast<SiteGroundTemperatureUndisturbedXing>();
+  ASSERT_TRUE(ux);
+  EXPECT_EQ(sgt2, ux.get());
 }
 
 TEST_F(ModelFixture, GroundHeatExchangerVertical_Connections) {
diff --git a/src/osversion/test/3_7_0/test_vt_GroundHeatExchangerVertical.osm b/src/osversion/test/3_7_0/test_vt_GroundHeatExchangerVertical.osm
new file mode 100644
index 00000000000..7cc50fec2d9
--- /dev/null
+++ b/src/osversion/test/3_7_0/test_vt_GroundHeatExchangerVertical.osm
@@ -0,0 +1,95 @@
+
+OS:Version,
+  {44a788f8-5d7b-4751-a46e-fa7b6694d6fc}, !- Handle
+  3.6.1;                                  !- Version Identifier
+
+OS:GroundHeatExchanger:Vertical,
+  {780db985-9f76-43b6-97b0-a146527f06ac}, !- Handle
+  Ground Heat Exchanger Vertical 1,       !- Name
+  ,                                       !- Inlet Node Name
+  ,                                       !- Outlet Node Name
+  0.0033,                                 !- Design Flow Rate {m3/s}
+  120,                                    !- Number of Bore Holes
+  76.2,                                   !- Bore Hole Length {m}
+  0.063508,                               !- Bore Hole Radius {m}
+  0.692626,                               !- Ground Thermal Conductivity {W/m-K}
+  2347000,                                !- Ground Thermal Heat Capacity {J/m3-K}
+  13.375,                                 !- Ground Temperature {C}
+  0.692626,                               !- Grout Thermal Conductivity {W/m-K}
+  0.391312,                               !- Pipe Thermal Conductivity {W/m-K}
+  0.0266667,                              !- Pipe Out Diameter {m}
+  0.0253977,                              !- U-Tube Distance {m}
+  0.00241285,                             !- Pipe Thickness {m}
+  2,                                      !- Maximum Length of Simulation
+  0.0005,                                 !- G-Function Reference Ratio {dimensionless}
+  -15.2996,                               !- G-Function Ln(T/Ts) Value 1
+  -0.348322,                              !- G-Function G Value 1
+  -14.201,                                !- G-Function Ln(T/Ts) Value 2
+  0.022208,                               !- G-Function G Value 2
+  -13.2202,                               !- G-Function Ln(T/Ts) Value 3
+  0.412345,                               !- G-Function G Value 3
+  -12.2086,                               !- G-Function Ln(T/Ts) Value 4
+  0.867498,                               !- G-Function G Value 4
+  -11.1888,                               !- G-Function Ln(T/Ts) Value 5
+  1.357839,                               !- G-Function G Value 5
+  -10.1816,                               !- G-Function Ln(T/Ts) Value 6
+  1.852024,                               !- G-Function G Value 6
+  -9.1815,                                !- G-Function Ln(T/Ts) Value 7
+  2.345656,                               !- G-Function G Value 7
+  -8.6809,                                !- G-Function Ln(T/Ts) Value 8
+  2.593958,                               !- G-Function G Value 8
+  -8.5,                                   !- G-Function Ln(T/Ts) Value 9
+  2.679,                                  !- G-Function G Value 9
+  -7.8,                                   !- G-Function Ln(T/Ts) Value 10
+  3.023,                                  !- G-Function G Value 10
+  -7.2,                                   !- G-Function Ln(T/Ts) Value 11
+  3.32,                                   !- G-Function G Value 11
+  -6.5,                                   !- G-Function Ln(T/Ts) Value 12
+  3.681,                                  !- G-Function G Value 12
+  -5.9,                                   !- G-Function Ln(T/Ts) Value 13
+  4.071,                                  !- G-Function G Value 13
+  -5.2,                                   !- G-Function Ln(T/Ts) Value 14
+  4.828,                                  !- G-Function G Value 14
+  -4.5,                                   !- G-Function Ln(T/Ts) Value 15
+  6.253,                                  !- G-Function G Value 15
+  -3.963,                                 !- G-Function Ln(T/Ts) Value 16
+  7.894,                                  !- G-Function G Value 16
+  -3.27,                                  !- G-Function Ln(T/Ts) Value 17
+  11.82,                                  !- G-Function G Value 17
+  -2.864,                                 !- G-Function Ln(T/Ts) Value 18
+  15.117,                                 !- G-Function G Value 18
+  -2.577,                                 !- G-Function Ln(T/Ts) Value 19
+  18.006,                                 !- G-Function G Value 19
+  -2.171,                                 !- G-Function Ln(T/Ts) Value 20
+  22.887,                                 !- G-Function G Value 20
+  -1.884,                                 !- G-Function Ln(T/Ts) Value 21
+  26.924,                                 !- G-Function G Value 21
+  -1.191,                                 !- G-Function Ln(T/Ts) Value 22
+  38.004,                                 !- G-Function G Value 22
+  -0.497,                                 !- G-Function Ln(T/Ts) Value 23
+  49.919,                                 !- G-Function G Value 23
+  -0.274,                                 !- G-Function Ln(T/Ts) Value 24
+  53.407,                                 !- G-Function G Value 24
+  -0.051,                                 !- G-Function Ln(T/Ts) Value 25
+  56.632,                                 !- G-Function G Value 25
+  0.196,                                  !- G-Function Ln(T/Ts) Value 26
+  59.825,                                 !- G-Function G Value 26
+  0.419,                                  !- G-Function Ln(T/Ts) Value 27
+  62.349,                                 !- G-Function G Value 27
+  0.642,                                  !- G-Function Ln(T/Ts) Value 28
+  64.524,                                 !- G-Function G Value 28
+  0.873,                                  !- G-Function Ln(T/Ts) Value 29
+  66.412,                                 !- G-Function G Value 29
+  1.112,                                  !- G-Function Ln(T/Ts) Value 30
+  67.993,                                 !- G-Function G Value 30
+  1.335,                                  !- G-Function Ln(T/Ts) Value 31
+  69.162,                                 !- G-Function G Value 31
+  1.679,                                  !- G-Function Ln(T/Ts) Value 32
+  70.476,                                 !- G-Function G Value 32
+  2.028,                                  !- G-Function Ln(T/Ts) Value 33
+  71.361,                                 !- G-Function G Value 33
+  2.275,                                  !- G-Function Ln(T/Ts) Value 34
+  71.79,                                  !- G-Function G Value 34
+  3.003,                                  !- G-Function Ln(T/Ts) Value 35
+  72.511;                                 !- G-Function G Value 35
+
diff --git a/src/osversion/test/3_7_0/test_vt_GroundHeatExchangerVertical.rb b/src/osversion/test/3_7_0/test_vt_GroundHeatExchangerVertical.rb
new file mode 100644
index 00000000000..ae35d298e32
--- /dev/null
+++ b/src/osversion/test/3_7_0/test_vt_GroundHeatExchangerVertical.rb
@@ -0,0 +1,9 @@
+#require '/usr/local/openstudio-3.6.1/Ruby/openstudio'
+
+include OpenStudio::Model
+
+m = Model.new
+
+coil = GroundHeatExchangerVertical.new(m)
+
+m.save('test_vt_GroundHeatExchangerVertical.osm', true)
diff --git a/src/osversion/test/VersionTranslator_GTest.cpp b/src/osversion/test/VersionTranslator_GTest.cpp
index 89f617d00e8..dfacbb21b60 100644
--- a/src/osversion/test/VersionTranslator_GTest.cpp
+++ b/src/osversion/test/VersionTranslator_GTest.cpp
@@ -2492,3 +2492,59 @@ TEST_F(OSVersionFixture, update_3_5_1_to_3_6_0_GroundHeatExchangerHorizontalTren
   EXPECT_EQ(12.8, uka.getDouble(6).get());                                                      // Average Amplitude of Surface Temperature
   EXPECT_EQ(17.3, uka.getDouble(7).get());                                                      // Phase Shift of Minimum Surface Temperature
 }
+
+TEST_F(OSVersionFixture, update_3_6_1_to_3_7_0_GroundHeatExchangerVertical) {
+  openstudio::path path = resourcesPath() / toPath("osversion/3_7_0/test_vt_GroundHeatExchangerVertical.osm");
+  osversion::VersionTranslator vt;
+  boost::optional<model::Model> model = vt.loadModel(path);
+  ASSERT_TRUE(model) << "Failed to load " << path;
+
+  openstudio::path outPath = resourcesPath() / toPath("osversion/3_7_0/test_vt_GroundHeatExchangerVertical_updated.osm");
+  model->save(outPath, true);
+
+  std::vector<WorkspaceObject> ghxs = model->getObjectsByType("OS:GroundHeatExchanger:Vertical");
+  ASSERT_EQ(1u, ghxs.size());
+  WorkspaceObject ghx = ghxs[0];
+
+  EXPECT_EQ("Ground Heat Exchanger Vertical 1", ghx.getString(1).get());  // Name
+  EXPECT_TRUE(ghx.isEmpty(2));                                            // Inlet Node Name
+  EXPECT_TRUE(ghx.isEmpty(3));                                            // Outlet Node Name
+  EXPECT_EQ(0.0033, ghx.getDouble(4).get());                              // Design Flow Rate
+  EXPECT_EQ(120, ghx.getInt(5).get());                                    // Number of Bore Holes
+  EXPECT_EQ(76.2, ghx.getDouble(6).get());                                // Bore Hole Length
+  EXPECT_EQ(0.063508, ghx.getDouble(7).get());                            // Bore Hole Radius
+  EXPECT_EQ(0.692626, ghx.getDouble(8).get());                            // Ground Thermal Conductivity
+  EXPECT_EQ(2347000, ghx.getDouble(9).get());                             // Ground Thermal Heat Capacity
+  EXPECT_EQ(13.375, ghx.getDouble(10).get());                             // Ground Temperature
+  EXPECT_EQ(0.692626, ghx.getDouble(11).get());                           // Grout Thermal Conductivity
+  EXPECT_EQ(0.391312, ghx.getDouble(12).get());                           // Pipe Thermal Conductivity
+  EXPECT_EQ(0.0266667, ghx.getDouble(13).get());                          // Pipe Out Diameter
+  EXPECT_EQ(0.0253977, ghx.getDouble(14).get());                          // U-Tube Distance
+  EXPECT_EQ(0.00241285, ghx.getDouble(15).get());                         // Pipe Thickness
+  EXPECT_EQ(2, ghx.getInt(16).get());                                     // Maximum Length of Simulation
+  EXPECT_NE("", ghx.getString(17).get());                                 // Undisturbed Ground Temperature Model
+  EXPECT_EQ(0.0005, ghx.getDouble(18).get());                             // G-Function Reference Ratio {dimensionless}
+
+  EXPECT_EQ(35u, ghx.numExtensibleGroups());
+  auto eg1 = ghx.extensibleGroups()[0];
+  EXPECT_EQ(-15.2996, eg1.getDouble(0, false).get());   // G-Function Ln(T/Ts) Value 1
+  EXPECT_EQ(-0.348322, eg1.getDouble(1, false).get());  // G-Function G Value 1
+  auto eg35 = ghx.extensibleGroups()[34];
+  EXPECT_EQ(3.003, eg35.getDouble(0, false).get());   // G-Function Ln(T/Ts) Value 35
+  EXPECT_EQ(72.511, eg35.getDouble(1, false).get());  // G-Function G Value 35
+
+  std::vector<WorkspaceObject> ukas = model->getObjectsByType("OS:Site:GroundTemperature:Undisturbed:KusudaAchenbach");
+  ASSERT_EQ(1u, ukas.size());
+
+  ASSERT_TRUE(ghx.getTarget(17));
+  WorkspaceObject uka = ghx.getTarget(17).get();
+  EXPECT_EQ(uka.nameString(), ghx.getTarget(17)->nameString());
+  EXPECT_EQ(IddObjectType(IddObjectType::OS_Site_GroundTemperature_Undisturbed_KusudaAchenbach), uka.iddObject().type());
+  EXPECT_EQ("Site Ground Temperature Undisturbed Kusuda Achenbach 1", uka.getString(1).get());  // Name
+  EXPECT_EQ(0.692626, uka.getDouble(2).get());                                                  // Soil Thermal Conductivity
+  EXPECT_EQ(920.0, uka.getDouble(3).get());                                                     // Soil Density
+  EXPECT_DOUBLE_EQ(2347000.0 / 920.0, uka.getDouble(4).get());                                  // Soil Specific Heat
+  EXPECT_EQ(13.375, uka.getDouble(5).get());                                                    // Average Soil Surface Temperature
+  EXPECT_EQ(3.2, uka.getDouble(6).get());                                                       // Average Amplitude of Surface Temperature
+  EXPECT_EQ(8.0, uka.getDouble(7).get());                                                       // Phase Shift of Minimum Surface Temperature
+}