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
Contains a class to exchange entries of a vector.
Finite volume 2p2c pressure model.
Determines the pressures and saturations of all fluid phases given the total mass of all components.
Helpers for deprecation.
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