3.1-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
buckleyleverettanalyticsolution.hh
Go to the documentation of this file.
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 * This program is free software: you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation, either version 3 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
16 *****************************************************************************/
17
23#ifndef DUMUX_BUCKLEYLEVERETT_ANALYTICAL_HH
24#define DUMUX_BUCKLEYLEVERETT_ANALYTICAL_HH
25
29
30
31namespace Dumux
32{
39template<typename Scalar, typename Law>
41{
42 static bool isLinear()
43 {
44 return false;
45 }
46};
47
48template<typename Scalar>
49struct CheckMaterialLaw<Scalar, LinearMaterial<Scalar> >
50{
51 static bool isLinear()
52 {
53 return true;
54 }
55};
56
57template<typename Scalar>
58struct CheckMaterialLaw<Scalar, EffToAbsLaw< LinearMaterial<Scalar> > >
59{
60 static bool isLinear()
61 {
62 return true;
63 }
64};
65
70template<class TypeTag> class BuckleyLeverettAnalytic
71{
72 using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
73 using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
74 using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
75
76 using SpatialParams = typename GET_PROP_TYPE(TypeTag, SpatialParams);
77 using MaterialLaw = typename SpatialParams::MaterialLaw;
78 using MaterialLawParams = typename MaterialLaw::Params;
79
80 using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
81 using FluidState = typename GET_PROP_TYPE(TypeTag, FluidState);
82
83 using Indices = typename GET_PROP_TYPE(TypeTag, ModelTraits)::Indices;
84
85 enum
86 {
87 dimworld = GridView::dimensionworld
88 };
89 enum
90 {
91 wPhaseIdx = Indices::wPhaseIdx,
92 nPhaseIdx = Indices::nPhaseIdx
93 };
94
95 using BlockVector = Dune::BlockVector<Dune::FieldVector<Scalar, 1> >;
96 using Element = typename GridView::template Codim<0>::Entity;
97 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
98
99private:
100
101 // functions needed for analytical solution
102
103 void initializeAnalytic()
104 {
105 int size = problem_.gridView().size(0);
106 analyticSolution_.resize(size);
107 analyticSolution_ = 0;
108 errorGlobal_.resize(size);
109 errorGlobal_ = 0;
110 errorLocal_.resize(size);
111 errorLocal_ = 0;
112
113 return;
114 }
119 void prepareAnalytic()
120 {
121 const auto& dummyElement = *problem_.gridView().template begin<0>();
122 const MaterialLawParams& materialLawParams(problem_.spatialParams().materialLawParams(dummyElement));
123
124 swr_ = materialLawParams.swr();
125 snr_ = materialLawParams.snr();
126 Scalar porosity = problem_.spatialParams().porosity(dummyElement);
127
128 FluidState fluidState;
129 fluidState.setTemperature(problem_.temperature(dummyElement));
130 fluidState.setPressure(wPhaseIdx, problem_.referencePressure(dummyElement));
131 fluidState.setPressure(nPhaseIdx, problem_.referencePressure(dummyElement));
132 Scalar viscosityW = FluidSystem::viscosity(fluidState, wPhaseIdx);
133 Scalar viscosityNW = FluidSystem::viscosity(fluidState, nPhaseIdx);
134
135
136 if (CheckMaterialLaw<Scalar, MaterialLaw>::isLinear() && viscosityW == viscosityNW)
137 {
138 std::pair<Scalar, Scalar> entry;
139 entry.first = 1 - snr_;
140
141 entry.second = vTot_ / (porosity * (1 - swr_ - snr_));
142
143 frontParams_.push_back(entry);
144 }
145 else
146 {
147 Scalar sw0 = swr_;
148 Scalar fw0 = MaterialLaw::krw(materialLawParams, sw0)/viscosityW;
149 fw0 /= (fw0 + MaterialLaw::krn(materialLawParams, sw0)/viscosityNW);
150 Scalar sw1 = sw0 + deltaS_;
151 Scalar fw1 = MaterialLaw::krw(materialLawParams, sw1)/viscosityW;
152 fw1 /= (fw1 + MaterialLaw::krn(materialLawParams, sw1)/viscosityNW);
153 Scalar tangentSlopeOld = (fw1 - fw0)/(sw1 - sw0);
154 sw1 += deltaS_;
155 fw1 = MaterialLaw::krw(materialLawParams, sw1)/viscosityW;
156 fw1 /= (fw1 + MaterialLaw::krn(materialLawParams, sw1)/viscosityNW);
157 Scalar tangentSlopeNew = (fw1 - fw0)/(sw1 - sw0);
158
159 while (tangentSlopeNew >= tangentSlopeOld && sw1 < (1.0 - snr_))
160 {
161 tangentSlopeOld = tangentSlopeNew;
162 sw1 += deltaS_;
163 fw1 = MaterialLaw::krw(materialLawParams, sw1)/viscosityW;
164 fw1 /= (fw1 + MaterialLaw::krn(materialLawParams, sw1)/viscosityNW);
165 tangentSlopeNew = (fw1 - fw0)/(sw1 - sw0);
166 }
167
168 sw0 = sw1 - deltaS_;
169 fw0 = MaterialLaw::krw(materialLawParams, sw0)/viscosityW;
170 fw0 /= (fw0 + MaterialLaw::krn(materialLawParams, sw0)/viscosityNW);
171 Scalar sw2 = sw1 + deltaS_;
172 Scalar fw2 = MaterialLaw::krw(materialLawParams, sw2)/viscosityW;
173 fw2 /= (fw2 + MaterialLaw::krn(materialLawParams, sw2)/viscosityNW);
174 while (sw1 <= (1.0 - snr_))
175 {
176 std::pair<Scalar, Scalar> entry;
177 entry.first = sw1;
178
179 Scalar dfwdsw = (fw2 - fw0)/(sw2 - sw0);
180
181 entry.second = vTot_ / porosity * dfwdsw;
182
183 frontParams_.push_back(entry);
184
185 sw0 = sw1;
186 sw1 = sw2;
187 fw0 = fw1;
188 fw1 = fw2;
189
190 sw2 += deltaS_;
191 fw2 = MaterialLaw::krw(materialLawParams, sw2)/viscosityW;
192 fw2 /= (fw2 + MaterialLaw::krn(materialLawParams, sw2)/viscosityNW);
193 }
194 }
195
196 return;
197 }
198
199 void calcSatError()
200 {
201 Scalar globalVolume = 0;
202 Scalar errorNorm = 0.0;
203
204 for (const auto& element : elements(problem_.gridView()))
205 {
206 // get entity
207 int index = problem_.variables().index(element);
208
209 Scalar sat = problem_.variables().cellData(index).saturation(wPhaseIdx);
210
211 Scalar volume = element.geometry().volume();
212
213 Scalar error = analyticSolution_[index] - sat;
214
215 errorLocal_[index] = error;
216
217 if (sat > swr_ + 1e-6)
218 {
219 globalVolume += volume;
220 errorNorm += (volume*volume*error*error);
221 }
222 }
223
224 if (globalVolume > 0.0 && errorNorm > 0.0)
225 {
226 using std::sqrt;
227 errorNorm = sqrt(errorNorm)/globalVolume;
228 errorGlobal_ = errorNorm;
229 }
230 else
231 {
232 errorGlobal_ = 0;
233 }
234
235 return;
236 }
237
238 void updateExSol()
239 {
240 Scalar time = problem_.timeManager().time() + problem_.timeManager().timeStepSize();
241
242 // position of the fluid front
243
244 Scalar xMax = frontParams_[0].second * time;
245
246 // iterate over vertices and get analytic saturation solution
247 for (const auto& element : elements(problem_.gridView()))
248 {
249 // get global coordinate of cell center
250 GlobalPosition globalPos = element.geometry().center();
251
252 int index = problem_.variables().index(element);
253
254 if (globalPos[0] > xMax)
255 analyticSolution_[index] = swr_;
256 else
257 {
258 int size = frontParams_.size();
259 if (size == 1)
260 {
261 analyticSolution_[index] = frontParams_[0].first;
262 }
263 else
264 {
265 // find x_f next to global coordinate of the vertex
266 for (int i = 0; i < size-1; i++)
267 {
268 Scalar x = frontParams_[i].second * time;
269 Scalar xMinus = frontParams_[i+1].second * time;
270 if (globalPos[0] <= x && globalPos[0] > xMinus)
271 {
272 analyticSolution_[index] = frontParams_[i].first
273 - (frontParams_[i].first - frontParams_[i+1].first)
274 / (x - xMinus) * (x - globalPos[0]);
275 break;
276 }
277 }
278
279 }
280 }
281 }
282
283 // call function to calculate the saturation error
284 calcSatError();
285
286 return;
287 }
288
289public:
291 {
292 initializeAnalytic();
293
294 updateExSol();
295 }
296
297 BlockVector AnalyticSolution() const
298 {
299 return analyticSolution_;
300 }
301
302 //Write saturation and pressure into file
303 template<class MultiWriter>
304 void addOutputVtkFields(MultiWriter &writer)
305 {
306 int size = problem_.gridView().size(0);
307 BlockVector *analyticSolution = writer.allocateManagedBuffer (size);
308 BlockVector *errorGlobal = writer.allocateManagedBuffer (size);
309 BlockVector *errorLocal = writer.allocateManagedBuffer (size);
310
311 *analyticSolution = analyticSolution_;
312 *errorGlobal = errorGlobal_;
313 *errorLocal = errorLocal_;
314
315 writer.attachCellData(*analyticSolution, "saturation (exact solution)");
316 writer.attachCellData(*errorGlobal, "global error");
317 writer.attachCellData(*errorLocal, "local error");
318
319 return;
320 }
321
323 BuckleyLeverettAnalytic(Problem& problem) :
324 problem_(problem), analyticSolution_(0), errorGlobal_(0), errorLocal_(0), frontParams_(0), deltaS_(1e-3)
325 {}
326
327 void initialize(Scalar vTot)
328 {
329 vTot_ = vTot;
330 initializeAnalytic();
331 prepareAnalytic();
332 }
333
334
335private:
336 Problem& problem_;
337
338 BlockVector analyticSolution_;
339 BlockVector errorGlobal_;
340 BlockVector errorLocal_;
341
342 std::vector<std::pair<Scalar, Scalar> > frontParams_;
343 const Scalar deltaS_;
344
345 Scalar swr_;
346 Scalar snr_;
347 Scalar vTot_;
348
349
350
351 int tangentIdx_;
352};
353}
354#endif
#define GET_PROP_TYPE(TypeTag, PropTagName)
Definition: propertysystemmacros.hh:283
Linear capillary pressure and relative permeability <-> saturation relations.
make the local view function available whenever we use the grid geometry
Definition: adapt.hh:29
std::string viscosity(int phaseIdx) noexcept
I/O name of viscosity for multiphase systems.
Definition: name.hh:74
std::string porosity() noexcept
I/O name of porosity.
Definition: name.hh:139
This material law takes a material law defined for effective saturations and converts it to a materia...
Definition: 2p/efftoabslaw.hh:60
Linear capillary pressure and relative permeability <-> saturation relations.
Definition: linearmaterial.hh:48
IMplicit Pressure Explicit Saturation (IMPES) scheme for the solution of the Buckley-Leverett problem...
Definition: buckleyleverettanalyticsolution.hh:41
static bool isLinear()
Definition: buckleyleverettanalyticsolution.hh:42
static bool isLinear()
Definition: buckleyleverettanalyticsolution.hh:51
static bool isLinear()
Definition: buckleyleverettanalyticsolution.hh:60
Definition: buckleyleverettanalyticsolution.hh:71
void initialize(Scalar vTot)
Definition: buckleyleverettanalyticsolution.hh:327
void addOutputVtkFields(MultiWriter &writer)
Definition: buckleyleverettanalyticsolution.hh:304
BuckleyLeverettAnalytic(Problem &problem)
Construct an IMPES object.
Definition: buckleyleverettanalyticsolution.hh:323
void calculateAnalyticSolution()
Definition: buckleyleverettanalyticsolution.hh:290
BlockVector AnalyticSolution() const
Definition: buckleyleverettanalyticsolution.hh:297
Defines the properties required for (immiscible) two-phase sequential models.
This material law takes a material law defined for effective saturations and converts it to a materia...