3.1-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
mcwhorteranalyticsolution.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 * See the file COPYING for full copying permissions. *
5 *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
19#ifndef DUMUX_MCWHORTER_ANALYTIC_HH
20#define DUMUX_MCWHORTER_ANALYTIC_HH
21
23
30namespace Dumux
31{
42template<typename TypeTag>
44{
45 using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
46 using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
47 using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
48
49 using SpatialParams = typename GET_PROP_TYPE(TypeTag, SpatialParams);
50 using MaterialLaw = typename SpatialParams::MaterialLaw;
51 using MaterialLawParams = typename MaterialLaw::Params;
52
53 using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
54 using FluidState = typename GET_PROP_TYPE(TypeTag, FluidState);
55
56 using SolutionTypes = typename GET_PROP(TypeTag, SolutionTypes);
57 using PrimaryVariables = typename SolutionTypes::PrimaryVariables;
58
59 using Indices = typename GET_PROP_TYPE(TypeTag, ModelTraits)::Indices;
60
61 enum
62 {
63 dimworld = GridView::dimensionworld
64 };
65 enum
66 {
67 wPhaseIdx = Indices::wPhaseIdx,
68 nPhaseIdx = Indices::nPhaseIdx,
69 saturationIdx = Indices::saturationIdx
70 };
71
72 using BlockVector = Dune::BlockVector<Dune::FieldVector<Scalar, 1> >;
73 using Element = typename GridView::template Codim<0>::Entity;
74 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
75
76private:
77
78 // functions needed for analytical solution
79
80 void initializeAnalytic()
81 {
82 int size = problem_.gridView().size(0);
83 analyticSolution_.resize(size);
84 analyticSolution_=0;
85 errorGlobal_.resize(size);
86 errorGlobal_ = 0;
87 errorLocal_.resize(size);
88 errorLocal_ = 0;
89
90 return;
91 }
92
93 void calcSatError()
94 {
95 Scalar globalVolume = 0;
96 Scalar errorNorm = 0.0;
97
98 for (const auto& element : elements(problem_.gridView()))
99 {
100 // get entity
101 int index = problem_.variables().index(element);
102
103 Scalar sat = problem_.variables().cellData(index).saturation(wPhaseIdx);
104
105 Scalar volume = element.geometry().volume();
106
107 Scalar error = analyticSolution_[index] - sat;
108
109 errorLocal_[index] = error;
110
111 if (sat > swr_ + 1e-6)
112 {
113 globalVolume += volume;
114 errorNorm += (volume*volume*error*error);
115 }
116 }
117
118 if (globalVolume > 0.0 && errorNorm > 0.0)
119 {
120 using std::sqrt;
121 errorNorm = sqrt(errorNorm)/globalVolume;
122 errorGlobal_ = errorNorm;
123 }
124 else
125 {
126 errorGlobal_ = 0;
127 }
128
129 return;
130 }
131
132 void prepareAnalytic()
133 {
134 const auto& dummyElement = *problem_.gridView().template begin<0>();
135 const MaterialLawParams& materialLawParams(problem_.spatialParams().materialLawParams(dummyElement));
136
137 swr_ = materialLawParams.swr();
138 snr_ = materialLawParams.snr();
139 porosity_ = problem_.spatialParams().porosity(dummyElement);
140 permeability_ = problem_.spatialParams().intrinsicPermeability(dummyElement)[0][0];
141 PrimaryVariables initVec;
142 problem_.initial(initVec, dummyElement);
143 sInit_ = initVec[saturationIdx];
144 Scalar s0 =(1 - snr_ - swr_);
145// std::cerr<<"\n swr, snr: "<< swr_ << snr_ << "\n";
146// std::cerr<<"\n sInit "<< sInit_<< "\n";
147
148 // h_= (s0 - sInit_)/intervalNum_;
149 h_= (s0)/intervalNum_;
150// std::cout<<"h_= "<<h_<<std::endl;
151
152 // define saturation range for analytic solution
153 satVec_= swr_;
154 for (int i=1; i<pointNum_; i++)
155 {
156 satVec_[i]=satVec_[i-1]+h_;
157 }
158 FluidState fluidState;
159 fluidState.setTemperature(problem_.temperature(dummyElement));
160 fluidState.setPressure(wPhaseIdx, problem_.referencePressure(dummyElement));
161 fluidState.setPressure(nPhaseIdx, problem_.referencePressure(dummyElement));
162 Scalar viscosityW = FluidSystem::viscosity(fluidState, wPhaseIdx);
163 Scalar viscosityNW = FluidSystem::viscosity(fluidState, nPhaseIdx);
164
165 // get fractional flow function vector
166 for (int i=0; i<pointNum_; i++)
167 {
168 fractionalW_[i] = MaterialLaw::krw(materialLawParams, satVec_[i])/viscosityW;
169 fractionalW_[i] /= (fractionalW_[i] + MaterialLaw::krn(materialLawParams, satVec_[i])/viscosityNW);
170 }
171
172 // get capillary pressure derivatives
173 dpcdsw_=0;
174
175 for (int i=0; i<pointNum_; i++)
176 {
177 dpcdsw_[i] = MaterialLaw::dpc_dsw(materialLawParams, satVec_[i]);
178 }
179// std::cout<<"dpcdsw = "<<dpcdsw_<<std::endl;
180
181 // set initial fW
182 if (sInit_ == 0)
183 fInit_=0;
184 else
185 fInit_=fractionalW_[0];
186
187 fractionalW_[0]=0;
188
189 // normalize fW
190 // with r_ = qt/q0
191 // qt: total volume flux, q0: displacing phase flux at boundary
192 // --> r_ = 1 for unidirectional displacement; r_ = 0 for impermeable boundary
193 for (int i=0; i<pointNum_; i++)
194 {
195 fn_[i]= r_ * (fractionalW_[i] - fInit_)/ (1 - r_ * fInit_);
196 }
197
198 // std::cout<<"r_ = "<<r_<<std::endl;
199 // std::cout<<"fn_ = "<<fn_<<std::endl;
200
201 // diffusivity function
202 for (int i=0; i<pointNum_; i++)
203 {d_[i] = fractionalW_[i]*(-dpcdsw_[i])*(MaterialLaw::krn(materialLawParams, satVec_[i])/viscosityNW)*permeability_;
204 }
205
206 // std::cout<<"fractionalW_ = "<<fractionalW_<<std::endl;
207 // std::cout<<"permeability_ = "<<permeability_<<std::endl;
208 // std::cout<<"d_ = "<<d_<<std::endl;
209
210
211 // gk_: part of fractional flow function
212 // initial guess for gk_
213 for (int i=0; i<pointNum_; i++)
214 {
215 gk_[i] = d_[i]/(1-fn_[i]);
216 }
217
218 gk_[0] = 0;
219
220// std::cout<<"gk_ = "<<gk_<<std::endl;
221
222 return;
223 }
224
225 void updateExSol()
226 {
227 Scalar time = problem_.timeManager().time() + problem_.timeManager().timeStepSize();
228
229 // with displacing phase flux at boundary q0 = A * 1/sqrt(t)
230 // Akm1, Ak: successive approximations of A
231 double Ak = 0;
232 double Akm1 = 0;
233 double diff = 1e100;
234
235 // partial numerical integrals a_, b_
236 a_=0, b_=0;
237 fp_=0;
238
239 // approximation of integral I
240 double I0 = 0;
241 double Ii = 0;
242
243 int k = 0;
244
245 using std::pow;
246 using std::abs;
247
248 while (diff> tolAnalytic_)
249 {
250 k++;
251// std::cout<<" k = "<<k<<std::endl;
252 if (k> 50000)
253 {
254 std::cout<<"Analytic solution: Too many iterations!"<<std::endl;
255 break;
256 }
257
258 Akm1=Ak;
259 I0=0;
260 for (int i=0; i<intervalNum_; i++)
261 {
262 a_[i] = 0.5 * h_ * sInit_ *(gk_[i] + gk_[i+1])+ pow(h_, 2) / 6* ((3* i + 1) * gk_[i]
263 + (3 * i + 2) * gk_[i+1]);
264 b_[i] = 0.5 * h_ * (gk_[i] + gk_[i+1]);
265 I0 += (a_[i] - sInit_ * b_[i]);
266 }
267 // std::cout<<" I0 = "<<I0<<std::endl;
268
269 gk_[0]=0;
270 for (int i=1; i<pointNum_; i++)
271 {
272 Ii=0;
273 for (int j = i; j<intervalNum_; j++)
274 Ii += (a_[j] - satVec_[i] * b_[j]);
275 //gk_[i] = d_[i] + gk_[i]*(fn_[i] + Ii/I0); // method A
276 gk_[i] = (d_[i] + gk_[i]*fn_[i])/(1 - Ii/I0); // method B
277 }
278
279 // with f(sInit) = 0: relationship between A and sInit
280 Ak = pow((0.5*porosity_/pow((1 - fInit_), 2)*I0), 0.5);
281 diff=abs(Ak - Akm1);
282 // std::cout<<"diff = "<<diff<<std::endl;
283 }
284
285 // std::cout<<" b_ = "<<b_<<std::endl;
286 // std::cout<<" Ak = "<<Ak<<std::endl;
287
288
289 // fp_: first derivative of f
290 for (int i = 0; i<pointNum_; i++)
291 {
292 for (int j = i; j<intervalNum_; j++)
293 fp_[i] += b_[j]/I0;
294 }
295
296 // std::cout<<" fp_ = "<<fp_<<std::endl;
297 // std::cout<<fInit_<<std::endl;
298
299 for (int i = 0; i<pointNum_; i++)
300 {
301 xf_[i]= 2 * Ak * (1 - fInit_ * r_)/ porosity_ * fp_[i]* pow(time, 0.5);
302 }
303
304// std::cout<<" xf_ = "<<xf_<<std::endl;
305
306 // iterate over vertices and get analytical saturation solution
307 for (const auto& element : elements(problem_.gridView()))
308 {
309 // get global coordinate of cell center
310 const GlobalPosition& globalPos = element.geometry().center();
311
312// std::cout<<"globalPos = "<<globalPos[0]<<", x0 = "<<xf_[0]<<"\n";
313
314 // find index of current vertex
315 int index = problem_.variables().index(element);
316
317 // find x_f next to global coordinate of the vertex
318 int xnext = 0;
319 for (int i=intervalNum_; i>0; i--)
320 {
321 if (globalPos[0] <= xf_[i])
322 {
323 xnext = i;
324 break;
325 }
326 }
327
328 // account for the area not yet reached by the front
329 if (globalPos[0]> xf_[0])
330 {
331 analyticSolution_[index] = sInit_;
332 continue;
333 }
334
335 if (globalPos[0] <= xf_[0])
336 {
337 analyticSolution_[index] = satVec_[xnext];
338 continue;
339 }
340
341// std::cout<<"Analytical = "<<satVec_[xnext]<<std::endl;
342 }
343
344 // call function to calculate the saturation error
345 calcSatError();
346 return;
347 }
348
349public:
351 {
352 initializeAnalytic();
353
354 updateExSol();
355 }
356
357 BlockVector AnalyticSolution() const
358 {
359 return analyticSolution_;
360 }
361
362 //Write saturation and pressure into file
363 template<class MultiWriter>
364 void addOutputVtkFields(MultiWriter &writer)
365 {
366 int size = problem_.gridView().size(0);
367 BlockVector *analyticSolution = writer.allocateManagedBuffer (size);
368 BlockVector *errorGlobal = writer.allocateManagedBuffer (size);
369 BlockVector *errorLocal = writer.allocateManagedBuffer (size);
370
371 *analyticSolution = analyticSolution_;
372 *errorGlobal = errorGlobal_;
373 *errorLocal = errorLocal_;
374
375 writer.attachCellData(*analyticSolution, "saturation (exact solution)");
376 writer.attachCellData(*errorGlobal, "global error");
377 writer.attachCellData(*errorLocal, "local error");
378
379 return;
380 }
381
382
384 {
385 initializeAnalytic();
386 prepareAnalytic();
387 }
388
389 McWhorterAnalytic(Problem& problem, Scalar tolAnalytic = 1e-14) :
390 problem_(problem), analyticSolution_(0), errorGlobal_(0), errorLocal_(0), tolAnalytic_(tolAnalytic)
391 {}
392
393private:
394 Problem& problem_;
395
396 BlockVector analyticSolution_;
397 BlockVector errorGlobal_;
398 BlockVector errorLocal_;
399
400 Scalar tolAnalytic_;
401 Scalar r_;
402
403 Scalar swr_;
404 Scalar snr_;
405 Scalar porosity_;
406 Scalar sInit_;
407 Scalar permeability_;
408 enum
409 { intervalNum_ = 1000, pointNum_ = intervalNum_+1};
410 Dune::FieldVector<Scalar, pointNum_> satVec_;
411 Dune::FieldVector<Scalar,pointNum_> fractionalW_;
412 Dune::FieldVector<Scalar, pointNum_> dpcdsw_;
413 Dune::FieldVector<Scalar, pointNum_> fn_;
414 Dune::FieldVector<Scalar, pointNum_> d_;
415 Dune::FieldVector<Scalar, pointNum_> gk_;
416 Dune::FieldVector<Scalar, pointNum_> xf_;
417 Scalar fInit_;
418 Scalar h_;
419 Dune::FieldVector<Scalar,intervalNum_> a_;
420 Dune::FieldVector<Scalar,intervalNum_> b_;
421 Dune::FieldVector<Scalar,pointNum_> fp_;
422
423};
424}
425#endif
#define GET_PROP(TypeTag, PropTagName)
Definition: propertysystemmacros.hh:281
#define GET_PROP_TYPE(TypeTag, PropTagName)
Definition: propertysystemmacros.hh:283
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
Analytic solution of the McWhorter problem.
Definition: mcwhorteranalyticsolution.hh:44
BlockVector AnalyticSolution() const
Definition: mcwhorteranalyticsolution.hh:357
McWhorterAnalytic(Problem &problem, Scalar tolAnalytic=1e-14)
Definition: mcwhorteranalyticsolution.hh:389
void addOutputVtkFields(MultiWriter &writer)
Definition: mcwhorteranalyticsolution.hh:364
void calculateAnalyticSolution()
Definition: mcwhorteranalyticsolution.hh:350
void initialize()
Definition: mcwhorteranalyticsolution.hh:383
Defines the properties required for (immiscible) two-phase sequential models.