OGS
BHE_2U.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_2U.h"
5
6#include <numbers>
7
9#include "Physics.h"
11
12namespace ProcessLib
13{
14namespace HeatTransportBHE
15{
16namespace BHE
17{
22 PipeConfigurationUType const& pipes,
23 bool const use_python_bcs)
25 pipes, use_python_bcs}
26{
27 // Initialize thermal resistances.
28 auto values = visit(
29 [&](auto const& control)
30 {
31 return control(refrigerant.reference_temperature,
32 0. /* initial time */);
33 },
35 updateHeatTransferCoefficients(values.flow_rate);
36}
37
38std::array<double, BHE_2U::number_of_unknowns> BHE_2U::pipeHeatCapacities()
39 const
40{
41 double const rho_r = refrigerant.density;
42 double const specific_heat_capacity = refrigerant.specific_heat_capacity;
43 double const rho_g = grout.rho_g;
44 double const porosity_g = grout.porosity_g;
45 double const heat_cap_g = grout.heat_cap_g;
46
47 return {{/*i1*/ rho_r * specific_heat_capacity,
48 /*i2*/ rho_r * specific_heat_capacity,
49 /*o1*/ rho_r * specific_heat_capacity,
50 /*o2*/ rho_r * specific_heat_capacity,
51 /*g1*/ (1.0 - porosity_g) * rho_g * heat_cap_g,
52 /*g2*/ (1.0 - porosity_g) * rho_g * heat_cap_g,
53 /*g3*/ (1.0 - porosity_g) * rho_g * heat_cap_g,
54 /*g4*/ (1.0 - porosity_g) * rho_g * heat_cap_g}};
55}
56
57std::array<double, BHE_2U::number_of_unknowns> BHE_2U::pipeHeatConductions(
58 int const section_index) const
59{
60 double const lambda_r = refrigerant.thermal_conductivity;
61 double const rho_r = refrigerant.density;
62 double const Cp_r = refrigerant.specific_heat_capacity;
63 double const alpha_L = _pipes.longitudinal_dispersion_length;
64 double const porosity_g = grout.porosity_g;
65 double const lambda_g = grout.lambda_g;
66
67 double const velocity_norm =
68 std::abs(getClampedFlowVelocity(section_index));
69
70 // Here we calculate the laplace coefficients in the governing
71 // equations of BHE. These governing equations can be found in
72 // 1) Diersch (2013) FEFLOW book on page 952, M.120-122, or
73 // 2) Diersch (2011) Comp & Geosci 37:1122-1135, Eq. 19-22.
74 auto const pipe_conduction =
75 lambda_r + rho_r * Cp_r * alpha_L * velocity_norm;
76 auto const grout_conduction = (1.0 - porosity_g) * lambda_g;
77 return {{pipe_conduction, // i1
78 pipe_conduction, // i2
79 pipe_conduction, // o1
80 pipe_conduction, // o2
81 grout_conduction, // g1
82 grout_conduction, // g2
83 grout_conduction, // g3
84 grout_conduction}}; // g4
85}
86
87std::array<Eigen::Vector3d, BHE_2U::number_of_unknowns>
88BHE_2U::pipeAdvectionVectors(Eigen::Vector3d const& /*elem_direction*/,
89 int const section_index) const
90{
91 double const rho_r = refrigerant.density;
92 double const Cp_r = refrigerant.specific_heat_capacity;
93
94 double const velocity = getClampedFlowVelocity(section_index);
95
96 Eigen::Vector3d const advection_downflow{0, 0, -rho_r * Cp_r * velocity};
97 Eigen::Vector3d const advection_upflow{0, 0, rho_r * Cp_r * velocity};
98 return {{advection_downflow, // i1
99 advection_downflow, // i2
100 advection_upflow, // o1
101 advection_upflow, // o2
102 {0, 0, 0}, // g1
103 {0, 0, 0}, // g2
104 {0, 0, 0}, // g3
105 {0, 0, 0}}}; // g4
106}
107
113std::array<double, 4> thermalResistancesGroutSoil2U(double const chi,
114 double const R_ar_1,
115 double const R_ar_2,
116 double const R_g)
117{
118 double R_gs = computeRgs(chi, R_g);
119 double R_gg_1 = computeRgg(chi, R_gs, R_ar_1, R_g);
120 double R_gg_2 = computeRgg(chi, R_gs, R_ar_2, R_g);
121 double chi_new = chi;
122
123 auto constraint = [&]()
124 { return 1.0 / ((1.0 / R_gg_1) + (1.0 / (2.0 * R_gs))); };
125
126 std::array<double, 3> const multiplier{chi * 2.0 / 3.0, chi * 1.0 / 3.0,
127 0.0};
128 for (double m_chi : multiplier)
129 {
130 if (constraint() >= 0)
131 {
132 break;
133 }
134 DBUG(
135 "Warning! Correction procedure was applied due to negative thermal "
136 "resistance! Chi = {:f}.\n",
137 m_chi);
138 R_gs = computeRgs(m_chi, R_g);
139 R_gg_1 = computeRgg(m_chi, R_gs, R_ar_1, R_g);
140 R_gg_2 = computeRgg(m_chi, R_gs, R_ar_2, R_g);
141 chi_new = m_chi;
142 }
143
144 return {chi_new, R_gg_1, R_gg_2, R_gs};
145}
146
147void BHE_2U::updateHeatTransferCoefficients(double const flow_rate)
148{
150 _pipes.inlet, borehole_geometry.length, refrigerant, flow_rate);
151
152 _flow_velocities = {tm_flow.velocity};
153
155 [&](int i)
156 { return calcThermalResistances(tm_flow.nusselt_number, i); });
157}
158
163 double const Nu, int const section_index) const
164{
165 constexpr double pi = std::numbers::pi;
166
167 double const lambda_r = refrigerant.thermal_conductivity;
168 double const lambda_g = grout.lambda_g;
169 double const lambda_p = _pipes.inlet.wall_thermal_conductivity;
170
171 // thermal resistances due to advective flow of refrigerant in the _pipes
172 // Eq. 36 in Diersch_2011_CG
173 double const R_adv_i = 1.0 / (Nu * lambda_r * pi);
174 double const R_adv_o = 1.0 / (Nu * lambda_r * pi);
175
176 // thermal resistance due to thermal conductivity of the pipe wall material
177 // Eq. 49
178 double const inlet_diameter = _pipes.inlet.diameter;
179 double const inlet_outside_diameter = _pipes.inlet.outsideDiameter();
180 double const R_con_a = std::log(inlet_outside_diameter / inlet_diameter) /
181 (2.0 * pi * lambda_p);
182
183 // the average outer diameter of the _pipes
184 double const d0 = _pipes.outlet.outsideDiameter();
185 double const D =
186 borehole_geometry.sections.diameterAtSection(section_index);
187 // Eq. 38
188 double const chi =
189 std::log(std::sqrt(D * D + 4 * d0 * d0) / 2 / std::sqrt(2) / d0) /
190 std::log(D / 2 / d0);
191 // Eq. 39
192 // thermal resistances of the grout
193 double const R_g =
194 std::acosh((D * D + d0 * d0 - 2 * _pipes.distance * _pipes.distance) /
195 (2 * D * d0)) /
196 (2 * pi * lambda_g) *
197 (3.098 - 4.432 * std::sqrt(2) * _pipes.distance / D +
198 2.364 * 2 * _pipes.distance * _pipes.distance / D / D);
199
200 // thermal resistance due to inter-grout exchange
201 double const R_ar_1 =
202 std::acosh((2.0 * _pipes.distance * _pipes.distance - d0 * d0) / d0 /
203 d0) /
204 (2.0 * pi * lambda_g);
205
206 double const R_ar_2 =
207 std::acosh((2.0 * 2.0 * _pipes.distance * _pipes.distance - d0 * d0) /
208 d0 / d0) /
209 (2.0 * pi * lambda_g);
210
211 auto const [chi_new, R_gg_1, R_gg_2, R_gs] =
212 thermalResistancesGroutSoil2U(chi, R_ar_1, R_ar_2, R_g);
213
214 // thermal resistance due to the grout transition.
215 double const R_con_b = chi_new * R_g;
216
217 // Eq. 29 and 30
218 double const R_fig = R_adv_i + R_con_a + R_con_b;
219 double const R_fog = R_adv_o + R_con_a + R_con_b;
220
221 return {R_fig, R_fog, R_gg_1, R_gg_2, R_gs};
222}
223
224std::array<std::pair<std::size_t /*node_id*/, int /*component*/>, 2>
226 std::size_t const top_node_id,
227 std::size_t const /*bottom_node_id*/,
228 int const in_component_id)
229{
230 return {std::make_pair(top_node_id, in_component_id),
231 std::make_pair(top_node_id, in_component_id + 2)};
232}
233
234std::optional<
235 std::array<std::pair<std::size_t /*node_id*/, int /*component*/>, 2>>
237 std::size_t const bottom_node_id,
238 int const in_component_id,
239 int const out_component_id)
240{
241 return {{std::make_pair(bottom_node_id, in_component_id),
242 std::make_pair(bottom_node_id, out_component_id)}};
243}
244
245std::array<double, BHE_2U::number_of_unknowns> BHE_2U::crossSectionAreas(
246 int const section_index) const
247{
248 // The borehole cross-section is divided equally among number_of_grout_zones
249 // quadrants; each grout zone occupies one quadrant minus the pipe wall.
250 double const quarter_borehole_area =
251 borehole_geometry.sections.areaAtSection(section_index) /
253 double const grout_area_inlet = checkedGroutArea(
254 quarter_borehole_area, _pipes.inlet.outsideArea(), section_index);
255 double const grout_area_outlet = checkedGroutArea(
256 quarter_borehole_area, _pipes.outlet.outsideArea(), section_index);
257
258 return {{
259 _pipes.inlet.area(), // i1
260 _pipes.inlet.area(), // i2
261 _pipes.outlet.area(), // o1
262 _pipes.outlet.area(), // o2
263 grout_area_inlet, // g1
264 grout_area_inlet, // g2
265 grout_area_outlet, // g3
266 grout_area_outlet, // g4
267 }};
268}
269
270double BHE_2U::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:72
void recomputeSectionalResistances(Fn &&calcForSection)
Recompute _sectional_thermal_resistances for all sections.
Definition BHECommon.h:117
FlowAndTemperatureControl const flowAndTemperatureControl
Definition BHECommon.h:74
double getClampedFlowVelocity(int const section_index) const
Get velocity for a section, clamping to last section if index exceeds the number of velocity entries....
Definition BHECommon.h:133
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_2U.cpp:225
void updateHeatTransferCoefficients(double const flow_rate)
Definition BHE_2U.cpp:147
double updateFlowRateAndTemperature(double T_out, double current_time)
Return the inflow temperature for the boundary condition.
Definition BHE_2U.cpp:270
std::array< double, number_of_unknowns > pipeHeatCapacities() const
Definition BHE_2U.cpp:38
std::vector< double > calcThermalResistances(double const Nu, int const section_index=0) const
Definition BHE_2U.cpp:162
BHE_2U(BoreholeGeometry const &borehole, RefrigerantProperties const &refrigerant, GroutParameters const &grout, FlowAndTemperatureControl const &flowAndTemperatureControl, PipeConfigurationUType const &pipes, bool const use_python_bcs)
Definition BHE_2U.cpp:18
std::array< double, number_of_unknowns > crossSectionAreas(int const section_index=0) const
Definition BHE_2U.cpp:245
std::array< double, number_of_unknowns > pipeHeatConductions(int const section_index=0) const
Definition BHE_2U.cpp:57
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_2U.cpp:236
static constexpr int number_of_grout_zones
Definition BHE_2U.h:53
std::array< Eigen::Vector3d, number_of_unknowns > pipeAdvectionVectors(Eigen::Vector3d const &, int const section_index=0) const
Definition BHE_2U.cpp:88
double checkedGroutArea(double const borehole_area_fraction, double const pipe_outside_area, int const section_index)
Definition BHECommon.h:40
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.
ThermoMechanicalFlowProperties calculateThermoMechanicalFlowPropertiesPipe(Pipe const &pipe, double const length, RefrigerantProperties const &fluid, double const flow_rate)
std::array< double, 4 > thermalResistancesGroutSoil2U(double const chi, double const R_ar_1, double const R_ar_2, double const R_g)
Definition BHE_2U.cpp:113