GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/test/multidomain/embedded/1d3d/root_soil_benchmark/problem_root.hh
Date: 2024-05-04 19:09:25
Exec Total Coverage
Lines: 92 107 86.0%
Functions: 7 12 58.3%
Branches: 86 198 43.4%

Line Branch Exec Source
1 // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 // vi: set et ts=4 sw=4 sts=4:
3 //
4 // SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5 // SPDX-License-Identifier: GPL-3.0-or-later
6 //
7 /*!
8 * \file
9 * \ingroup EmbeddedTests
10 * \brief The root problem for the benchmark cases C1.2a/b from Schnepf et al (2020) https://doi.org/10.3389/fpls.2020.00316
11 */
12 #ifndef DUMUX_TEST_ROOT_SOIL_BENCHMARK_ROOT_PROBLEM_HH
13 #define DUMUX_TEST_ROOT_SOIL_BENCHMARK_ROOT_PROBLEM_HH
14
15 #include <dumux/common/parameters.hh>
16 #include <dumux/common/properties.hh>
17 #include <dumux/common/boundarytypes.hh>
18 #include <dumux/common/numeqvector.hh>
19 #include <dumux/porousmediumflow/problem.hh>
20 #include <dumux/discretization/evalsolution.hh>
21 #include <dumux/discretization/elementsolution.hh>
22
23 #include "couplingreconstruction.hh"
24
25 namespace Dumux {
26
27 /*!
28 * \ingroup EmbeddedTests
29 * \brief The root problem for the benchmark cases C1.2a/b from Schnepf et al (2020) https://doi.org/10.3389/fpls.2020.00316
30 */
31 template <class TypeTag>
32 class RootProblem : public PorousMediumFlowProblem<TypeTag>
33 {
34 using ParentType = PorousMediumFlowProblem<TypeTag>;
35 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
36 using PointSource = GetPropType<TypeTag, Properties::PointSource>;
37 using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
38 using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
39 using NumEqVector = Dumux::NumEqVector<PrimaryVariables>;
40 using BoundaryTypes = Dumux::BoundaryTypes<PrimaryVariables::size()>;
41 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
42 using GridView = typename GridGeometry::GridView;
43 using FVElementGeometry = typename GridGeometry::LocalView;
44 using SubControlVolume = typename GridGeometry::SubControlVolume;
45 using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace;
46 using GlobalPosition = typename GridGeometry::GlobalCoordinate;
47 using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>;
48 using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
49 using Element = typename GridView::template Codim<0>::Entity;
50 using CouplingManager = GetPropType<TypeTag, Properties::CouplingManager>;
51
52 public:
53 enum BCType
54 { constCollarPressure, constTranspiration, cyclicTranspiration };
55
56 template<class SpatialParams>
57 2 RootProblem(std::shared_ptr<const GridGeometry> gridGeometry,
58 std::shared_ptr<SpatialParams> spatialParams,
59 std::shared_ptr<CouplingManager> couplingManager,
60 const GlobalPosition& domainSize)
61 : ParentType(gridGeometry, spatialParams, "Root")
62
6/20
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
8 , couplingManager_(couplingManager)
63 {
64 // read parameters from input file
65
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
4 name_ = getParamFromGroup<std::string>(this->paramGroup(), "Problem.Name");
66
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 criticalCollarPressure_ = getParam<Scalar>("BoundaryConditions.CriticalCollarPressure", -1.4e6); // in Pa
67
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 initialRootPressure_ = getParam<Scalar>("BoundaryConditions.InitialRootPressure", -1e5); // in Pa
68
1/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 dailyTranspirationRate_ = getParam<Scalar>("BoundaryConditions.DailyTranspirationRate", 1.0); // mm/day
69
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 dailyTranspirationRate_ *= domainSize[0]*domainSize[1]/86400.0; // kg/s (domain size in m, kg->g=mm->m)
70
71
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 const auto bcType = getParam<std::string>("BoundaryConditions.BoundaryType", "CyclicTranspiration");
72
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (bcType == "CyclicTranspiration") bcType_ = BCType::cyclicTranspiration;
73 else if (bcType == "ConstCollarPressure") bcType_ = BCType::constCollarPressure;
74 else if (bcType == "ConstTranspiration") bcType_ = BCType::constTranspiration;
75 else DUNE_THROW(Dune::InvalidStateException, "Unknown BCType: " << bcType);
76
77
1/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 bcSmoothingParam_ = getParam<Scalar>("BoundaryConditions.SmoothingK", 0.1);
78
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 kernelWidthFactor_ = getParam<Scalar>("MixedDimension.KernelWidthFactor");
79 2 }
80
81 const std::string& name() const
82
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 { return name_; }
83
84 BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const
85 {
86
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 116919 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78969 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
195888 BoundaryTypes values;
87 195888 values.setAllNeumann();
88
89
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 116919 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78969 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
195888 if (bcType_ == BCType::constCollarPressure)
90 if (globalPos[2] + eps_ > this->gridGeometry().bBoxMax()[2])
91 values.setAllDirichlet();
92
93 return values;
94 }
95
96 PrimaryVariables dirichletAtPos(const GlobalPosition& globalPos) const
97 { return PrimaryVariables(criticalCollarPressure_); }
98
99 template<class ElementVolumeVariables, class ElementFluxVarsCache>
100 262482 NumEqVector neumann(const Element& element,
101 const FVElementGeometry& fvGeometry,
102 const ElementVolumeVariables& elemVolVars,
103 const ElementFluxVarsCache& elemFluxVarsCache,
104 const SubControlVolumeFace& scvf) const
105 {
106
2/2
✓ Branch 0 taken 3977 times.
✓ Branch 1 taken 127264 times.
262482 NumEqVector values(0.0);
107
108 // set transpiration rate at the root collar
109 262482 const auto globalPos = scvf.center();
110
10/10
✓ Branch 0 taken 3977 times.
✓ Branch 1 taken 127264 times.
✓ Branch 2 taken 3977 times.
✓ Branch 3 taken 127264 times.
✓ Branch 4 taken 3977 times.
✓ Branch 5 taken 127264 times.
✓ Branch 6 taken 3977 times.
✓ Branch 7 taken 127264 times.
✓ Branch 8 taken 3977 times.
✓ Branch 9 taken 127264 times.
1312410 if (globalPos[2] + eps_ > this->gridGeometry().bBoxMax()[2])
111 {
112 // if the plant has water stress reduce the transpiration rate (imposing Dirichlet boundary condition weakly)
113 15908 const auto& volVars = elemVolVars[scvf.insideScvIdx()];
114 15908 const auto dist = fvGeometry.scv(scvf.insideScvIdx()).volume();
115 7954 const auto elemSol = elementSolution(element, elemVolVars, fvGeometry);
116 7954 const auto p = evalSolution(element, element.geometry(), elemSol, globalPos)[0];
117 23862 const auto eIdx = this->gridGeometry().elementMapper().index(element);
118
4/4
✓ Branch 0 taken 3648 times.
✓ Branch 1 taken 329 times.
✓ Branch 2 taken 3648 times.
✓ Branch 3 taken 329 times.
15908 const Scalar Kx = this->spatialParams().Kx(eIdx);
119
2/2
✓ Branch 0 taken 3648 times.
✓ Branch 1 taken 329 times.
7954 const auto rho = volVars.density(0);
120 7954 const Scalar criticalTranspiration = rho*Kx*(p - criticalCollarPressure_ - rho*9.81*dist)/dist;
121 15908 values[Indices::conti0EqIdx] = smoothMin(potentialTranspirationRate(), criticalTranspiration, dailyTranspirationRate_*bcSmoothingParam_);
122 7954 values /= volVars.extrusionFactor() * scvf.area(); // convert from kg/s to kg/(s*m^2)
123 }
124
125 262482 return values;
126 }
127
128 //! Smooth minimum function
129 Scalar smoothMin(const Scalar a, const Scalar b, const Scalar k) const
130 {
131 using std::max; using std::min; using std::abs;
132
8/12
✓ Branch 0 taken 3250 times.
✓ Branch 1 taken 293 times.
✓ Branch 2 taken 3250 times.
✓ Branch 3 taken 293 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 398 times.
✓ Branch 9 taken 36 times.
✓ Branch 10 taken 398 times.
✓ Branch 11 taken 36 times.
7954 const auto h = max(k-abs(a-b), 0.0 )/k;
133
4/6
✓ Branch 0 taken 2209 times.
✓ Branch 1 taken 1334 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 328 times.
✓ Branch 5 taken 106 times.
6514 return min(a, b) - h*h*h*k*(1.0/6.0);
134 }
135
136 //! Compute potential transpiration rate in kg/s
137 5279 Scalar potentialTranspirationRate() const
138 {
139 // possibly make the transpiration rate dependent on the current root length for growth
140
1/2
✓ Branch 0 taken 5279 times.
✗ Branch 1 not taken.
5279 if (bcType_ == BCType::cyclicTranspiration)
141 5279 return dailyTranspirationRate_*std::sin(time_*2.0*M_PI / 86400.0 - M_PI/2.0) + dailyTranspirationRate_;
142 else if (bcType_ == BCType::constTranspiration)
143 return dailyTranspirationRate_;
144 else
145 return std::numeric_limits<Scalar>::max();
146 }
147
148 void addPointSources(std::vector<PointSource>& pointSources) const
149
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 { pointSources = this->couplingManager().lowDimPointSources(); }
150
151 template<class ElementVolumeVariables>
152 9148794 void pointSource(PointSource& source,
153 const Element &element,
154 const FVElementGeometry& fvGeometry,
155 const ElementVolumeVariables& elemVolVars,
156 const SubControlVolume &scv) const
157 {
158 // compute source at every integration point
159 9148794 const auto id = source.id();
160
161 27446382 const Scalar p0 = this->couplingManager().bulkPriVars(id)[Indices::pressureIdx];
162 27446382 const Scalar pRoot = this->couplingManager().lowDimPriVars(id)[Indices::pressureIdx];
163 27446382 const Scalar radius = this->couplingManager().radius(id);
164 27446382 const auto lEIdx = this->couplingManager().pointSourceData(id).lowDimElementIdx();
165 27446382 const auto bEIdx = this->couplingManager().pointSourceData(id).bulkElementIdx();
166 18297588 const Scalar Kr = this->spatialParams().Kr(lEIdx);
167 9148794 const Scalar kernelRadius = kernelWidthFactor_*radius;
168 9148794 const Scalar density = 1000;
169 9148794 const Scalar viscosity = 1e-3;
170 27446382 const Scalar delta = this->couplingManager().averageDistance(id);
171
172 // sink defined as radial flow Jr * density [m^2 s-1]* [kg m-3]
173 9148794 const auto sourceValue = -1.0*this->couplingManager().reconstruction().computeSource(
174 bEIdx, lEIdx, p0, pRoot, kernelRadius, radius, Kr, density, viscosity, id, delta
175 );
176 18297588 source = sourceValue*source.quadratureWeight()*source.integrationElement();
177 9148794 }
178
179 PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
180 {
181
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2340 times.
2340 if (bcType_ == BCType::constCollarPressure)
182 return PrimaryVariables(criticalCollarPressure_);
183 else
184 4680 return PrimaryVariables(initialRootPressure_);
185 }
186
187 //! Called after every time step
188 //! Output the total global exchange term
189 //! Output the individual source terms into sourceTerms
190 451 void computeSourceIntegral(const SolutionVector& sol, const GridVariables& gridVars,
191 std::vector<Scalar>& sourceTerms)
192 {
193 451 PrimaryVariables source(0.0);
194
4/4
✓ Branch 3 taken 527670 times.
✓ Branch 4 taken 451 times.
✓ Branch 5 taken 527670 times.
✓ Branch 6 taken 451 times.
529023 for (const auto& element : elements(this->gridGeometry().gridView()))
195 {
196 1055340 auto fvGeometry = localView(this->gridGeometry());
197 527670 fvGeometry.bindElement(element);
198
199 1055340 auto elemVolVars = localView(gridVars.curGridVolVars());
200 527670 elemVolVars.bindElement(element, fvGeometry, sol);
201
202 527670 PrimaryVariables localSource(0.0);
203
5/6
✓ Branch 0 taken 527670 times.
✓ Branch 1 taken 527670 times.
✓ Branch 2 taken 527670 times.
✓ Branch 3 taken 527670 times.
✓ Branch 5 taken 527670 times.
✗ Branch 6 not taken.
2110680 for (const auto& scv : scvs(fvGeometry))
204 {
205
1/2
✓ Branch 1 taken 527670 times.
✗ Branch 2 not taken.
527670 auto pointSources = this->scvPointSources(element, fvGeometry, elemVolVars, scv);
206 527670 pointSources *= scv.volume()*elemVolVars[scv].extrusionFactor();
207 527670 localSource += pointSources;
208 }
209
210 1583010 const auto eIdx = this->gridGeometry().elementMapper().index(element);
211 527670 sourceTerms[eIdx] = localSource[0];
212 1055340 source += localSource;
213 }
214
215 902 std::cout << "Global integrated source (root): " << source << " (kg/s) / "
216 902 << source*3600*24*1000 << " (g/day)" << '\n';
217 451 }
218
219 //! compute the actual transpiration rate
220 434 Scalar computeActualTranspirationRate(const SolutionVector& sol, const GridVariables& gridVars, bool verbose = true) const
221 {
222 434 NumEqVector transpirationRate(0.0);
223
4/4
✓ Branch 3 taken 507780 times.
✓ Branch 4 taken 434 times.
✓ Branch 5 taken 507780 times.
✓ Branch 6 taken 434 times.
509082 for (const auto& element : elements(this->gridGeometry().gridView()))
224 {
225 1015560 auto fvGeometry = localView(this->gridGeometry());
226 507780 fvGeometry.bindElement(element);
227
228 1523340 auto elemVolVars = localView(gridVars.curGridVolVars());
229 507780 elemVolVars.bindElement(element, fvGeometry, sol);
230
231
6/6
✓ Branch 0 taken 1015560 times.
✓ Branch 1 taken 507780 times.
✓ Branch 2 taken 1015560 times.
✓ Branch 3 taken 507780 times.
✓ Branch 4 taken 14322 times.
✓ Branch 5 taken 1001238 times.
2031120 for (const auto& scvf : scvfs(fvGeometry))
232
2/2
✓ Branch 0 taken 14322 times.
✓ Branch 1 taken 1001238 times.
1015560 if (scvf.boundary())
233 transpirationRate += this->neumann(element, fvGeometry, elemVolVars, 0.0, scvf)
234
1/2
✓ Branch 3 taken 14322 times.
✗ Branch 4 not taken.
28644 *scvf.area()*elemVolVars[scvf.insideScvIdx()].extrusionFactor();
235 }
236
237
1/2
✓ Branch 0 taken 434 times.
✗ Branch 1 not taken.
434 if (verbose)
238 {
239 868 std::cout << "Actual transpiration rate: " << transpirationRate << " (kg/s) / "
240 434 << transpirationRate[0]*86400*1000 << " (g/day)";
241
1/2
✓ Branch 0 taken 434 times.
✗ Branch 1 not taken.
434 if (bcType_ != BCType::constCollarPressure)
242 868 std::cout << " / Potential transpiration rate: " << potentialTranspirationRate() << " (kg/s) / "
243 434 << potentialTranspirationRate()*86400*1000 << " (g/day) / ";
244 434 std::cout << std::endl;
245 }
246
247 434 return transpirationRate[0];
248 }
249
250 //! Get the coupling manager
251 const CouplingManager& couplingManager() const
252
2/4
✓ Branch 15 taken 2 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 2 times.
✗ Branch 19 not taken.
54892768 { return *couplingManager_; }
253
254 //! set the current time for evaluation of time-dependent boundary conditions
255 void setTime(const Scalar t)
256
2/2
✓ Branch 1 taken 451 times.
✓ Branch 2 taken 4 times.
455 { time_= t; }
257
258 //! get the boundary condition type
259 BCType bcType() const
260 { return bcType_; }
261
262 private:
263 Scalar initialRootPressure_, criticalCollarPressure_, dailyTranspirationRate_;
264 Scalar time_;
265 Scalar kernelWidthFactor_;
266
267 BCType bcType_;
268 Scalar bcSmoothingParam_;
269
270 static constexpr Scalar eps_ = 1.5e-7;
271 std::string name_;
272
273 std::shared_ptr<CouplingManager> couplingManager_;
274 };
275
276 } // end namespace Dumux
277
278 #endif
279