lensproblem.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 file is part of the Open Porous Media project (OPM).
5
6 OPM 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 2 of the License, or
9 (at your option) any later version.
10
11 OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
18
19 Consult the COPYING file in the top-level source directory of this
20 module for the precise wording of the license and the list of
21 copyright holders.
22*/
28#ifndef EWOMS_LENS_PROBLEM_HH
29#define EWOMS_LENS_PROBLEM_HH
30
31#include <dune/common/fmatrix.hh>
32#include <dune/common/fvector.hh>
33#include <dune/common/version.hh>
34
35#include <opm/material/components/Dnapl.hpp>
36#include <opm/material/components/SimpleH2O.hpp>
37#include <opm/material/fluidmatrixinteractions/RegularizedVanGenuchten.hpp>
38#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
39#include <opm/material/fluidmatrixinteractions/EffToAbsLaw.hpp>
40#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
41#include <opm/material/fluidstates/ImmiscibleFluidState.hpp>
42#include <opm/material/fluidsystems/TwoPhaseImmiscibleFluidSystem.hpp>
43
46
50
52
55
56#include <iostream>
57#include <sstream>
58#include <string>
59
60namespace Opm {
61template <class TypeTag>
62class LensProblem;
63}
64
65namespace Opm::Properties {
66
67// Create new type tags
68namespace TTag {
69struct LensBaseProblem { using InheritsFrom = std::tuple<StructuredGridVanguard>; };
70} // end namespace TTag
71
72// Set the problem property
73template<class TypeTag>
74struct Problem<TypeTag, TTag::LensBaseProblem> { using type = Opm::LensProblem<TypeTag>; };
75
76// Use Dune-grid's YaspGrid
77template<class TypeTag>
78struct Grid<TypeTag, TTag::LensBaseProblem> { using type = Dune::YaspGrid<2>; };
79
80// Set the wetting phase
81template<class TypeTag>
82struct WettingPhase<TypeTag, TTag::LensBaseProblem>
83{
84private:
86
87public:
88 using type = Opm::LiquidPhase<Scalar, Opm::SimpleH2O<Scalar> >;
89};
90
91// Set the non-wetting phase
92template<class TypeTag>
93struct NonwettingPhase<TypeTag, TTag::LensBaseProblem>
94{
95private:
97
98public:
99 using type = Opm::LiquidPhase<Scalar, Opm::DNAPL<Scalar> >;
100};
101
102// Set the material Law
103template<class TypeTag>
104struct MaterialLaw<TypeTag, TTag::LensBaseProblem>
105{
106private:
108 enum { wettingPhaseIdx = FluidSystem::wettingPhaseIdx };
109 enum { nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx };
110
112 using Traits = Opm::TwoPhaseMaterialTraits<Scalar,
113 /*wettingPhaseIdx=*/FluidSystem::wettingPhaseIdx,
114 /*nonWettingPhaseIdx=*/FluidSystem::nonWettingPhaseIdx>;
115
116 // define the material law which is parameterized by effective
117 // saturations
118 using EffectiveLaw = Opm::RegularizedVanGenuchten<Traits>;
119
120public:
121 // define the material law parameterized by absolute saturations
122 using type = Opm::EffToAbsLaw<EffectiveLaw>;
123};
124
125} // namespace Opm::Properties
126
127namespace Opm::Parameters {
128
129// define the properties specific for the lens problem
130template<class Scalar>
131struct LensLowerLeftX { static constexpr Scalar value = 1.0; };
132
133template<class Scalar>
134struct LensLowerLeftY { static constexpr Scalar value = 2.0; };
135
136template<class Scalar>
137struct LensLowerLeftZ { static constexpr Scalar value = 0.0; };
138
139template<class Scalar>
140struct LensUpperRightX { static constexpr Scalar value = 4.0; };
141
142template<class Scalar>
143struct LensUpperRightY { static constexpr Scalar value = 3.0; };
144
145template<class Scalar>
146struct LensUpperRightZ { static constexpr Scalar value = 1.0; };
147
148} // namespace Opm::Parameters
149
150namespace Opm {
151
175template <class TypeTag>
176class LensProblem : public GetPropType<TypeTag, Properties::BaseProblem>
177{
179
189
190 enum {
191 // number of phases
192 numPhases = FluidSystem::numPhases,
193
194 // phase indices
195 wettingPhaseIdx = FluidSystem::wettingPhaseIdx,
196 nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx,
197
198 // equation indices
199 contiNEqIdx = Indices::conti0EqIdx + nonWettingPhaseIdx,
200
201 // Grid and world dimension
202 dim = GridView::dimension,
203 dimWorld = GridView::dimensionworld
204 };
205
211
212 using CoordScalar = typename GridView::ctype;
213 using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
214
215 using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
216
217public:
221 explicit LensProblem(Simulator& simulator)
222 : ParentType(simulator)
223 { }
224
229 {
230 ParentType::finishInit();
231
232 eps_ = 3e-6;
233 FluidSystem::init();
234
235 temperature_ = 273.15 + 20; // -> 20°C
236 lensLowerLeft_[0] = Parameters::Get<Parameters::LensLowerLeftX<Scalar>>();
237 lensLowerLeft_[1] = Parameters::Get<Parameters::LensLowerLeftY<Scalar>>();
238 lensUpperRight_[0] = Parameters::Get<Parameters::LensUpperRightX<Scalar>>();
239 lensUpperRight_[1] = Parameters::Get<Parameters::LensUpperRightY<Scalar>>();
240
241 if constexpr (dim == 3) {
242 lensLowerLeft_[2] = Parameters::Get<Parameters::LensLowerLeftZ<Scalar>>();
243 lensUpperRight_[2] = Parameters::Get<Parameters::LensUpperRightZ<Scalar>>();
244 }
245
246 // residual saturations
247 lensMaterialParams_.setResidualSaturation(wettingPhaseIdx, 0.18);
248 lensMaterialParams_.setResidualSaturation(nonWettingPhaseIdx, 0.0);
249 outerMaterialParams_.setResidualSaturation(wettingPhaseIdx, 0.05);
250 outerMaterialParams_.setResidualSaturation(nonWettingPhaseIdx, 0.0);
251
252 // parameters for the Van Genuchten law: alpha and n
253 lensMaterialParams_.setVgAlpha(0.00045);
254 lensMaterialParams_.setVgN(7.3);
255 outerMaterialParams_.setVgAlpha(0.0037);
256 outerMaterialParams_.setVgN(4.7);
257
258 lensMaterialParams_.finalize();
259 outerMaterialParams_.finalize();
260
261 lensK_ = this->toDimMatrix_(9.05e-12);
262 outerK_ = this->toDimMatrix_(4.6e-10);
263
264 if (dimWorld == 3) {
265 this->gravity_ = 0;
266 this->gravity_[1] = -9.81;
267 }
268 }
269
273 static void registerParameters()
274 {
275 ParentType::registerParameters();
276
277 Parameters::Register<Parameters::LensLowerLeftX<Scalar>>
278 ("The x-coordinate of the lens' lower-left corner [m].");
279 Parameters::Register<Parameters::LensLowerLeftY<Scalar>>
280 ("The y-coordinate of the lens' lower-left corner [m].");
281 Parameters::Register<Parameters::LensUpperRightX<Scalar>>
282 ("The x-coordinate of the lens' upper-right corner [m].");
283 Parameters::Register<Parameters::LensUpperRightY<Scalar>>
284 ("The y-coordinate of the lens' upper-right corner [m].");
285
286 if constexpr (dim == 3) {
287 Parameters::Register<Parameters::LensLowerLeftZ<Scalar>>
288 ("The z-coordinate of the lens' lower-left corner [m].");
289 Parameters::Register<Parameters::LensUpperRightZ<Scalar>>
290 ("The z-coordinate of the lens' upper-right corner [m].");
291 }
292
293 Parameters::SetDefault<Parameters::CellsX>(48);
294 Parameters::SetDefault<Parameters::CellsY>(32);
295 Parameters::SetDefault<Parameters::DomainSizeX<Scalar>>(6.0);
296 Parameters::SetDefault<Parameters::DomainSizeY<Scalar>>(4.0);
297
298 if constexpr (dim == 3) {
299 Parameters::SetDefault<Parameters::CellsZ>(16);
300 Parameters::SetDefault<Parameters::DomainSizeZ<Scalar>>(1.0);
301 }
302
303 // Use forward differences
305 constexpr bool useFD = std::is_same_v<LLS, Properties::TTag::FiniteDifferenceLocalLinearizer>;
306 if constexpr (useFD) {
307 Parameters::SetDefault<Parameters::NumericDifferenceMethod>(+1);
308 }
309
310 Parameters::SetDefault<Parameters::EndTime<Scalar>>(30e3);
311 Parameters::SetDefault<Parameters::EnableIntensiveQuantityCache>(true);
312 Parameters::SetDefault<Parameters::EnableStorageCache>(true);
313 Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(250.0);
314 Parameters::SetDefault<Parameters::VtkWriteIntrinsicPermeabilities>(true);
315 Parameters::SetDefault<Parameters::EnableGravity>(true);
316 }
317
321 static std::string briefDescription()
322 {
323 std::string thermal = "isothermal";
324 constexpr bool enableEnergy = getPropValue<TypeTag, Properties::EnableEnergy>();
325 if constexpr (enableEnergy)
326 thermal = "non-isothermal";
327
328 std::string deriv = "finite difference";
330 constexpr bool useAutoDiff = std::is_same_v<LLS, Properties::TTag::AutoDiffLocalLinearizer>;
331 if constexpr (useAutoDiff) {
332 deriv = "automatic differentiation";
333 }
334
335 std::string disc = "vertex centered finite volume";
337 constexpr bool useEcfv = std::is_same<D, Opm::EcfvDiscretization<TypeTag>>::value;
338 if constexpr (useEcfv)
339 disc = "element centered finite volume";
340
341 return std::string("")+
342 "Ground remediation problem where a dense oil infiltrates "+
343 "an aquifer with an embedded low-permability lens. " +
344 "This is the binary for the "+thermal+" variant using "+deriv+
345 "and the "+disc+" discretization";
346 }
347
352
356 template <class Context>
357 const DimMatrix& intrinsicPermeability(const Context& context, unsigned spaceIdx,
358 unsigned timeIdx) const
359 {
360 const GlobalPosition& globalPos = context.pos(spaceIdx, timeIdx);
361
362 if (isInLens_(globalPos))
363 return lensK_;
364 return outerK_;
365 }
366
370 template <class Context>
371 Scalar porosity(const Context& /*context*/,
372 unsigned /*spaceIdx*/,
373 unsigned /*timeIdx*/) const
374 { return 0.4; }
375
379 template <class Context>
380 const MaterialLawParams& materialLawParams(const Context& context,
381 unsigned spaceIdx, unsigned timeIdx) const
382 {
383 const GlobalPosition& globalPos = context.pos(spaceIdx, timeIdx);
384
385 if (isInLens_(globalPos))
386 return lensMaterialParams_;
387 return outerMaterialParams_;
388 }
389
393 template <class Context>
394 Scalar temperature(const Context& /*context*/,
395 unsigned /*spaceIdx*/,
396 unsigned /*timeIdx*/) const
397 { return temperature_; }
398
400
405
409 std::string name() const
410 {
412
413 constexpr bool useAutoDiff = std::is_same_v<LLS, Properties::TTag::AutoDiffLocalLinearizer>;
414
416 constexpr bool useTrans = std::is_same_v<FM, Opm::TransFluxModule<TypeTag>>;
417
418 std::ostringstream oss;
419 oss << "lens_" << Model::name()
420 << "_" << Model::discretizationName()
421 << "_" << (useAutoDiff?"ad":"fd");
422 if (useTrans)
423 oss << "_trans";
424
425 return oss.str();
426 }
427
432 { }
433
438 { }
439
444 {
445#ifndef NDEBUG
446 //this->model().checkConservativeness();
447
448 // Calculate storage terms
449 EqVector storage;
450 this->model().globalStorage(storage);
451
452 // Write mass balance information for rank 0
453 if (this->gridView().comm().rank() == 0) {
454 std::cout << "Storage: " << storage << std::endl << std::flush;
455 }
456#endif // NDEBUG
457 }
458
460
465
469 template <class Context>
470 void boundary(BoundaryRateVector& values,
471 const Context& context,
472 unsigned spaceIdx,
473 unsigned timeIdx) const
474 {
475 const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
476
477 if (onLeftBoundary_(pos) || onRightBoundary_(pos)) {
478 // free flow boundary. we assume incompressible fluids
479 Scalar densityW = WettingPhase::density(temperature_, /*pressure=*/Scalar(1e5));
480 Scalar densityN = NonwettingPhase::density(temperature_, /*pressure=*/Scalar(1e5));
481
482 Scalar T = temperature(context, spaceIdx, timeIdx);
483 Scalar pw, Sw;
484
485 // set wetting phase pressure and saturation
486 if (onLeftBoundary_(pos)) {
487 Scalar height = this->boundingBoxMax()[1] - this->boundingBoxMin()[1];
488 Scalar depth = this->boundingBoxMax()[1] - pos[1];
489 Scalar alpha = (1 + 1.5 / height);
490
491 // hydrostatic pressure scaled by alpha
492 pw = 1e5 - alpha * densityW * this->gravity()[1] * depth;
493 Sw = 1.0;
494 }
495 else {
496 Scalar depth = this->boundingBoxMax()[1] - pos[1];
497
498 // hydrostatic pressure
499 pw = 1e5 - densityW * this->gravity()[1] * depth;
500 Sw = 1.0;
501 }
502
503 // specify a full fluid state using pw and Sw
504 const MaterialLawParams& matParams = this->materialLawParams(context, spaceIdx, timeIdx);
505
506 Opm::ImmiscibleFluidState<Scalar, FluidSystem,
507 /*storeEnthalpy=*/false> fs;
508 fs.setSaturation(wettingPhaseIdx, Sw);
509 fs.setSaturation(nonWettingPhaseIdx, 1 - Sw);
510 fs.setTemperature(T);
511
512 Scalar pC[numPhases];
513 MaterialLaw::capillaryPressures(pC, matParams, fs);
514 fs.setPressure(wettingPhaseIdx, pw);
515 fs.setPressure(nonWettingPhaseIdx, pw + pC[nonWettingPhaseIdx] - pC[wettingPhaseIdx]);
516
517 fs.setDensity(wettingPhaseIdx, densityW);
518 fs.setDensity(nonWettingPhaseIdx, densityN);
519
520 fs.setViscosity(wettingPhaseIdx, WettingPhase::viscosity(temperature_, fs.pressure(wettingPhaseIdx)));
521 fs.setViscosity(nonWettingPhaseIdx, NonwettingPhase::viscosity(temperature_, fs.pressure(nonWettingPhaseIdx)));
522
523 // impose an freeflow boundary condition
524 values.setFreeFlow(context, spaceIdx, timeIdx, fs);
525 }
526 else if (onInlet_(pos)) {
527 RateVector massRate(0.0);
528 massRate = 0.0;
529 massRate[contiNEqIdx] = -0.04; // kg / (m^2 * s)
530
531 // impose a forced flow boundary
532 values.setMassRate(massRate);
533 }
534 else {
535 // no flow boundary
536 values.setNoFlow();
537 }
538 }
539
541
546
550 template <class Context>
551 void initial(PrimaryVariables& values, const Context& context, unsigned spaceIdx, unsigned timeIdx) const
552 {
553 const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
554 Scalar depth = this->boundingBoxMax()[1] - pos[1];
555
556 Opm::ImmiscibleFluidState<Scalar, FluidSystem> fs;
557 fs.setPressure(wettingPhaseIdx, /*pressure=*/1e5);
558
559 Scalar Sw = 1.0;
560 fs.setSaturation(wettingPhaseIdx, Sw);
561 fs.setSaturation(nonWettingPhaseIdx, 1 - Sw);
562
563 fs.setTemperature(temperature_);
564
565 typename FluidSystem::template ParameterCache<Scalar> paramCache;
566 paramCache.updatePhase(fs, wettingPhaseIdx);
567 Scalar densityW = FluidSystem::density(fs, paramCache, wettingPhaseIdx);
568
569 // hydrostatic pressure (assuming incompressibility)
570 Scalar pw = 1e5 - densityW * this->gravity()[1] * depth;
571
572 // calculate the capillary pressure
573 const MaterialLawParams& matParams = this->materialLawParams(context, spaceIdx, timeIdx);
574 Scalar pC[numPhases];
575 MaterialLaw::capillaryPressures(pC, matParams, fs);
576
577 // make a full fluid state
578 fs.setPressure(wettingPhaseIdx, pw);
579 fs.setPressure(nonWettingPhaseIdx, pw + (pC[wettingPhaseIdx] - pC[nonWettingPhaseIdx]));
580
581 // assign the primary variables
582 values.assignNaive(fs);
583 }
584
591 template <class Context>
592 void source(RateVector& rate,
593 const Context& /*context*/,
594 unsigned /*spaceIdx*/,
595 unsigned /*timeIdx*/) const
596 { rate = Scalar(0.0); }
597
599
600private:
601 bool isInLens_(const GlobalPosition& pos) const
602 {
603 for (unsigned i = 0; i < dim; ++i) {
604 if (pos[i] < lensLowerLeft_[i] - eps_ || pos[i] > lensUpperRight_[i]
605 + eps_)
606 return false;
607 }
608 return true;
609 }
610
611 bool onLeftBoundary_(const GlobalPosition& pos) const
612 { return pos[0] < this->boundingBoxMin()[0] + eps_; }
613
614 bool onRightBoundary_(const GlobalPosition& pos) const
615 { return pos[0] > this->boundingBoxMax()[0] - eps_; }
616
617 bool onLowerBoundary_(const GlobalPosition& pos) const
618 { return pos[1] < this->boundingBoxMin()[1] + eps_; }
619
620 bool onUpperBoundary_(const GlobalPosition& pos) const
621 { return pos[1] > this->boundingBoxMax()[1] - eps_; }
622
623 bool onInlet_(const GlobalPosition& pos) const
624 {
625 Scalar width = this->boundingBoxMax()[0] - this->boundingBoxMin()[0];
626 Scalar lambda = (this->boundingBoxMax()[0] - pos[0]) / width;
627 return onUpperBoundary_(pos) && 0.5 < lambda && lambda < 2.0 / 3.0;
628 }
629
630 GlobalPosition lensLowerLeft_;
631 GlobalPosition lensUpperRight_;
632
633 DimMatrix lensK_;
634 DimMatrix outerK_;
635 MaterialLawParams lensMaterialParams_;
636 MaterialLawParams outerMaterialParams_;
637
638 Scalar temperature_;
639 Scalar eps_;
640};
641
642} // namespace Opm
643
644#endif
Soil contamination problem where DNAPL infiltrates a fully water saturated medium.
Definition: lensproblem.hh:177
Scalar temperature(const Context &, unsigned, unsigned) const
Definition: lensproblem.hh:394
static void registerParameters()
Definition: lensproblem.hh:273
void beginTimeStep()
Called by the simulator before each time integration.
Definition: lensproblem.hh:431
static std::string briefDescription()
Returns a human readable description of the problem for the help message.
Definition: lensproblem.hh:321
const MaterialLawParams & materialLawParams(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: lensproblem.hh:380
void initial(PrimaryVariables &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the initial value for a control volume.
Definition: lensproblem.hh:551
Scalar porosity(const Context &, unsigned, unsigned) const
Definition: lensproblem.hh:371
LensProblem(Simulator &simulator)
Definition: lensproblem.hh:221
void finishInit()
Called by the Opm::Simulator in order to initialize the problem.
Definition: lensproblem.hh:228
void boundary(BoundaryRateVector &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the boundary conditions for a boundary segment.
Definition: lensproblem.hh:470
const DimMatrix & intrinsicPermeability(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: lensproblem.hh:357
std::string name() const
The problem name.
Definition: lensproblem.hh:409
void endTimeStep()
Called by the simulator after each time integration.
Definition: lensproblem.hh:443
void beginIteration()
Called by the simulator before each Newton-Raphson iteration.
Definition: lensproblem.hh:437
void source(RateVector &rate, const Context &, unsigned, unsigned) const
Evaluate the source term for all phases within a given sub-control-volume.
Definition: lensproblem.hh:592
Defines the properties required for the immiscible multi-phase model.
Defines the common parameters for the porous medium multi-phase models.
Definition: blackoilnewtonmethodparams.hpp:31
Definition: blackoilmodel.hh:74
Definition: blackoilbioeffectsmodules.hh:45
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition: propertysystem.hh:233
static constexpr Scalar value
Definition: groundwaterproblem.hh:95
static constexpr Scalar value
Definition: groundwaterproblem.hh:98
static constexpr Scalar value
Definition: groundwaterproblem.hh:101
static constexpr Scalar value
Definition: groundwaterproblem.hh:104
static constexpr Scalar value
Definition: groundwaterproblem.hh:107
static constexpr Scalar value
Definition: groundwaterproblem.hh:110
Dune::YaspGrid< 2 > type
Definition: lensproblem.hh:78
The type of the DUNE grid.
Definition: basicproperties.hh:104
Opm::EffToAbsLaw< EffectiveLaw > type
Definition: lensproblem.hh:122
The material law which ought to be used (extracted from the spatial parameters)
Definition: multiphasebaseproperties.hh:55
Opm::LiquidPhase< Scalar, Opm::DNAPL< Scalar > > type
Definition: lensproblem.hh:99
The non-wetting phase for two-phase models.
Definition: immiscibleproperties.hh:44
The type of the problem.
Definition: fvbaseproperties.hh:86
Definition: lensproblem.hh:69
std::tuple< StructuredGridVanguard > InheritsFrom
Definition: lensproblem.hh:69
Opm::LiquidPhase< Scalar, Opm::SimpleH2O< Scalar > > type
Definition: lensproblem.hh:88
The wetting phase for two-phase models.
Definition: immiscibleproperties.hh:41
This file contains the flux module that uses transmissibilities.