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-09-21 20:52:54
Exec Total Coverage
Lines: 90 104 86.5%
Functions: 7 11 63.6%
Branches: 76 182 41.8%

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