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 OnePNCTests | ||
10 | * \brief Definition of a problem for the 1pnc problem: | ||
11 | * Component transport of nitrogen dissolved in the water phase. | ||
12 | */ | ||
13 | |||
14 | #ifndef DUMUX_1P2C_TEST_PROBLEM_HH | ||
15 | #define DUMUX_1P2C_TEST_PROBLEM_HH | ||
16 | |||
17 | #include <dumux/common/properties.hh> | ||
18 | #include <dumux/common/parameters.hh> | ||
19 | |||
20 | #include <dumux/common/boundarytypes.hh> | ||
21 | #include <dumux/common/numeqvector.hh> | ||
22 | #include <dumux/porousmediumflow/problem.hh> | ||
23 | |||
24 | |||
25 | namespace Dumux { | ||
26 | |||
27 | /*! | ||
28 | * \ingroup OnePNCTests | ||
29 | * \brief Definition of a problem for the 1pnc problem: | ||
30 | * Component transport of nitrogen dissolved in the water phase. | ||
31 | * | ||
32 | * Nitrogen is dissolved in the water phase and is transported with the | ||
33 | * water flow from the left side to the right. | ||
34 | * | ||
35 | * The model domain is specified in the input file and | ||
36 | * we use homogeneous soil properties. | ||
37 | * Initially, the domain is filled with pure water. | ||
38 | * | ||
39 | * At the left side, a Dirichlet condition defines a nitrogen mole fraction. | ||
40 | * The water phase flows from the left side to the right if the applied pressure | ||
41 | * gradient is >0. The nitrogen is transported with the water flow | ||
42 | * and leaves the domain at theboundary, where again Dirichlet boundary | ||
43 | * conditions are applied. | ||
44 | * | ||
45 | * This problem uses the \ref OnePNCModel model. | ||
46 | */ | ||
47 | template <class TypeTag> | ||
48 | class OnePNCDispersionProblem : public PorousMediumFlowProblem<TypeTag> | ||
49 | { | ||
50 | using ParentType = PorousMediumFlowProblem<TypeTag>; | ||
51 | |||
52 | using Scalar = GetPropType<TypeTag, Properties::Scalar>; | ||
53 | using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>; | ||
54 | using BoundaryTypes = Dumux::BoundaryTypes<GetPropType<TypeTag, Properties::ModelTraits>::numEq()>; | ||
55 | using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>; | ||
56 | using NumEqVector = Dumux::NumEqVector<PrimaryVariables>; | ||
57 | using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView; | ||
58 | using Element = typename GridView::template Codim<0>::Entity; | ||
59 | |||
60 | using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>; | ||
61 | using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView; | ||
62 | using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; | ||
63 | |||
64 | using GridVariables = GetPropType<TypeTag, Properties::GridVariables>; | ||
65 | using ElementVolumeVariables = typename GridVariables::GridVolumeVariables::LocalView; | ||
66 | using ElementFluxVariablesCache = typename GridVariables::GridFluxVariablesCache::LocalView; | ||
67 | |||
68 | // copy some indices for convenience | ||
69 | using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices; | ||
70 | |||
71 | enum | ||
72 | { | ||
73 | #if NONISOTHERMAL | ||
74 | energyEqIdx = Indices::energyEqIdx, | ||
75 | #endif | ||
76 | // indices of the primary variables | ||
77 | pressureIdx = Indices::pressureIdx, | ||
78 | |||
79 | // component indices | ||
80 | H2OIdx = FluidSystem::compIdx(FluidSystem::MultiPhaseFluidSystem::H2OIdx), | ||
81 | N2Idx = FluidSystem::compIdx(FluidSystem::MultiPhaseFluidSystem::N2Idx), | ||
82 | // indices of the equations | ||
83 | contiH2OEqIdx = Indices::conti0EqIdx + H2OIdx, | ||
84 | contiN2EqIdx = Indices::conti0EqIdx + N2Idx | ||
85 | }; | ||
86 | |||
87 | //! Property that defines whether mole or mass fractions are used | ||
88 | static constexpr bool useMoles = getPropValue<TypeTag, Properties::UseMoles>(); | ||
89 | static constexpr int numFluidComps = FluidSystem::numComponents; | ||
90 | static const int dimWorld = GridView::dimensionworld; | ||
91 | using GlobalPosition = typename SubControlVolumeFace::GlobalPosition; | ||
92 | |||
93 | public: | ||
94 | 6 | OnePNCDispersionProblem(std::shared_ptr<const GridGeometry> gridGeometry) | |
95 |
7/20✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 6 times.
✓ Branch 15 taken 6 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 6 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
|
18 | : ParentType(gridGeometry) |
96 | { | ||
97 | //initialize fluid system | ||
98 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | FluidSystem::init(); |
99 | |||
100 | // stating in the console whether mole or mass fractions are used | ||
101 | if constexpr (useMoles) | ||
102 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
12 | std::cout<<"problem uses mole fractions" << '\n'; |
103 | else | ||
104 | std::cout<<"problem uses mass fractions" << '\n'; | ||
105 | |||
106 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | boundaryConcentration_ = getParam<Scalar>("Problem.BoundaryConcentration"); |
107 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | temperatureDifference_ = getParam<Scalar>("Problem.BoundaryTemperatureDifference"); |
108 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | counterFlowRate_ = getParam<Scalar>("Problem.CounterFlowRate"); |
109 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | pressure_ = getParam<Scalar>("Problem.Pressure"); |
110 |
2/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
|
6 | problemName_ = getParam<std::string>("Problem.Name"); |
111 | 6 | } | |
112 | |||
113 | /*! | ||
114 | * \brief The problem name. | ||
115 | */ | ||
116 | const std::string& name() const | ||
117 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | { return problemName_; } |
118 | |||
119 | /*! | ||
120 | * \brief Specifies which kind of boundary condition should be | ||
121 | * used for which equation on a given boundary segment. | ||
122 | */ | ||
123 | 138996 | BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const | |
124 | { | ||
125 | 138996 | BoundaryTypes values; | |
126 | |||
127 | 138996 | values.setAllDirichlet(); | |
128 | |||
129 | 484704 | if (isRightBoundary_(globalPos) || | |
130 | 276210 | isLowerBoundary_(globalPos) || | |
131 | isUpperBoundary_(globalPos) ) | ||
132 | values.setAllNeumann(); | ||
133 | |||
134 | 138996 | return values; | |
135 | } | ||
136 | |||
137 | /*! | ||
138 | * \brief Evaluate the boundary conditions for a dirichlet | ||
139 | * boundary segment. | ||
140 | * | ||
141 | * For this method, the \a values parameter stores primary variables. | ||
142 | */ | ||
143 | 33858 | PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const | |
144 | { | ||
145 | 33858 | PrimaryVariables values = initialAtPos(globalPos); | |
146 | |||
147 | 67716 | if (isLeftBoundary_(globalPos)) | |
148 | { | ||
149 | 48716 | values[contiN2EqIdx] = boundaryConcentration_; | |
150 | #if NONISOTHERMAL | ||
151 | 57000 | values[energyEqIdx] = this->spatialParams().temperatureAtPos(globalPos) + temperatureDifference_; | |
152 | #endif | ||
153 | } | ||
154 | |||
155 | 33858 | return values; | |
156 | } | ||
157 | |||
158 | /*! | ||
159 | * \brief Evaluates the boundary conditions for a neumann | ||
160 | * boundary segment (implementation for the box scheme). | ||
161 | * | ||
162 | * This is the method for the case where the Neumann condition is | ||
163 | * potentially solution dependent and requires some quantities that | ||
164 | * are specific to the fully-implicit method. | ||
165 | * | ||
166 | * \param element The finite element | ||
167 | * \param fvGeometry The finite-volume geometry | ||
168 | * \param elemVolVars All volume variables for the element | ||
169 | * \param elemFluxVarsCache Flux variables caches for all faces in stencil | ||
170 | * \param scvf The sub-control volume face | ||
171 | * | ||
172 | * For this method, the \a values parameter stores the flux | ||
173 | * in normal direction of each phase. Negative values mean influx. | ||
174 | * E.g. for the mass balance that would be the mass flux in \f$ [ kg / (m^2 \cdot s)] \f$. | ||
175 | */ | ||
176 | ✗ | NumEqVector neumann(const Element& element, | |
177 | const FVElementGeometry& fvGeometry, | ||
178 | const ElementVolumeVariables& elemVolVars, | ||
179 | const ElementFluxVariablesCache& elemFluxVarsCache, | ||
180 | const SubControlVolumeFace& scvf) const | ||
181 | { | ||
182 | ✗ | const auto globalPos = element.geometry().corner(scvf.insideScvIdx()); | |
183 | ✗ | NumEqVector values(0.0); | |
184 | ✗ | if (isRightBoundary_(globalPos)) | |
185 | ✗ | values[contiH2OEqIdx] = -1.0 * counterFlowRate_; | |
186 | ✗ | return values; | |
187 | } | ||
188 | |||
189 | /*! | ||
190 | * \brief Evaluates the source term for all phases within a given | ||
191 | * sub-control volume. | ||
192 | * | ||
193 | * For this method, the \a priVars parameter stores the rate mass | ||
194 | * of a component is generated or annihilated per volume | ||
195 | * unit. Positive values mean that mass is created, negative ones | ||
196 | * mean that it vanishes. | ||
197 | * | ||
198 | * The units must be according to either using mole or mass fractions (mole/(m^3*s) or kg/(m^3*s)). | ||
199 | */ | ||
200 | ✗ | NumEqVector sourceAtPos(const GlobalPosition &globalPos) const | |
201 | 11715200 | { return NumEqVector(0.0); } | |
202 | |||
203 | //#### initial value for a control volume | ||
204 | 36504 | PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const | |
205 | { | ||
206 | 36504 | PrimaryVariables values; | |
207 | |||
208 | 36504 | GetPropType<TypeTag, Properties::FluidState> fluidState; | |
209 | 73008 | fluidState.setTemperature(this->spatialParams().temperatureAtPos(globalPos)); | |
210 | 36504 | fluidState.setPressure(0, pressure_); | |
211 | 36504 | Scalar density = FluidSystem::density(fluidState, 0); | |
212 | 182520 | const Scalar depth = this->gridGeometry().bBoxMax()[1] - globalPos[1]; | |
213 | 146016 | const Scalar gravity = this->spatialParams().gravity(globalPos)[1]; | |
214 | |||
215 | 73008 | values[Indices::pressureIdx] = pressure_ - (density * gravity * depth); //initial condition for the pressure | |
216 | 73008 | values[contiN2EqIdx] = 0.0; //initial condition for the molefraction | |
217 | #if NONISOTHERMAL | ||
218 | 60969 | values[energyEqIdx] = this->spatialParams().temperatureAtPos(globalPos); | |
219 | #endif | ||
220 | 36504 | return values; | |
221 | } | ||
222 | |||
223 | private: | ||
224 | bool isLeftBoundary_(const GlobalPosition& globalPos) const | ||
225 |
5/10✓ Branch 0 taken 33858 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33858 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 33858 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 33858 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 33858 times.
✗ Branch 9 not taken.
|
169290 | { return globalPos[0] < this->gridGeometry().bBoxMin()[0] + eps_; } |
226 | |||
227 | bool isRightBoundary_(const GlobalPosition& globalPos) const | ||
228 |
10/20✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 103356 times.
✓ Branch 11 taken 35640 times.
✓ Branch 12 taken 103356 times.
✓ Branch 13 taken 35640 times.
✓ Branch 14 taken 103356 times.
✓ Branch 15 taken 35640 times.
✓ Branch 16 taken 103356 times.
✓ Branch 17 taken 35640 times.
✓ Branch 18 taken 103356 times.
✓ Branch 19 taken 35640 times.
|
694980 | { return globalPos[0] > this->gridGeometry().bBoxMax()[0] - eps_; } |
229 | |||
230 | bool isLowerBoundary_(const GlobalPosition& globalPos) const | ||
231 |
10/10✓ Branch 0 taken 34749 times.
✓ Branch 1 taken 68607 times.
✓ Branch 2 taken 34749 times.
✓ Branch 3 taken 68607 times.
✓ Branch 4 taken 34749 times.
✓ Branch 5 taken 68607 times.
✓ Branch 6 taken 34749 times.
✓ Branch 7 taken 68607 times.
✓ Branch 8 taken 34749 times.
✓ Branch 9 taken 68607 times.
|
516780 | { return globalPos[1] < this->gridGeometry().bBoxMin()[1] + eps_; } |
232 | |||
233 | bool isUpperBoundary_(const GlobalPosition& globalPos) const | ||
234 |
10/10✓ Branch 0 taken 34749 times.
✓ Branch 1 taken 33858 times.
✓ Branch 2 taken 34749 times.
✓ Branch 3 taken 33858 times.
✓ Branch 4 taken 34749 times.
✓ Branch 5 taken 33858 times.
✓ Branch 6 taken 34749 times.
✓ Branch 7 taken 33858 times.
✓ Branch 8 taken 34749 times.
✓ Branch 9 taken 33858 times.
|
343035 | { return globalPos[1] > this->gridGeometry().bBoxMax()[1] - eps_; } |
235 | |||
236 | static constexpr Scalar eps_ = 1e-6; | ||
237 | Scalar pressure_; | ||
238 | Scalar counterFlowRate_; | ||
239 | Scalar temperatureDifference_; | ||
240 | Scalar boundaryConcentration_; | ||
241 | std::string problemName_; | ||
242 | }; | ||
243 | |||
244 | } // end namespace Dumux | ||
245 | |||
246 | #endif | ||
247 |