OGS
BHE_1U.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "BHE_1U.h"
5
6#include <numbers>
7
11#include "Physics.h"
13
14namespace ProcessLib
15{
16namespace HeatTransportBHE
17{
18namespace BHE
19{
24 PipeConfigurationUType const& pipes,
25 bool const use_python_bcs)
27 pipes, use_python_bcs}
28{
29 checkEqualPipeOutsideDiameters(_pipes.inlet, _pipes.outlet, "BHE 1U");
30 // Initialize thermal resistances.
31 auto values = visit(
32 [&](auto const& control)
33 {
34 return control(refrigerant.reference_temperature,
35 0. /* initial time */);
36 },
38 updateHeatTransferCoefficients(values.flow_rate);
39}
40
41std::array<double, BHE_1U::number_of_unknowns> BHE_1U::pipeHeatCapacities()
42 const
43{
44 double const rho_r = refrigerant.density;
45 double const specific_heat_capacity = refrigerant.specific_heat_capacity;
46 double const rho_g = grout.rho_g;
47 double const porosity_g = grout.porosity_g;
48 double const heat_cap_g = grout.heat_cap_g;
49
50 return {{/*i1*/ rho_r * specific_heat_capacity,
51 /*o1*/ rho_r * specific_heat_capacity,
52 /*g1*/ (1.0 - porosity_g) * rho_g * heat_cap_g,
53 /*g2*/ (1.0 - porosity_g) * rho_g * heat_cap_g}};
54}
55
56std::array<double, BHE_1U::number_of_unknowns> BHE_1U::pipeHeatConductions()
57 const
58{
59 double const lambda_r = refrigerant.thermal_conductivity;
60 double const rho_r = refrigerant.density;
61 double const Cp_r = refrigerant.specific_heat_capacity;
62 double const alpha_L = _pipes.longitudinal_dispersion_length;
63 double const porosity_g = grout.porosity_g;
64 double const lambda_g = grout.lambda_g;
65
66 double const velocity_norm = std::abs(flow_velocity);
67
68 // Here we calculate the laplace coefficients in the governing
69 // equations of BHE. These governing equations can be found in
70 // 1) Diersch (2013) FEFLOW book on page 952, M.120-122, or
71 // 2) Diersch (2011) Comp & Geosci 37:1122-1135, Eq. 19-22.
72 auto const pipe_conduction =
73 lambda_r + rho_r * Cp_r * alpha_L * velocity_norm;
74 auto const grout_conduction = (1.0 - porosity_g) * lambda_g;
75 return {{pipe_conduction, // i1
76 pipe_conduction, // o1
77 grout_conduction, // g1
78 grout_conduction}}; // g2
79}
80
81std::array<Eigen::Vector3d, BHE_1U::number_of_unknowns>
82BHE_1U::pipeAdvectionVectors(Eigen::Vector3d const& elem_direction) const
83{
84 double const& rho_r = refrigerant.density;
85 double const& Cp_r = refrigerant.specific_heat_capacity;
86
87 auto const legs = flowLegs();
88 auto leg_adv = [&](double const v_signed) -> Eigen::Vector3d
89 { return rho_r * Cp_r * v_signed * elem_direction; };
90
91 return {{leg_adv(legs[0]), // i1
92 leg_adv(legs[1]), // o1
93 {0, 0, 0}, // g1
94 {0, 0, 0}}}; // g2
95}
96
102std::array<double, 3> thermalResistancesGroutSoil(double const chi,
103 double const R_ar,
104 double const R_g)
105{
106 double R_gs = computeRgs(chi, R_g);
107 double R_gg = computeRgg(chi, R_gs, R_ar, R_g);
108 double new_chi = chi;
109
110 auto constraint = [&]()
111 { return 1.0 / ((1.0 / R_gg) + (1.0 / (2.0 * R_gs))); };
112
113 std::array<double, 3> const multiplier{chi * 2.0 / 3.0, chi * 1.0 / 3.0,
114 0.0};
115 for (double m_chi : multiplier)
116 {
117 if (constraint() >= 0)
118 {
119 break;
120 }
121 DBUG(
122 "Warning! Correction procedure was applied due to negative thermal "
123 "resistance! Chi = {:f}.\n",
124 m_chi);
125
126 R_gs = computeRgs(m_chi, R_g);
127 R_gg = computeRgg(m_chi, R_gs, R_ar, R_g);
128 new_chi = m_chi;
129 }
130
131 return {new_chi, R_gg, R_gs};
132}
133
134void BHE_1U::updateHeatTransferCoefficients(double const flow_rate)
135{
137 _pipes.inlet, borehole_geometry.length, refrigerant, flow_rate);
138
139 flow_velocity = tm_flow.velocity;
140 cached_nu_ = tm_flow.nusselt_number;
141}
142
143std::vector<double> BHE_1U::thermalResistances(
144 ParameterLib::SpatialPosition const& pos) const
145{
147}
148
151 double const Nu, ParameterLib::SpatialPosition const& pos) const
152{
153 constexpr double pi = std::numbers::pi;
154
155 double const lambda_r = refrigerant.thermal_conductivity;
156 double const lambda_g = grout.lambda_g;
157 // t=0.0: borehole properties are physically time-invariant; genuinely
158 // time-varying parameter types are rejected in createPipe.
159 double const lambda_p_inlet =
160 sampleStrictPositive(_pipes.inlet.wall_thermal_conductivity, 0.0, pos,
161 "inlet wall_thermal_conductivity");
162 double const lambda_p_outlet =
163 sampleStrictPositive(_pipes.outlet.wall_thermal_conductivity, 0.0, pos,
164 "outlet wall_thermal_conductivity");
165
166 // thermal resistances due to advective flow of refrigerant in the _pipes
167 // Eq. 36 in Diersch_2011_CG
168 double const R_adv_i1 = 1.0 / (Nu * lambda_r * pi);
169 double const R_adv_o1 = 1.0 / (Nu * lambda_r * pi);
170
171 // thermal resistance due to thermal conductivity of the pipe wall material
172 // Eq. 49
173 double const inlet_outside_diameter = _pipes.inlet.outsideDiameter();
174 double const R_con_a_inlet =
175 pipeWallThermalResistance(_pipes.inlet, lambda_p_inlet);
176 double const R_con_a_outlet =
177 pipeWallThermalResistance(_pipes.outlet, lambda_p_outlet);
178
179 // the average outer diameter of the _pipes
180 double const d0 = inlet_outside_diameter;
181 double const D = sampleStrictPositive(borehole_geometry.diameter, 0.0, pos,
182 "borehole_diameter");
183 // Context prefix shared by the acosh-argument checks below. `cause` names
184 // the physical degeneracy that drives the argument to <= 1 so the fatal
185 // message is actionable.
186 auto const geometry_context =
187 [&](std::string_view const equation, std::string_view const cause)
188 {
189 return uTypeGeometryContext(pos, D, d0, _pipes.distance, equation,
190 cause);
191 };
192 // Eq. 51: chi requires D > sqrt(2) * d0 so that log(D/(sqrt(2)*d0)) > 0.
193 checkBoreholeVsPipeDiameter(D, std::sqrt(2.0) * d0, pos,
194 "BHE 1U chi formula (Eq. 51)");
195 double const chi = std::log(std::sqrt(D * D + 2 * d0 * d0) / 2 / d0) /
196 std::log(D / std::sqrt(2) / d0);
197 // Eq. 52
198 // thermal resistances of the grout
199 double const acosh_arg_R_g =
200 (D * D + d0 * d0 - _pipes.distance * _pipes.distance) / (2 * D * d0);
202 acosh_arg_R_g,
203 geometry_context(
204 "BHE 1U R_g (Eq. 52)",
205 "The argument drops to <= 1 when a pipe reaches the borehole wall "
206 "(distance >= D - d0), giving a zero grout resistance R_g and an "
207 "infinite (1/R) assembly coefficient."));
208 double const R_g = std::acosh(acosh_arg_R_g) / (2 * pi * lambda_g) *
209 (1.601 - 0.888 * _pipes.distance / D);
210
211 // thermal resistance due to inter-grout exchange
212 double const acosh_arg_R_ar =
213 (2.0 * _pipes.distance * _pipes.distance - d0 * d0) / d0 / d0;
215 acosh_arg_R_ar,
216 geometry_context(
217 "BHE 1U R_ar",
218 "The argument drops to <= 1 when the pipes touch (distance <= d0), "
219 "giving a zero inter-grout resistance R_ar and an infinite (1/R) "
220 "assembly coefficient."));
221 double const R_ar = std::acosh(acosh_arg_R_ar) / (2.0 * pi * lambda_g);
222
223 auto const [chi_new, R_gg, R_gs] =
224 thermalResistancesGroutSoil(chi, R_ar, R_g);
225
226 // thermal resistance due to the grout transition.
227 double const R_con_b = chi_new * R_g;
228 // Eq. 29 and 30
229 double const R_fig = R_adv_i1 + R_con_a_inlet + R_con_b;
230 double const R_fog = R_adv_o1 + R_con_a_outlet + R_con_b;
231
232 return {R_fig, R_fog, R_gg, R_gs};
233}
234
235std::array<std::pair<std::size_t /*node_id*/, int /*component*/>, 2>
237 std::size_t const top_node_id,
238 std::size_t const /*bottom_node_id*/,
239 int const in_component_id)
240{
241 return {std::make_pair(top_node_id, in_component_id),
242 std::make_pair(top_node_id, in_component_id + 1)};
243}
244
245std::optional<
246 std::array<std::pair<std::size_t /*node_id*/, int /*component*/>, 2>>
248 std::size_t const bottom_node_id,
249 int const in_component_id,
250 int const out_component_id)
251{
252 return {{std::make_pair(bottom_node_id, in_component_id),
253 std::make_pair(bottom_node_id, out_component_id)}};
254}
255
256std::array<double, BHE_1U::number_of_unknowns> BHE_1U::crossSectionAreas(
257 ParameterLib::SpatialPosition const& pos) const
258{
259 double const D = sampleStrictPositive(borehole_geometry.diameter, 0.0, pos,
260 "borehole_diameter");
261 double const borehole_area = Pipe::circleArea(D);
262 double const half_borehole_area = borehole_area / number_of_grout_zones;
263 return {
264 {_pipes.inlet.area(), _pipes.outlet.area(),
265 checkedGroutArea(half_borehole_area, _pipes.inlet.outsideArea(), pos),
266 checkedGroutArea(half_borehole_area, _pipes.outlet.outsideArea(),
267 pos)}};
268}
269
270double BHE_1U::updateFlowRateAndTemperature(double const T_out,
271 double const current_time)
272{
273 auto values =
274 visit([&](auto const& control) { return control(T_out, current_time); },
276 updateHeatTransferCoefficients(values.flow_rate);
277 return values.temperature;
278}
279} // namespace BHE
280} // namespace HeatTransportBHE
281} // namespace ProcessLib
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22
BHECommonUType(BoreholeGeometry const &borehole, RefrigerantProperties const &refrigerant, GroutParameters const &grout, FlowAndTemperatureControl const &flowAndTemperatureControl, PipeConfigurationUType const &pipes, bool const use_python_bcs)
RefrigerantProperties const refrigerant
Definition BHECommon.h:51
FlowAndTemperatureControl const flowAndTemperatureControl
Definition BHECommon.h:53
double updateFlowRateAndTemperature(double T_out, double current_time)
Return the inflow temperature for the boundary condition.
Definition BHE_1U.cpp:270
std::vector< double > thermalResistances(ParameterLib::SpatialPosition const &pos) const
Definition BHE_1U.cpp:143
static std::optional< std::array< std::pair< std::size_t, int >, 2 > > getBHEBottomDirichletBCNodesAndComponents(std::size_t const bottom_node_id, int const in_component_id, int const out_component_id)
Definition BHE_1U.cpp:247
std::array< double, number_of_unknowns > pipeHeatConductions() const
Definition BHE_1U.cpp:56
std::vector< double > calcThermalResistances(double const Nu, ParameterLib::SpatialPosition const &pos) const
Nu is the Nusselt number.
Definition BHE_1U.cpp:150
static constexpr int number_of_grout_zones
Definition BHE_1U.h:50
void updateHeatTransferCoefficients(double const flow_rate)
Definition BHE_1U.cpp:134
BHE_1U(BoreholeGeometry const &borehole, RefrigerantProperties const &refrigerant, GroutParameters const &grout, FlowAndTemperatureControl const &flowAndTemperatureControl, PipeConfigurationUType const &pipes, bool const use_python_bcs)
Definition BHE_1U.cpp:20
static std::array< std::pair< std::size_t, int >, 2 > getBHEInflowDirichletBCNodesAndComponents(std::size_t const top_node_id, std::size_t const, int const in_component_id)
Definition BHE_1U.cpp:236
std::array< Eigen::Vector3d, number_of_unknowns > pipeAdvectionVectors(Eigen::Vector3d const &elem_direction) const
Definition BHE_1U.cpp:82
std::array< double, number_of_flow_legs > flowLegs() const
Definition BHE_1U.h:56
std::array< double, number_of_unknowns > pipeHeatCapacities() const
Definition BHE_1U.cpp:41
std::array< double, number_of_unknowns > crossSectionAreas(ParameterLib::SpatialPosition const &pos) const
Definition BHE_1U.cpp:256
void checkAcoshArg(double const arg, std::string_view const context)
double sampleStrictPositive(ParameterLib::Parameter< double > const &param, double const t, ParameterLib::SpatialPosition const &pos, std::string_view const param_role)
std::array< double, 3 > thermalResistancesGroutSoil(double const chi, double const R_ar, double const R_g)
Definition BHE_1U.cpp:102
void checkBoreholeVsPipeDiameter(double const D, double const min_diameter, ParameterLib::SpatialPosition const &pos, std::string_view const context)
std::string uTypeGeometryContext(ParameterLib::SpatialPosition const &pos, double const D, double const d0, double const distance, std::string_view const equation, std::string_view const cause)
double checkedGroutArea(double const borehole_area_fraction, double const pipe_outside_area, ParameterLib::SpatialPosition const &pos)
double computeRgg(double const chi, double const R_gs, double const R_ar, double const R_g)
std::variant< InflowTemperature, Power, BuildingPower, BuildingPowerHotWaterActiveCooling, BuildingPowerHotWaterPassiveCooling, BuildingPowerHotWater, BuildingPowerActiveCooling, BuildingPowerPassiveCooling, ActiveCooling > FlowAndTemperatureControl
double computeRgs(double const chi, double const R_g)
Grout-soil thermal resistance: R_gs = (1 - chi) * R_g.
void checkEqualPipeOutsideDiameters(Pipe const &inlet, Pipe const &outlet, std::string_view const context)
double pipeWallThermalResistance(Pipe const &pipe, double const wall_thermal_conductivity)
ThermoMechanicalFlowProperties calculateThermoMechanicalFlowPropertiesPipe(Pipe const &pipe, double const length, RefrigerantProperties const &fluid, double const flow_rate)
static double circleArea(double const d)
Definition Pipe.h:46