Skip to content

Commit

Permalink
Merge pull request #4932 from NREL/ghx-vert
Browse files Browse the repository at this point in the history
Support undisturbed ground temperature models on GroundHeatExchangerVertical
  • Loading branch information
joseph-robertson authored Aug 1, 2023
2 parents 84bd57c + c10e1b7 commit 34180f2
Show file tree
Hide file tree
Showing 14 changed files with 655 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 6 additions & 2 deletions resources/model/OpenStudio.idd
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/energyplus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);

Expand All @@ -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);

Expand Down Expand Up @@ -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);

Expand Down
121 changes: 121 additions & 0 deletions src/energyplus/Test/GroundHeatExchangerVertical_GTest.cpp
Original file line number Diff line number Diff line change
@@ -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());
}
93 changes: 93 additions & 0 deletions src/model/GroundHeatExchangerVertical.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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)) {}
Expand Down
Loading

0 comments on commit 34180f2

Please sign in to comment.