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