3.4
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
fvpressuremultiphysics.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 *****************************************************************************/
24#ifndef DUMUX_FVPRESSURE2P2C_MULTIPHYSICS_HH
25#define DUMUX_FVPRESSURE2P2C_MULTIPHYSICS_HH
26
27#include <dune/common/float_cmp.hh>
28
29// dumux environment
33
34namespace Dumux {
68template<class TypeTag>
70{
76
78
81
84
86 enum
87 {
88 dim = GridView::dimension, dimWorld = GridView::dimensionworld
89 };
90 enum
91 {
92 pw = Indices::pressureW
93 };
94 enum
95 {
96 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx,
97 wCompIdx = Indices::wPhaseIdx, nCompIdx = Indices::nPhaseIdx,
98 contiWEqIdx = Indices::contiWEqIdx, contiNEqIdx = Indices::contiNEqIdx
99 };
100
101 // using declarations to abbreviate several dune classes...
102 using Element = typename GridView::Traits::template Codim<0>::Entity;
103 using Grid = typename GridView::Grid;
104 using Intersection = typename GridView::Intersection;
105
106 // convenience shortcuts for Vectors/Matrices
107 using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
108 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
109 using PhaseVector = Dune::FieldVector<Scalar, getPropValue<TypeTag, Properties::NumPhases>()>;
111
113 using EntryType = Dune::FieldVector<Scalar, 2>;
115 Problem& problem()
116 { return this->problem_; }
117 const Problem& problem() const
118 { return this->problem_; }
119public:
120 //function which assembles the system of equations to be solved
121 void assemble(bool first);
122
123 void get1pSource(EntryType& sourceEntry, const Element& elementI, const CellData& cellDataI);
124
125 void get1pStorage(EntryType& storageEntry, const Element& elementI, CellData& cellDataI);
126
127 void get1pFlux(EntryType& entries, const Intersection& intersection,
128 const CellData& cellDataI);
129
130 void get1pFluxOnBoundary(EntryType& entries,
131 const Intersection& intersection,
132 const CellData& cellDataI);
133
134 //initialize multi-physics-specific pressure model constituents
135 void initialize(bool solveTwice = false)
136 {
137 // assign whole domain to most complex subdomain, => 2p
138 int size = this->problem().gridView().size(0);
139 for (int i = 0; i < size; i++)
140 {
141 CellData& cellData = this->problem().variables().cellData(i);
142 cellData.subdomain() = 2;
143 }
144 nextSubdomain.resize(size);
146 }
147
156 void serializeEntity(std::ostream &outstream, const Element &element)
157 {
158 ParentType::serializeEntity(outstream,element);
159 int eIdxGlobal = problem().variables().index(element);
160 CellData& cellData = problem().variables().cellData(eIdxGlobal);
161 outstream <<" "<< cellData.subdomain();
162 }
163
172 void deserializeEntity(std::istream &instream, const Element &element)
173 {
174 ParentType::deserializeEntity(instream,element);
175
176 int eIdxGlobal = problem().variables().index(element);
177 CellData& cellData = problem().variables().cellData(eIdxGlobal);
178 int subdomainIdx;
179 instream >> subdomainIdx;
180 cellData.setSubdomainAndFluidStateType(subdomainIdx);
181 }
182
183
184 //constitutive functions are initialized and stored in the variables object
185 void updateMaterialLaws(bool postTimeStep = false);
186 //updates singlephase secondary variables for one cell and stores in the variables object
187 void update1pMaterialLawsInElement(const Element& elementI, CellData& cellData, bool postTimeStep);
188
193 template<class MultiWriter>
194 void addOutputVtkFields(MultiWriter &writer)
195 {
197
198 if(problem().vtkOutputLevel()>=1)
199 {
200 int size = problem().gridView().size(0);
201 // add multiphysics stuff
202 Dune::BlockVector<Dune::FieldVector<int,1> >* subdomainPtr = writer.template allocateManagedBuffer<int, 1> (size);
203 for (int i = 0; i < size; i++)
204 {
205 CellData& cellData = problem().variables().cellData(i);
206 (*subdomainPtr)[i] = cellData.subdomain();
207 }
208 writer.attachCellData(*subdomainPtr, "subdomain");
209 }
210
211 return;
212 }
213
218 FVPressure2P2CMultiPhysics(Problem& problem) : FVPressure2P2C<TypeTag>(problem),
219 gravity_(problem.gravity()), timer_(false)
220 {}
221
222protected:
223 #if HAVE_MPI
224 using ElementMapper = typename SolutionTypes::ElementMapper;
226 #endif
227
228 // subdomain map
229 Dune::BlockVector<Dune::FieldVector<int,1> > nextSubdomain;
230 const GlobalPosition& gravity_;
232 static constexpr int pressureType = getPropValue<TypeTag, Properties::PressureFormulation>();
233 Dune::Timer timer_;
234
242 enum
243 {
244 rhs = 1,
245 matrix = 0
246
247 };
248};
249
262template<class TypeTag>
264{
265 if(first)
266 {
267 ParentType::assemble(true);
268 return;
269 }
270 // initialization: set matrix this->A_ to zero
271 this->A_ = 0;
272 this->f_ = 0;
273
274 for (const auto& element : elements(problem().gridView()))
275 {
276 // get the global index of the cell
277 int eIdxGlobalI = problem().variables().index(element);
278
279 // assemble interior element contributions
280 if (element.partitionType() == Dune::InteriorEntity)
281 {
282 // get the cell data
283 CellData& cellDataI = problem().variables().cellData(eIdxGlobalI);
284
285 Dune::FieldVector<Scalar, 2> entries(0.);
286
287 /***** source term ***********/
288 if(cellDataI.subdomain() != 2)
289 problem().pressureModel().get1pSource(entries,element, cellDataI);
290 else
291 problem().pressureModel().getSource(entries,element, cellDataI, first);
292
293 this->f_[eIdxGlobalI] = entries[rhs];
294
295 /***** flux term ***********/
296 // iterate over all faces of the cell
297 for (const auto& intersection : intersections(problem().gridView(), element))
298 {
299 /************* handle interior face *****************/
300 if (intersection.neighbor())
301 {
302 int eIdxGlobalJ = problem().variables().index(intersection.outside());
303
304 if (cellDataI.subdomain() != 2
305 or problem().variables().cellData(eIdxGlobalJ).subdomain() != 2) // cell in the 1p domain
306 get1pFlux(entries, intersection, cellDataI);
307 else
308 problem().pressureModel().getFlux(entries, intersection, cellDataI, first);
309
310 //set right hand side
311 this->f_[eIdxGlobalI] -= entries[rhs];
312 // set diagonal entry
313 this->A_[eIdxGlobalI][eIdxGlobalI] += entries[matrix];
314 // set off-diagonal entry
315 this->A_[eIdxGlobalI][eIdxGlobalJ] = -entries[matrix];
316 } // end neighbor
317
318
319 /************* boundary face ************************/
320 else
321 {
322 if (cellDataI.subdomain() != 2) //the current cell in the 1p domain
323 problem().pressureModel().get1pFluxOnBoundary(entries, intersection, cellDataI);
324 else
325 problem().pressureModel().getFluxOnBoundary(entries, intersection, cellDataI, first);
326
327 //set right hand side
328 this->f_[eIdxGlobalI] += entries[rhs];
329 // set diagonal entry
330 this->A_[eIdxGlobalI][eIdxGlobalI] += entries[matrix];
331 }
332 } //end interfaces loop
333 // printmatrix(std::cout, this->A_, "global stiffness matrix", "row", 11, 3);
334
335 /***** storage term ***********/
336 if (cellDataI.subdomain() != 2) //the current cell in the 1p domain
337 problem().pressureModel().get1pStorage(entries, element, cellDataI);
338 else
339 problem().pressureModel().getStorage(entries, element, cellDataI, first);
340
341 this->f_[eIdxGlobalI] += entries[rhs];
342 // set diagonal entry
343 this->A_[eIdxGlobalI][eIdxGlobalI] += entries[matrix];
344 }
345 // assemble overlap and ghost element contributions
346 else
347 {
348 this->A_[eIdxGlobalI] = 0.0;
349 this->A_[eIdxGlobalI][eIdxGlobalI] = 1.0;
350 this->f_[eIdxGlobalI] = this->pressure()[eIdxGlobalI];
351 }
352 } // end grid traversal
353// printmatrix(std::cout, this->A_, "global stiffness matrix after assempling", "row", 11,3);
354// printvector(std::cout, this->f_, "right hand side", "row", 10);
355 return;
356}
357
369template<class TypeTag>
370void FVPressure2P2CMultiPhysics<TypeTag>::get1pSource(Dune::FieldVector<Scalar, 2>& sourceEntry,
371 const Element& elementI, const CellData& cellDataI)
372{
373 sourceEntry=0.;
374
375 // cell volume & perimeter, assume linear map here
376 Scalar volume = elementI.geometry().volume();
377 int subdomainIdx = cellDataI.subdomain();
378
379 /****************implement source************************/
380 PrimaryVariables source(NAN);
381 problem().source(source, elementI);
382 source[1+subdomainIdx] /= cellDataI.density(subdomainIdx);
383
384 sourceEntry[1] = volume * source[1+subdomainIdx];
385
386 return;
387}
388
402template<class TypeTag>
403void FVPressure2P2CMultiPhysics<TypeTag>::get1pStorage(Dune::FieldVector<Scalar, 2>& storageEntry,
404 const Element& elementI,
405 CellData& cellDataI)
406{
407 storageEntry = 0.;
408 // cell index
409 int eIdxGlobalI = problem().variables().index(elementI);
410 int presentPhaseIdx = cellDataI.subdomain();
411 Scalar volume = elementI.geometry().volume();
412
413 // determine maximum error to scale error-term
414 Scalar timestep_ = problem().timeManager().timeStepSize();
415
416 // compressibility term: 1p domain, so no dv_dp calculated
417 if (true)
418 {
419 Scalar& incp = this->incp_;
420
421 // numerical derivative of fluid volume with respect to pressure
422 PhaseVector p_(incp);
423 p_[nPhaseIdx] += cellDataI.pressure(nPhaseIdx);
424 p_[wPhaseIdx] += cellDataI.pressure(wPhaseIdx);
425
426 Scalar sumC = (cellDataI.massConcentration(wCompIdx) + cellDataI.massConcentration(nCompIdx));
427 Scalar Z0 = cellDataI.massConcentration(wCompIdx) / sumC;
428 // initialize simple fluidstate object
431 flashSolver.concentrationFlash1p2c(pseudoFluidState, Z0, p_, cellDataI.subdomain(),
432 cellDataI.temperature(wPhaseIdx));
433
434 Scalar v_ = 1. / pseudoFluidState.density(presentPhaseIdx);
435 cellDataI.dv_dp() = (sumC * ( v_ - (1. /cellDataI.density(presentPhaseIdx)))) /incp;
436
437 if (cellDataI.dv_dp()>0)
438 {
439 // dV_dp > 0 is unphysical: Try inverse increment for secant
440 Dune::dinfo << "dv_dp larger 0 at Idx " << eIdxGlobalI << " , try and invert secant"<< std::endl;
441
442 p_ -= 2*incp;
443 flashSolver.concentrationFlash1p2c(pseudoFluidState, Z0, p_, cellDataI.subdomain(),
444 cellDataI.temperature(wPhaseIdx));
445 v_ = 1. / pseudoFluidState.density(presentPhaseIdx);
446 cellDataI.dv_dp() = (sumC * ( v_ - (1. /cellDataI.density(presentPhaseIdx)))) /incp;
447 // dV_dp > 0 is unphysical: Try inverse increment for secant
448 if (cellDataI.dv_dp()>0)
449 {
450 Dune::dinfo <<__FILE__<< "dv_dp still larger 0 after inverting secant. regularize"<< std::endl;
451 cellDataI.dv_dp() *= -1;
452 }
453 }
454
455
456 Scalar compress_term = cellDataI.dv_dp() / timestep_;
457
458 storageEntry[matrix] -= compress_term*volume;
459 storageEntry[rhs] -= cellDataI.pressure(pressureType) * compress_term * volume;
460
461 using std::isnan;
462 using std::isinf;
463 if (isnan(compress_term) ||isinf(compress_term))
464 DUNE_THROW(Dune::MathError, "Compressibility term leads to NAN matrix entry at index " << eIdxGlobalI);
465
466 if(!getPropValue<TypeTag, Properties::EnableCompressibility>())
467 DUNE_THROW(Dune::NotImplemented, "Compressibility is switched off???");
468 }
469
470 // Abort error damping if there will be a possibly tiny timestep compared with last one
471 // This might be the case if the episode or simulation comes to an end.
472 if( problem().timeManager().episodeWillBeFinished()
473 || problem().timeManager().willBeFinished())
474 {
475 problem().variables().cellData(eIdxGlobalI).errorCorrection() = 0.;
476 return;
477 }
478
479 // error reduction routine: volumetric error is damped and inserted to right hand side
480 // if damping is not done, the solution method gets unstable!
481 problem().variables().cellData(eIdxGlobalI).volumeError() /= timestep_;
482 Scalar maxError = this->maxError_;
483 Scalar erri = fabs(cellDataI.volumeError());
484 Scalar x_lo = this->ErrorTermLowerBound_;
485 Scalar x_mi = this->ErrorTermUpperBound_;
486 Scalar fac = this->ErrorTermFactor_;
487 if (pressureType == pw)
488 fac = 0.1*this->ErrorTermFactor_;
489 Scalar lofac = 0.;
490 Scalar hifac = 0.;
491
492 if ((erri*timestep_ > 5e-5) && (erri > x_lo * maxError) && (!problem().timeManager().willBeFinished()))
493 {
494 if (erri <= x_mi * maxError)
495 storageEntry[rhs] +=
496 problem().variables().cellData(eIdxGlobalI).errorCorrection() =
497 fac* (1-x_mi*(lofac-1)/(x_lo-x_mi) + (lofac-1)/(x_lo-x_mi)*erri/maxError)
498 * cellDataI.volumeError() * volume;
499 else
500 storageEntry[rhs] +=
501 problem().variables().cellData(eIdxGlobalI).errorCorrection() =
502 fac * (1 + x_mi - hifac*x_mi/(1-x_mi) + (hifac/(1-x_mi)-1)*erri/maxError)
503 * cellDataI.volumeError() * volume;
504 }
505 else
506 problem().variables().cellData(eIdxGlobalI).errorCorrection()=0 ;
507
508 return;
509}
510
525template<class TypeTag>
526void FVPressure2P2CMultiPhysics<TypeTag>::get1pFlux(Dune::FieldVector<Scalar, 2>& entries,
527 const Intersection& intersection, const CellData& cellDataI)
528{
529 entries = 0.;
530 auto elementI = intersection.inside();
531
532 // get global coordinate of cell center
533 const GlobalPosition& globalPos = elementI.geometry().center();
534
535 // get absolute permeability
536 DimMatrix permeabilityI(problem().spatialParams().intrinsicPermeability(elementI));
537
538 // get normal vector
539 const GlobalPosition& unitOuterNormal = intersection.centerUnitOuterNormal();
540
541 // get face volume
542 Scalar faceArea = intersection.geometry().volume();
543
544 // access neighbor
545 auto neighbor = intersection.outside();
546 int eIdxGlobalJ = problem().variables().index(neighbor);
547 CellData& cellDataJ = problem().variables().cellData(eIdxGlobalJ);
548
549 // gemotry info of neighbor
550 const GlobalPosition& globalPosNeighbor = neighbor.geometry().center();
551
552 // distance vector between barycenters
553 GlobalPosition distVec = globalPosNeighbor - globalPos;
554
555 // compute distance between cell centers
556 Scalar dist = distVec.two_norm();
557
558 GlobalPosition unitDistVec(distVec);
559 unitDistVec /= dist;
560
561 DimMatrix permeabilityJ
562 = problem().spatialParams().intrinsicPermeability(neighbor);
563
564 // compute vectorized permeabilities
565 DimMatrix meanPermeability(0);
566 harmonicMeanMatrix(meanPermeability, permeabilityI, permeabilityJ);
567
568 Dune::FieldVector<Scalar, dim> permeability(0);
569 meanPermeability.mv(unitDistVec, permeability);
570
571 // due to "safety cell" around subdomain, both cells I and J
572 // have single-phase conditions, although one is in 2p domain.
573 using std::min;
574 int phaseIdx = min(cellDataI.subdomain(), cellDataJ.subdomain());
575
576 Scalar rhoMean = 0.5 * (cellDataI.density(phaseIdx) + cellDataJ.density(phaseIdx));
577
578 // 1p => no pc => only 1 pressure, potential
579 Scalar potential = (cellDataI.pressure(phaseIdx) - cellDataJ.pressure(phaseIdx)) / dist;
580
581 potential += rhoMean * (unitDistVec * gravity_);
582
583 Scalar lambda;
584
585 if (potential > 0.)
586 {
587 lambda = cellDataI.mobility(phaseIdx);
588 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiWEqIdx, false); // store in cellJ since cellI is const
589 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiNEqIdx, false); // store in cellJ since cellI is const
590 }
591 else if (potential < 0.)
592 {
593 lambda = cellDataJ.mobility(phaseIdx);
594 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiWEqIdx, true);
595 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiNEqIdx, true);
596 }
597 else
598 {
599 lambda = harmonicMean(cellDataI.mobility(phaseIdx) , cellDataJ.mobility(phaseIdx));
600 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiWEqIdx, false);
601 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiNEqIdx, false);
602 }
603
604 entries[0] = lambda * faceArea * fabs(permeability * unitOuterNormal) / (dist);
605 entries[1] = rhoMean * lambda;
606 entries[1] *= faceArea * fabs(permeability * unitOuterNormal) * (unitDistVec * gravity_);
607
608 return;
609}
610
628template<class TypeTag>
629void FVPressure2P2CMultiPhysics<TypeTag>::get1pFluxOnBoundary(Dune::FieldVector<Scalar, 2>& entries,
630 const Intersection& intersection, const CellData& cellDataI)
631{
632 entries = 0.;
633 // get global coordinate of cell center
634 auto elementI = intersection.inside();
635 const GlobalPosition& globalPos = elementI.geometry().center();
636// int eIdxGlobalI = problem().variables().index(elementI);
637 int phaseIdx = cellDataI.subdomain();
638
639 // get normal vector
640 const GlobalPosition& unitOuterNormal = intersection.centerUnitOuterNormal();
641 // get face volume
642 Scalar faceArea = intersection.geometry().volume();
643
644 // center of face in global coordinates
645 const GlobalPosition& globalPosFace = intersection.geometry().center();
646
647 // geometrical information
648 GlobalPosition distVec(globalPosFace - globalPos);
649 Scalar dist = distVec.two_norm();
650 GlobalPosition unitDistVec(distVec);
651 unitDistVec /= dist;
652
653 //get boundary condition for boundary face center
654 BoundaryTypes bcType;
655 problem().boundaryTypes(bcType, intersection);
656
657 // prepare pressure boundary condition
658 PhaseVector pressBC(0.);
659
660 /********** Dirichlet Boundary *************/
661 if (bcType.isDirichlet(Indices::pressureEqIdx))
662 {
663 // get absolute permeability
664 DimMatrix permeabilityI(problem().spatialParams().intrinsicPermeability(elementI));
665 if(this->regulateBoundaryPermeability)
666 {
667 int axis = intersection.indexInInside() / 2;
668 if(permeabilityI[axis][axis] < this->minimalBoundaryPermeability)
669 permeabilityI[axis][axis] = this->minimalBoundaryPermeability;
670 }
671 // get mobilities and fractional flow factors
672 Scalar lambdaI = cellDataI.mobility(phaseIdx);
673
674 //permeability vector at boundary
675 Dune::FieldVector<Scalar, dim> permeability(0);
676 permeabilityI.mv(unitDistVec, permeability);
677
678 // create a fluid state for the boundary
679 FluidState BCfluidState;
680
681 //read boundary values
682 PrimaryVariables primaryVariablesOnBoundary(NAN);
683 problem().dirichlet(primaryVariablesOnBoundary, intersection);
684
685 {
686 // read boundary values
687 problem().transportModel().evalBoundary(globalPosFace,
688 intersection,
689 BCfluidState,
690 pressBC);
691
692 // determine fluid properties at the boundary
693 Scalar densityBound =
694 FluidSystem::density(BCfluidState, phaseIdx);
695 Scalar viscosityBound =
696 FluidSystem::viscosity(BCfluidState, phaseIdx);
697
698 // mobility at the boundary
699 Scalar lambdaBound = 0.;
700 switch (getPropValue<TypeTag, Properties::BoundaryMobility>())
701 {
702 case Indices::satDependent:
703 {
704 lambdaBound = BCfluidState.saturation(phaseIdx) / viscosityBound;
705 break;
706 }
707 case Indices::permDependent:
708 {
709 const auto fluidMatrixInteraction = problem().spatialParams().fluidMatrixInteractionAtPos(elementI.geometry().center());
710 if (phaseIdx == wPhaseIdx)
711 lambdaBound = fluidMatrixInteraction.krw(BCfluidState.saturation(wPhaseIdx)) / viscosityBound;
712 else
713 lambdaBound = fluidMatrixInteraction.krn(BCfluidState.saturation(wPhaseIdx)) / viscosityBound;
714 break;
715 }
716 }
717 Scalar rhoMean = 0.5 * (cellDataI.density(phaseIdx) + densityBound);
718
719 Scalar potential = 0;
720
721 //calculate potential gradient: pc = 0;
722 potential = (cellDataI.pressure(phaseIdx) - pressBC[phaseIdx]) / dist;
723
724 potential += rhoMean * (unitDistVec * gravity_);
725
726 Scalar lambda(0.);
727
728 if (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potential, 0.0, 1.0e-30))
729 {
730 lambda = 0.5*(lambdaI + lambdaBound);
731 }
732 else if (potential > 0.)
733 {
734 lambda = lambdaI;
735 }
736 else
737 {
738 lambda = lambdaBound;
739 }
740
741 //calculate current matrix entry
742 Scalar entry(0.), rightEntry(0.);
743 entry = lambda * (fabs(permeability * unitOuterNormal) / dist) * faceArea;
744
745 //calculate right hand side
746 rightEntry = lambda * rhoMean * fabs(permeability * unitOuterNormal)
747 * faceArea ;
748
749 // set diagonal entry and right hand side entry
750 entries[0] += entry;
751 entries[1] += entry * primaryVariablesOnBoundary[Indices::pressureEqIdx];
752 entries[1] -= rightEntry * (gravity_ * unitDistVec);
753 } //end of if(first) ... else{...
754 } // end dirichlet
755
756 /**********************************
757 * set neumann boundary condition
758 **********************************/
759 else if(bcType.isNeumann(Indices::pressureEqIdx))
760 {
761 PrimaryVariables J(NAN);
762 problem().neumann(J, intersection);
763 J[1+phaseIdx] /= cellDataI.density(phaseIdx);
764
765 entries[1] -= J[1+phaseIdx] * faceArea;
766 }
767 else
768 DUNE_THROW(Dune::NotImplemented, "Boundary Condition neither Dirichlet nor Neumann!");
769
770
771 return;
772}
773
774
786template<class TypeTag>
788{
789 //get timestep for error term
790 Scalar maxError = 0.;
791
792 // next subdomain map
793 if (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(problem().timeManager().time(), 0.0, 1.0e-30))
794 nextSubdomain = 2; // start with complicated sub in initialization
795 else
796 nextSubdomain = -1; // reduce complexity after first TS
797
798 // Loop A) through leaf grid
799 for (const auto& element : elements(problem().gridView()))
800 {
801 // get global coordinate of cell center
802 int eIdxGlobal = problem().variables().index(element);
803 CellData& cellData = problem().variables().cellData(eIdxGlobal);
804
805 if(cellData.subdomain() == 2) // complex
806 {
807 this->updateMaterialLawsInElement(element, postTimeStep);
808
809 // check subdomain consistency
810 timer_.start();
811 // enshure we are not at source
812 // get sources from problem
813 PrimaryVariables source(NAN);
814 problem().source(source, element);
815
816 if ((cellData.saturation(wPhaseIdx) > 0.0 && cellData.saturation(wPhaseIdx) < 1.0)
817 || Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(source.one_norm(), 0.0, 1.0e-30)) // cell still 2p
818 {
819 // mark this element
820 nextSubdomain[eIdxGlobal] = 2;
821
822 // mark neighbors
823 for (const auto& intersection : intersections(problem().gridView(), element))
824 {
825 if (intersection.neighbor())
826 {
827 int eIdxGlobalJ = problem().variables().index(intersection.outside());
828 // mark neighbor Element
829 nextSubdomain[eIdxGlobalJ] = 2;
830 }
831 }
832 }
833 else if(nextSubdomain[eIdxGlobal] != 2)// update next subdomain if possible
834 {
835 if(Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(cellData.saturation(wPhaseIdx), 0.0, 1.0e-30))
836 nextSubdomain[eIdxGlobal] = wPhaseIdx;
837 else if (Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(cellData.saturation(nPhaseIdx), 0.0, 1.0e-30))
838 nextSubdomain[eIdxGlobal] = nPhaseIdx;
839 }
840 timer_.stop();
841 // end subdomain check
842 }// end complex domain
843 else if (nextSubdomain[eIdxGlobal] != 2) //check if cell remains in simple subdomain
844 nextSubdomain[eIdxGlobal] = cellData.subdomain();
845
846 } //end define complex area of next subdomain
847
848 timer_.start();
849 //communicate next subdomain if parallel
850 #if HAVE_MPI
851 // communicate updated values
852 DataHandle dataHandle(problem().variables().elementMapper(), nextSubdomain);
853 problem().gridView().template communicate<DataHandle>(dataHandle,
854 Dune::InteriorBorder_All_Interface,
855 Dune::ForwardCommunication);
856 #endif
857
858 // Loop B) thorugh leaf grid
859 // investigate cells that were "simple" in current TS
860 for (const auto& element : elements(problem().gridView()))
861 {
862 int eIdxGlobal = problem().variables().index(element);
863 CellData& cellData = problem().variables().cellData(eIdxGlobal);
864
865 // store old subdomain information and assign new info
866 int oldSubdomainI = cellData.subdomain();
867 cellData.subdomain() = nextSubdomain[eIdxGlobal];
868
869 //first check if simple will become complicated
870 if(oldSubdomainI != 2
871 && nextSubdomain[eIdxGlobal] == 2)
872 {
873 // use complex update of the fluidstate
874 timer_.stop();
875 this->updateMaterialLawsInElement(element, postTimeStep);
876 timer_.start();
877 }
878 else if(oldSubdomainI != 2
879 && nextSubdomain[eIdxGlobal] != 2) // will be simple and was simple
880 {
881 // perform simple update
882 this->update1pMaterialLawsInElement(element, cellData, postTimeStep);
883 }
884 //else
885 // a) will remain complex -> everything already done in loop A
886 // b) will be simple and was complex: complex FS available, so next TS
887 // will use comlex FS, next updateMaterialLaw will transform to simple
888
889 using std::max;
890 maxError = max(maxError, fabs(cellData.volumeError()));
891 }// end grid traversal
892 this->maxError_ = maxError/problem().timeManager().timeStepSize();
893
894 timer_.stop();
895
896 if(problem().timeManager().willBeFinished() or problem().timeManager().episodeWillBeFinished())
897 Dune::dinfo << "Subdomain routines took " << timer_.elapsed() << " seconds" << std::endl;
898
899 return;
900}
901
912template<class TypeTag>
913void FVPressure2P2CMultiPhysics<TypeTag>::update1pMaterialLawsInElement(const Element& elementI, CellData& cellData, bool postTimeStep)
914{
915 // get global coordinate of cell center
916 GlobalPosition globalPos = elementI.geometry().center();
917 int eIdxGlobal = problem().variables().index(elementI);
918
919 // determine which phase should be present
920 int presentPhaseIdx = cellData.subdomain(); // this is already =nextSubomainIdx
921
922 // reset to calculate new timeStep if we are at the end of a time step
923 if(postTimeStep)
924 cellData.reset();
925
926 // acess the simple fluid state and prepare for manipulation
927 auto& pseudoFluidState = cellData.manipulateSimpleFluidState();
928
929 const auto fluidMatrixInteraction = problem().spatialParams().fluidMatrixInteractionAtPos(elementI.geometry().center());
930
931 // prepare phase pressure for fluid state
932 // both phase pressures are necessary for the case 1p domain is assigned for
933 // the next 2p subdomain
934 PhaseVector pressure(0.);
935 Scalar pc = 0;
936 if(getPropValue<TypeTag, Properties::EnableCapillarity>())
937 pc = fluidMatrixInteraction.pc(((presentPhaseIdx == wPhaseIdx) ? 1. : 0.)); // assign sw = 1 if wPhase present, else 0
938 if(pressureType == wPhaseIdx)
939 {
940 pressure[wPhaseIdx] = this->pressure(eIdxGlobal);
941 pressure[nPhaseIdx] = this->pressure(eIdxGlobal)+pc;
942 }
943 else
944 {
945 pressure[wPhaseIdx] = this->pressure(eIdxGlobal)-pc;
946 pressure[nPhaseIdx] = this->pressure(eIdxGlobal);
947 }
948
949 // get the overall mass of first component: Z0 = C^0 / (C^0+C^1) [-]
950 Scalar sumConc = cellData.massConcentration(wCompIdx)
951 + cellData.massConcentration(nCompIdx);
952 Scalar Z0 = cellData.massConcentration(wCompIdx)/ sumConc;
953
955 flashSolver.concentrationFlash1p2c(pseudoFluidState, Z0, pressure, presentPhaseIdx, problem().temperatureAtPos(globalPos));
956
957 // write stuff in fluidstate
958 assert(presentPhaseIdx == pseudoFluidState.presentPhaseIdx());
959
960// cellData.setSimpleFluidState(pseudoFluidState);
961
962 // initialize viscosities
963 cellData.setViscosity(presentPhaseIdx, FluidSystem::viscosity(pseudoFluidState, presentPhaseIdx));
964
965 // initialize mobilities
966 if(presentPhaseIdx == wPhaseIdx)
967 {
968 cellData.setMobility(wPhaseIdx,
969 fluidMatrixInteraction.krw(pseudoFluidState.saturation(wPhaseIdx)) / cellData.viscosity(wPhaseIdx));
970 cellData.setMobility(nPhaseIdx, 0.);
971 }
972 else
973 {
974 cellData.setMobility(nPhaseIdx,
975 fluidMatrixInteraction.krn(pseudoFluidState.saturation(wPhaseIdx)) / cellData.viscosity(nPhaseIdx));
976 cellData.setMobility(wPhaseIdx, 0.);
977 }
978
979 // error term handling
980 Scalar vol(0.);
981 vol = sumConc / pseudoFluidState.density(presentPhaseIdx);
982
983 if (Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(problem().timeManager().timeStepSize(), 0.0, 1.0e-30))
984 cellData.volumeError() = (vol - problem().spatialParams().porosity(elementI));
985 return;
986}
987
988}//end namespace Dumux
989#endif
Determines the pressures and saturations of all fluid phases given the total mass of all components.
Contains a class to exchange entries of a vector.
Finite volume 2p2c pressure model.
constexpr Scalar harmonicMean(Scalar x, Scalar y, Scalar wx=1.0, Scalar wy=1.0) noexcept
Calculate the (weighted) harmonic mean of two scalar values.
Definition: math.hh:69
void harmonicMeanMatrix(Dune::FieldMatrix< Scalar, m, n > &K, const Dune::FieldMatrix< Scalar, m, n > &Ki, const Dune::FieldMatrix< Scalar, m, n > &Kj)
Calculate the harmonic mean of a fixed-size matrix.
Definition: math.hh:109
Definition: adapt.hh:29
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type GetProp
get the type of a property
Definition: propertysystem.hh:141
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:150
std::string viscosity(int phaseIdx) noexcept
I/O name of viscosity for multiphase systems.
Definition: name.hh:74
std::string permeability() noexcept
I/O name of permeability.
Definition: name.hh:143
std::string pressure(int phaseIdx) noexcept
I/O name of pressure for multiphase systems.
Definition: name.hh:34
std::string density(int phaseIdx) noexcept
I/O name of density for multiphase systems.
Definition: name.hh:65
Scalar volume(Shape shape, Scalar inscribedRadius)
Returns the volume of a given geometry based on the inscribed radius.
Definition: poreproperties.hh:73
Flash calculation routines for compositional sequential models.
Definition: compositionalflash.hh:51
static void concentrationFlash1p2c(FluidState1p2c &fluidState, const Scalar &Z0, const Dune::FieldVector< Scalar, numPhases > phasePressure, const int presentPhaseIdx, const Scalar &temperature)
The simplest possible update routine for 1p2c "flash" calculations.
Definition: compositionalflash.hh:179
Container for compositional variables in a 1p2c situation.
Definition: pseudo1p2c.hh:44
Scalar density(int phaseIdx) const
Set the density of a phase .
Definition: pseudo1p2c.hh:109
Scalar temperature(int phaseIdx) const
Returns the temperature of the fluids .
Definition: pseudo1p2c.hh:189
A data handle class to exchange entries of a vector.
Definition: vectorcommdatahandle.hh:78
The finite volume model for the solution of the compositional pressure equation.
Definition: fvpressure.hh:73
Problem & problem_
Definition: fvpressure.hh:181
Dune::FieldVector< Scalar, 2 > EntryType
Definition: fvpressure.hh:135
void addOutputVtkFields(MultiWriter &writer)
Write data files.
Definition: fvpressurecompositional.hh:169
The finite volume model for the solution of the compositional pressure equation.
Definition: fvpressuremultiphysics.hh:70
Dune::BlockVector< Dune::FieldVector< int, 1 > > nextSubdomain
vector holding next subdomain
Definition: fvpressuremultiphysics.hh:229
void get1pFluxOnBoundary(EntryType &entries, const Intersection &intersection, const CellData &cellDataI)
The compositional single-phase flux in the multiphysics framework.
Definition: fvpressuremultiphysics.hh:629
const GlobalPosition & gravity_
Definition: fvpressuremultiphysics.hh:230
void update1pMaterialLawsInElement(const Element &elementI, CellData &cellData, bool postTimeStep)
updates secondary variables of one single phase cell
Definition: fvpressuremultiphysics.hh:913
void assemble(bool first)
function which assembles the system of equations to be solved
Definition: fvpressuremultiphysics.hh:263
void addOutputVtkFields(MultiWriter &writer)
Write data files.
Definition: fvpressuremultiphysics.hh:194
FVPressure2P2CMultiPhysics(Problem &problem)
Constructs a FVPressure2P2CPC object.
Definition: fvpressuremultiphysics.hh:218
void get1pStorage(EntryType &storageEntry, const Element &elementI, CellData &cellDataI)
Assembles the storage term for a 1p cell in a multiphysics framework.
Definition: fvpressuremultiphysics.hh:403
void updateMaterialLaws(bool postTimeStep=false)
constitutive functions are updated once if new concentrations are calculated and stored in the variab...
Definition: fvpressuremultiphysics.hh:787
void get1pSource(EntryType &sourceEntry, const Element &elementI, const CellData &cellDataI)
Assembles the source term.
Definition: fvpressuremultiphysics.hh:370
Dune::Timer timer_
A timer for the time spent on the multiphysics framework.
Definition: fvpressuremultiphysics.hh:233
@ rhs
index for the right hand side entry
Definition: fvpressuremultiphysics.hh:244
@ matrix
index for the global matrix entry
Definition: fvpressuremultiphysics.hh:245
void serializeEntity(std::ostream &outstream, const Element &element)
Function for serialization of the pressure field.
Definition: fvpressuremultiphysics.hh:156
void deserializeEntity(std::istream &instream, const Element &element)
Function for deserialization of the pressure field.
Definition: fvpressuremultiphysics.hh:172
static constexpr int pressureType
gives kind of pressure used ( , , )
Definition: fvpressuremultiphysics.hh:232
void initialize(bool solveTwice=false)
Definition: fvpressuremultiphysics.hh:135
typename SolutionTypes::ElementMapper ElementMapper
Definition: fvpressuremultiphysics.hh:224
void get1pFlux(EntryType &entries, const Intersection &intersection, const CellData &cellDataI)
The compositional single-phase flux in the multiphysics framework.
Definition: fvpressuremultiphysics.hh:526
The finite volume base class for the solution of a pressure equation.
Definition: sequential/cellcentered/pressure.hh:49
void initialize()
Initialize pressure model.
Definition: sequential/cellcentered/pressure.hh:213
void deserializeEntity(std::istream &instream, const Element &element)
Function for deserialization of the pressure field.
Definition: sequential/cellcentered/pressure.hh:264
void serializeEntity(std::ostream &outstream, const Element &element)
Function for serialization of the pressure field.
Definition: sequential/cellcentered/pressure.hh:251