3.3.0
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
fv3dpressureadaptive.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_FV3DPRESSURE2P2C_ADAPTIVE_HH
25#define DUMUX_FV3DPRESSURE2P2C_ADAPTIVE_HH
26
27// dune environent:
28#include <dune/istl/bvector.hh>
29#include <dune/istl/operators.hh>
30#include <dune/istl/solvers.hh>
31#include <dune/istl/preconditioners.hh>
32
33// dumux environment
35#include <dumux/common/math.hh>
39
40// include pressure model from Markus
44
45namespace Dumux {
46namespace Properties {
47template<class TypeTag>
48struct MPFAInteractionVolume<TypeTag, TTag::SequentialTwoPTwoCAdaptive> { using type = FvMpfaL3dInteractionVolumeAdaptive<TypeTag>; };
49template<class TypeTag>
50struct MPFAInteractionVolumeContainer<TypeTag, TTag::SequentialTwoPTwoCAdaptive> { using type = FvMpfaL3d2P2CInteractionVolumeContainerAdaptive<TypeTag>; };
51} // end namespace Properties
52
79template<class TypeTag> class FV3dPressure2P2CAdaptive
80: public FVPressure2P2CMultiPhysics<TypeTag>
81{
82 //the model implementation
86
91
93
96
99
101 enum
102 {
103 dim = GridView::dimension, dimWorld = GridView::dimensionworld,
104 NumPhases = getPropValue<TypeTag, Properties::NumPhases>(), NumComponents = getPropValue<TypeTag, Properties::NumComponents>()
105 };
106 enum
107 {
108 pw = Indices::pressureW,
109 pn = Indices::pressureN,
110 pGlobal = Indices::pressureGlobal,
111 Sw = Indices::saturationW,
112 Sn = Indices::saturationN
113 };
114 enum
115 {
116 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx,
117 wCompIdx = Indices::wPhaseIdx, nCompIdx = Indices::nPhaseIdx,
118 contiWEqIdx = Indices::contiWEqIdx, contiNEqIdx = Indices::contiNEqIdx
119 };
120 enum
121 {
122 rhs = BaseType::rhs, matrix = BaseType::matrix,
123 };
124
125 // using declarations to abbreviate several dune classes...
126 using Vertex = typename GridView::Traits::template Codim<dim>::Entity;
127 using Element = typename GridView::Traits::template Codim<0>::Entity;
128
129 using Grid = typename GridView::Grid;
130 using Intersection = typename GridView::Intersection;
131 using IntersectionIterator = typename GridView::IntersectionIterator;
132
133 // convenience shortcuts for Vectors/Matrices
134 using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
135 using TransmissivityMatrix = Dune::FieldVector<Scalar,dim+1>;
136 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
137 using PhaseVector = Dune::FieldVector<Scalar, getPropValue<TypeTag, Properties::NumPhases>()>;
138 using ComponentVector = Dune::FieldVector<Scalar, getPropValue<TypeTag, Properties::NumComponents>()>;
140
141 // the typenames used for the stiffness matrix and solution vector
144
145 // Dumux MPFA types
147 using InteractionVolume = typename InteractionVolumeContainer::InteractionVolume;
148
149protected:
151 Problem& problem()
152 {
153 return this->problem_;
154 }
155 const Problem& problem() const
156 {
157 return this->problem_;
158 }
160
161public:
162 void update()
163 {
167 {
170 new InteractionVolumeContainer(problem());
171
173 }
174 asImp_().initializeMatrix();
176 }
177 //initializes the matrix to store the system of equations
178 void initializeMatrix();
181
182 void initialize(bool solveTwice = false){
184 {
187 new InteractionVolumeContainer(problem());
188
190 }
191 ParentType::initialize(solveTwice);
192 }
193
194 //function which assembles the system of equations to be solved
195 void assemble(bool first);
196
197 void getMpfaFlux(const IntersectionIterator&, const CellData&);
198
199 void get1pMpfaFlux(const IntersectionIterator&, const CellData&);
200
201 //constitutive functions are initialized and stored in the variables object
202 void updateMaterialLaws(bool fromPostTimestep = false);
203
204 // mpfa transmissibilities
205 int computeTransmissibilities(const IntersectionIterator&,
206 TransmissivityMatrix&,
207 GlobalPosition&,
208 int&,
209 GlobalPosition&,
210 int&);
211
214 {
215 int gridSize = problem().gridView().size(0);
216 this->pressure().resize(gridSize);
217
218 for (const auto& element : elements(problem().gridView()))
219 {
220 // get the global index of the cell
221 int eIdxGlobalI = problem().variables().index(element);
222
223 // assemble interior element contributions
224 if (element.partitionType() == Dune::InteriorEntity)
225 {
226 this->pressure()[eIdxGlobalI]
227 = problem().variables().cellData(eIdxGlobalI).pressure(this->pressureType);
228 }
229 }
230#if HAVE_MPI
231 // communicate updated values
233 using ElementMapper = typename SolutionTypes::ElementMapper;
235 using DataHandle = VectorCommDataHandleEqual<ElementMapper, PressureSolution, 0/*elementCodim*/>;
236
237 DataHandle dataHandle(problem().variables().elementMapper(), this->pressure());
238 problem().gridView().template communicate<DataHandle>(dataHandle,
239 Dune::InteriorBorder_All_Interface,
240 Dune::ForwardCommunication);
241#endif
242 }
243
248 FV3dPressure2P2CAdaptive(Problem& problem) : FVPressure2P2CMultiPhysics<TypeTag>(problem),
249 enableMPFA(false),
251 {
253 enableMPFA = getParam<bool>("GridAdapt.EnableMultiPointFluxApproximation");
254
255 maxInteractionVolumes = getParam<int>("GridAdapt.MaxInteractionVolumes");
256 }
257
258private:
260 Implementation &asImp_()
261 { return *static_cast<Implementation *>(this);}
262
264 const Implementation &asImp_() const
265 { return *static_cast<const Implementation *>(this);}
266
267 int searchCommonVertex_(const Intersection& is, Vertex& vertex)
268 {
269 /******* get corner of interest ************/
270 // search through corners of large cell with isIt
271 int localIdxLarge = 0;
272 for(localIdxLarge = 0; localIdxLarge < is.inside().subEntities(dim); ++localIdxLarge)
273 {
274 auto vLarge = is.inside().template subEntity<dim>(localIdxLarge);
275
276 // search through corners of small cell with isIt
277 for(int verticeSmall = 0; verticeSmall<is.outside().subEntities(dim); ++verticeSmall)
278 {
279 auto vSmall = is.outside().template subEntity<dim>(verticeSmall);
280
281 if(problem().variables().index(vSmall) == problem().variables().index(vLarge) )
282 {
283 vertex = vSmall;
284 return localIdxLarge;
285 }
286 }
287 }
288 return -1;
289 }
290
291protected:
292 int transmissibilityAdapter_(const IntersectionIterator& isIt,
293 InteractionVolume& interactionVolume,
294 const int& subVolumeFaceIdx,
295 bool properFluxDirection,
296 Element& additional2,
297 Element& additional3,
298 TransmissivityMatrix& additionalT);
299
300 std::map<int, std::vector<int> > irregularCellMap_;
304
306 InteractionVolumeContainer* interactionVolumesContainer_;
309};
310
312template<class TypeTag>
314{
315 int gridSize_ = problem().gridView().size(0);
316 // update RHS vector, matrix
317 this->A_.setSize (gridSize_,gridSize_); //
318 this->f_.resize(gridSize_);
319 irregularCellMap_.clear();
320
321 this->initializeMatrixRowSize();
322 this->A_.endrowsizes();
323 this->initializeMatrixIndices();
324 this->A_.endindices();
325}
326
328template<class TypeTag>
330{
331 // determine matrix row sizes
332 for (const auto& element : elements(problem().gridView()))
333 {
334 // cell index
335 int eIdxGlobalI = problem().variables().index(element);
336 CellData& cellDataI = problem().variables().cellData(eIdxGlobalI);
337
338 // initialize row size
339 int rowSize = 1;
340
341 // set perimeter to zero
342 cellDataI.perimeter() = 0;
343
344 // prepare storage for all found 3rd cells
345 std::vector<int> foundAdditionals;
346
347 int numberOfIntersections = 0;
348 // run through all intersections with neighbors
349 for (const auto& intersection : intersections(problem().gridView(), element))
350 {
351 cellDataI.perimeter() += intersection.geometry().volume();
352 numberOfIntersections++;
353 if (intersection.neighbor())
354 {
355 rowSize++;
356
357 // special treatment for hanging nodes in the mpfa case
358 if (enableMPFA && (element.level() < intersection.outside().level()))
359 {
360 // each cell might have 4 hanging nodes with 4 irregular neighbors each
361 // get global ID of Interface from larger cell
362 int intersectionID = problem().grid().localIdSet().subId(element,
363 intersection.indexInInside(), 1);
364 //index outside
365 int eIdxGlobalJ = problem().variables().index(intersection.outside());
366
367 // add Entry of current neighbor cell to the IS seen from large cell
368 irregularCellMap_[intersectionID].push_back(eIdxGlobalJ);
369 }
370 }
371 }
372 cellDataI.fluxData().resize(numberOfIntersections);
373 this->A_.incrementrowsize(eIdxGlobalI, rowSize);
374 } //end first loop (that already reserved enough space for the MPFA connections on hanging nodes)
375
376 // second loop to determine which matrix entries will be occupied
377 if(enableMPFA && maxInteractionVolumes>1)
378 {
379 //prepare map for additional cell-connection through mpfa
380 std::multimap<int, int> addionalRelations;
381 using IntPair = std::pair<int,int>;
382 std::pair<std::multimap<int,int>::iterator,std::multimap<int,int>::iterator> range;
383 std::multimap<int,int>::iterator rangeIt;
384
385 // second loop for further sub-faces
386 for (const auto& element : elements(problem().gridView()))
387 {
388 // cell index
389 int eIdxGlobalI = problem().variables().index(element);
390 // run through all intersections with neighbors
391 const auto isEndIt = problem().gridView().iend(element);
392 for (auto isIt = problem().gridView().ibegin(element); isIt != isEndIt; ++isIt)
393 {
394 const auto& intersection = *isIt;
395
396 if (intersection.neighbor())
397 {
398 //index outside
399 int eIdxGlobalJ = problem().variables().index(intersection.outside());
400
401 // if mpfa is used, more entries might be needed if all interactionRegions are regarded
402 if (intersection.outside().level() > element.level()) //look from larger cell
403 {
404 // Prepare MPFA
405 /* get geometric Info, transmissibility matrix */
406 GlobalPosition globalPos3(0.);
407 int eIdxGlobal3=-1;
408 GlobalPosition globalPos4(0.);
409 int eIdxGlobal4=-1;
410 TransmissivityMatrix T(0.);
411
412 int interactionRegions
413 = problem().variables().getMpfaData3D(intersection, T,
414 globalPos3, eIdxGlobal3, globalPos4, eIdxGlobal4 );
415 if (interactionRegions == 0)
416 interactionRegions = problem().pressureModel().computeTransmissibilities(isIt,T,
417 globalPos3, eIdxGlobal3, globalPos4, eIdxGlobal4 );
418 if(!interactionRegions)
419 Dune::dgrave << "something went wrong getting mpfa data on cell " << eIdxGlobalI << std::endl;
420 if (interactionRegions == 1) // no second subface
421 continue;
422
423 //loop over all found interaction regions
424 for (int cocumber=1; cocumber<interactionRegions; cocumber++ )
425 {
426 problem().variables().getMpfaData3D(intersection, T,
427 globalPos3, eIdxGlobal3, globalPos4, eIdxGlobal4, cocumber);
428 // indices
429 int additionalIdx2 = eIdxGlobal3;
430 int additionalIdx3 = eIdxGlobal4;
431
432 bool addIndex = true;
433
434 // check if additionals are "normal" neighbors of I
435 bool additional2isNeighbor(false), additional3isNeighbor(false);
436 // run through all intersections with neighbors if eIt
437 for (const auto& checkIntersection
438 : intersections(problem().gridView(), element))
439 {
440 if (checkIntersection.neighbor())
441 {
442 if(additionalIdx2==problem().variables().index(checkIntersection.outside()))
443 additional2isNeighbor = true;
444 if(additionalIdx3 == problem().variables().index(checkIntersection.outside()))
445 additional3isNeighbor = true;
446 }
447
448 }
449 // if not "normal" neighbor, increase row size
450 if(!additional2isNeighbor)
451 {
452 // check if relation not already added
453 IntPair intPair(eIdxGlobalI,additionalIdx2);
454 if(eIdxGlobalI > additionalIdx2)
455 {
456 using std::swap;
457 swap(intPair.first, intPair.second);
458 }
459 range = addionalRelations.equal_range(intPair.first);
460 for (rangeIt=range.first; range.first!=range.second
461 && rangeIt!=range.second; ++rangeIt)
462 if((*rangeIt).second == intPair.second)
463 addIndex = false;
464 if(addIndex)
465 {
466 this->A_.incrementrowsize(eIdxGlobalI);
467 // add space for additional itsself
468 this->A_.incrementrowsize(additionalIdx2);
469 // mark relation as added
470 addionalRelations.insert(intPair);
471 }
472 }
473
474 // if not "normal" neighbor, increase row size
475 if(!additional3isNeighbor)
476 {
477 addIndex = true;
478 // check if relation not already added
479 IntPair intPair(eIdxGlobalI,additionalIdx3);
480 if(eIdxGlobalI > additionalIdx3)
481 {
482 using std::swap;
483 swap(intPair.first, intPair.second);
484 }
485 range = addionalRelations.equal_range(intPair.first);
486 for (rangeIt=range.first; range.first!=range.second
487 && rangeIt!=range.second; ++rangeIt)
488 if((*rangeIt).second == intPair.second)
489 addIndex = false;
490 if(addIndex)
491 {
492 this->A_.incrementrowsize(eIdxGlobalI);
493 // add space for additional itsself
494 this->A_.incrementrowsize(additionalIdx3);
495 // mark relation as added
496 addionalRelations.insert(intPair);
497 }
498 }
499
500 //reset bools for J
501 additional2isNeighbor = additional3isNeighbor = false;
502 // run through all intersections with neighbors of J
503 for (const auto& checkIntersection
504 : intersections(problem().gridView(), intersection.outside()))
505 {
506 if (checkIntersection.neighbor())
507 {
508 if(additionalIdx2 == problem().variables().index(checkIntersection.outside()))
509 additional2isNeighbor = true;
510 if(additionalIdx3 == problem().variables().index(checkIntersection.outside()))
511 additional3isNeighbor = true;
512 }
513 }
514
515 // if not "normal" neighbor, increase row size
516 if(!additional2isNeighbor)
517 {
518 addIndex = true;
519 // check if relation not already added
520 IntPair intPair(eIdxGlobalJ,additionalIdx2);
521 if(eIdxGlobalJ > additionalIdx2)
522 {
523 using std::swap;
524 swap(intPair.first, intPair.second);
525 }
526 range = addionalRelations.equal_range(intPair.first);
527 for (rangeIt=range.first; range.first!=range.second
528 && rangeIt!=range.second; ++rangeIt)
529 if((*rangeIt).second == intPair.second)
530 addIndex = false;
531 if(addIndex)
532 {
533 this->A_.incrementrowsize(eIdxGlobalJ);
534 // add space for additional itsself
535 this->A_.incrementrowsize(additionalIdx2);
536 // mark relation as added
537 addionalRelations.insert(intPair);
538 }
539 }
540
541 // if not "normal" neighbor, increase row size
542 if(!additional3isNeighbor)
543 {
544 addIndex = true;
545 // check if relation not already added
546 IntPair intPair(eIdxGlobalJ,additionalIdx3);
547 if(eIdxGlobalJ > additionalIdx3)
548 {
549 using std::swap;
550 swap(intPair.first, intPair.second);
551 }
552 range = addionalRelations.equal_range(intPair.first);
553 for (rangeIt=range.first; range.first!=range.second
554 && rangeIt!=range.second; ++rangeIt)
555 if((*rangeIt).second == intPair.second)
556 addIndex = false;
557 if(addIndex)
558 {
559 this->A_.incrementrowsize(eIdxGlobalJ);
560 // add space for additional itsself
561 this->A_.incrementrowsize(additionalIdx3);
562 // mark relation as added
563 addionalRelations.insert(intPair);
564 }
565 }
566 }
567 }
568 }
569 }
570 } //end second loop
571 }
572}
573
575/* Method adds TPFA and MPFA matrix entries
576 */
577template<class TypeTag>
579{
580 // determine position of matrix entries
581 for (const auto& element : elements(problem().gridView()))
582 {
583 // cell index
584 int eIdxGlobalI = problem().variables().index(element);
585
586 // add diagonal index
587 this->A_.addindex(eIdxGlobalI, eIdxGlobalI);
588
589 // run through all intersections with neighbors
590 const auto isEndIt = problem().gridView().iend(element);
591 for (auto isIt = problem().gridView().ibegin(element); isIt != isEndIt; ++isIt)
592 {
593 const auto& intersection = *isIt;
594
595 if (intersection.neighbor())
596 {
597 // access neighbor
598 int eIdxGlobalJ = problem().variables().index(intersection.outside());
599
600 // add off diagonal index
601 this->A_.addindex(eIdxGlobalI, eIdxGlobalJ);
602
603 // special treatment for hanging nodes in the mpfa case
604 if (enableMPFA && (element.level() < intersection.outside().level()))
605 {
606 // prepare stuff to enter transmissibility calculation
607 GlobalPosition globalPos3(0.);
608 int eIdxGlobal3=-1;
609 GlobalPosition globalPos4(0.);
610 int eIdxGlobal4=-1;
611 TransmissivityMatrix T(0.);
612 TransmissivityMatrix additionalT(0.);
613
614 int interactionRegions
615 = problem().variables().getMpfaData3D(intersection, T, globalPos3, eIdxGlobal3, globalPos4, eIdxGlobal4 );
616 if (interactionRegions == 0)
617 interactionRegions = problem().pressureModel().computeTransmissibilities(isIt,T,
618 globalPos3, eIdxGlobal3, globalPos4, eIdxGlobal4 );
619
620 for (int cocumber=1; cocumber<interactionRegions; cocumber++ )
621 {
622 problem().variables().getMpfaData3D(intersection, T,
623 globalPos3, eIdxGlobal3, globalPos4, eIdxGlobal4, cocumber);
624
625 // add off diagonal index in both directions!!
626 this->A_.addindex(eIdxGlobalI, eIdxGlobal3);
627 this->A_.addindex(eIdxGlobal3, eIdxGlobalI);
628 this->A_.addindex(eIdxGlobalI, eIdxGlobal4);
629 this->A_.addindex(eIdxGlobal4, eIdxGlobalI);
630 this->A_.addindex(eIdxGlobalJ, eIdxGlobal3);
631 this->A_.addindex(eIdxGlobal3, eIdxGlobalJ);
632 this->A_.addindex(eIdxGlobalJ, eIdxGlobal4);
633 this->A_.addindex(eIdxGlobal4, eIdxGlobalJ);
634 }
635 }
636 }
637 }
638 }
639}
640
642template<class TypeTag>
644{
645 if(first)
646 {
647 BaseType::assemble(true);
648 return;
649 }
650
651 // initialization: set matrix A_ to zero
652 this->A_ = 0;
653 this->f_ = 0;
654
655 for (const auto& element : elements(problem().gridView()))
656 {
657 // get the global index of the cell
658 int eIdxGlobalI = problem().variables().index(element);
659
660 // assemble interior element contributions
661 if (element.partitionType() == Dune::InteriorEntity)
662 {
663 // get the cell data
664 CellData& cellDataI = problem().variables().cellData(eIdxGlobalI);
665
666 Dune::FieldVector<Scalar, 2> entries(0.);
667
668 /***** source term ***********/
669#ifndef noMultiphysics
670 if(cellDataI.subdomain() != 2)
671 problem().pressureModel().get1pSource(entries,element, cellDataI);
672 else
673#endif
674 problem().pressureModel().getSource(entries,element, cellDataI, first);
675
676 this->f_[eIdxGlobalI] += entries[rhs];
677
678 /***** flux term ***********/
679 // iterate over all faces of the cell
680 const auto isEndIt = problem().gridView().iend(element);
681 for (auto isIt = problem().gridView().ibegin(element); isIt != isEndIt; ++isIt)
682 {
683 const auto& intersection = *isIt;
684
685 /************* handle interior face *****************/
686 if (intersection.neighbor())
687 {
688 auto neighbor = intersection.outside();
689 int eIdxGlobalJ = problem().variables().index(neighbor);
690 //check for hanging nodes
691 //take a hanging node never from the element with smaller level!
692 bool haveSameLevel = (element.level() == neighbor.level());
693 // calculate only from one side, but add matrix entries for both sides
694 // the last condition is needed to properly assemble in the presence
695 // of ghost elements
696 if (getPropValue<TypeTag, Properties::VisitFacesOnlyOnce>()
697 && (eIdxGlobalI > eIdxGlobalJ) && haveSameLevel
698 && neighbor.partitionType() == Dune::InteriorEntity)
699 continue;
700
701 entries = 0;
702 //check for hanging nodes
703 if(!haveSameLevel && enableMPFA)
704 {
705 if (cellDataI.subdomain() != 2
706 || problem().variables().cellData(eIdxGlobalJ).subdomain() != 2) // cell in the 1p domain
707 {
708 asImp_().get1pMpfaFlux(isIt, cellDataI);
709 }
710 else
711 {
712 asImp_().getMpfaFlux(isIt, cellDataI);
713 }
714 }
715 else
716 {
717 CellData cellDataJ = problem().variables().cellData(eIdxGlobalJ);
718 if (cellDataI.subdomain() != 2
719 || problem().variables().cellData(eIdxGlobalJ).subdomain() != 2) // cell in the 1p domain
720 {
721 asImp_().get1pFlux(entries, intersection, cellDataI);
722 }
723 else
724 {
725 asImp_().getFlux(entries, intersection, cellDataI, first);
726 }
727
728 //set right hand side
729 this->f_[eIdxGlobalI] -= entries[rhs];
730
731 // set diagonal entry
732 this->A_[eIdxGlobalI][eIdxGlobalI] += entries[matrix];
733
734 // set off-diagonal entry
735 this->A_[eIdxGlobalI][eIdxGlobalJ] -= entries[matrix];
736
737 // The second condition is needed to not spoil the ghost element entries
738 if (getPropValue<TypeTag, Properties::VisitFacesOnlyOnce>()
739 && neighbor.partitionType() == Dune::InteriorEntity)
740 {
741 this->f_[eIdxGlobalJ] += entries[rhs];
742 this->A_[eIdxGlobalJ][eIdxGlobalJ] += entries[matrix];
743 this->A_[eIdxGlobalJ][eIdxGlobalI] -= entries[matrix];
744 }
745 }
746 } // end neighbor
747
748 /************* boundary face ************************/
749 else
750 {
751 entries = 0;
752 if (cellDataI.subdomain() != 2) //the current cell in the 1p domain
753 asImp_().get1pFluxOnBoundary(entries, intersection, cellDataI);
754 else
755 asImp_().getFluxOnBoundary(entries, intersection, cellDataI, first);
756
757 //set right hand side
758 this->f_[eIdxGlobalI] += entries[rhs];
759 // set diagonal entry
760 this->A_[eIdxGlobalI][eIdxGlobalI] += entries[matrix];
761 }
762 } //end interfaces loop
763
764 /***** storage term ***********/
765 if (cellDataI.subdomain() != 2) //the current cell in the 1p domain
766 asImp_().get1pStorage(entries, element, cellDataI);
767 else
768 asImp_().getStorage(entries, element, cellDataI, first);
769
770 this->f_[eIdxGlobalI] += entries[rhs];
771 // set diagonal entry
772 this->A_[eIdxGlobalI][eIdxGlobalI] += entries[matrix];
773 }
774 // assemble overlap and ghost element contributions
775 else
776 {
777 this->A_[eIdxGlobalI] = 0.0;
778 this->A_[eIdxGlobalI][eIdxGlobalI] = 1.0;
779 this->f_[eIdxGlobalI] = this->pressure()[eIdxGlobalI];
780 }
781 } // end grid traversal
782}
783
785
803template<class TypeTag>
804void FV3dPressure2P2CAdaptive<TypeTag>::getMpfaFlux(const IntersectionIterator& isIt,
805 const CellData& cellDataI)
806{
807 const auto& intersection = *isIt;
808
809 // acess Cell I
810 auto elementI = intersection.inside();
811 int eIdxGlobalI = problem().variables().index(elementI);
812
813 // get global coordinate of cell center
814 const GlobalPosition& globalPos = elementI.geometry().center();
815
816 // cell volume & perimeter, assume linear map here
817 Scalar volume = elementI.geometry().volume();
818 Scalar perimeter = cellDataI.perimeter();
819
820 // get absolute permeability
821 DimMatrix permeabilityI(problem().spatialParams().intrinsicPermeability(elementI));
822
823 // access neighbor
824 auto neighbor = intersection.outside();
825 int eIdxGlobalJ = problem().variables().index(neighbor);
826 CellData& cellDataJ = problem().variables().cellData(eIdxGlobalJ);
827
828 // gemotry info of neighbor
829 const GlobalPosition& globalPosNeighbor = neighbor.geometry().center();
830
831 // distance vector between barycenters
832 GlobalPosition distVec = globalPosNeighbor - globalPos;
833
834 // compute distance between cell centers
835 Scalar dist = distVec.two_norm();
836
837 GlobalPosition unitDistVec(distVec);
838 unitDistVec /= dist;
839
840 DimMatrix permeabilityJ
841 = problem().spatialParams().intrinsicPermeability(neighbor);
842
843 // compute vectorized permeabilities
844 DimMatrix meanPermeability(0);
845 harmonicMeanMatrix(meanPermeability, permeabilityI, permeabilityJ);
846
847 Dune::FieldVector<Scalar, dim> permeability(0);
848 meanPermeability.mv(unitDistVec, permeability);
849
850 // get average density for gravity flux
851 PhaseVector rhoMean(0.);
852 for (int phaseIdx=0; phaseIdx<NumPhases; phaseIdx++)
853 rhoMean[phaseIdx] =0.5 * (cellDataI.density(phaseIdx)+cellDataJ.density(phaseIdx));
854
855 // reset potential gradients
856 Dune::FieldVector<Scalar,2> potential(0.);
857
858 // determine volume derivatives in neighbor
859 if (!cellDataJ.hasVolumeDerivatives())
860 asImp_().volumeDerivatives(globalPosNeighbor, neighbor);
861
862 ComponentVector dv_dC(0.), graddv_dC(0.);
863 for (int compIdx = 0; compIdx < NumComponents; ++compIdx)
864 {
865 dv_dC[compIdx]= (cellDataJ.dv(compIdx) // dV/dm1= dv/dC^1
866 + cellDataI.dv(compIdx)) * 0.5;
867 graddv_dC[compIdx] = (cellDataJ.dv(compIdx)
868 - cellDataI.dv(compIdx)) / dist;
869 }
870// potentialW = problem().variables().potentialWetting(eIdxGlobalI, isIndex);
871// potentialNW = problem().variables().potentialNonwetting(eIdxGlobalI, isIndex);
872//
873// densityW = (potentialW > 0.) ? densityWI : densityWJ;
874// densityNW = (potentialNW > 0.) ? densityNWI : densityNWJ;
875//
876// densityW = (potentialW == 0.) ? rhoMeanW : densityW;
877// densityNW = (potentialNW == 0.) ? rhoMeanNW : densityNW;
878 //jochen: central weighting for gravity term
879
880 // Prepare MPFA
881 /* get geometrical Info, transmissibility matrix */
882 GlobalPosition globalPos3(0.);
883 int eIdxGlobal3=-1;
884 GlobalPosition globalPos4(0.);
885 int eIdxGlobal4=-1;
886 TransmissivityMatrix T(0.);
887
888 // prepare second interaction region
889 GlobalPosition globalPosAdditional3(0.);
890 int eIdxGlobalAdditional3=-1;
891 GlobalPosition globalPosAdditional4(0.);
892 int eIdxGlobalAdditional4=-1;
893
894 TransmissivityMatrix additionalT(0.);
895
896 int interactionRegions
897 = problem().variables().getMpfaData3D(intersection, T,
898 globalPos3, eIdxGlobal3, globalPos4, eIdxGlobal4 );
899 if (interactionRegions == 0)
900 interactionRegions = problem().pressureModel().computeTransmissibilities(isIt,T,
901 globalPos3, eIdxGlobal3, globalPos4, eIdxGlobal4 );
902 if(!interactionRegions)
903 Dune::dgrave << "something went wrong getting mpfa data on cell " << eIdxGlobalI << std::endl;
904
905 // shortcurts mpfa case
906 CellData& cellData3 = problem().variables().cellData(eIdxGlobal3);
907 CellData& cellData4 = problem().variables().cellData(eIdxGlobal4);
908 Scalar temp1 = globalPos * this->gravity_;
909 Scalar temp2 = globalPosNeighbor * this->gravity_;
910 Scalar temp3 = globalPos3 * this->gravity_;
911 Scalar temp4 = globalPos4 * this->gravity_;
912
913 for (int phaseIdx = 0; phaseIdx < NumPhases; ++phaseIdx)
914 {
915 potential[phaseIdx] = (cellDataI.pressure(phaseIdx)-temp1*rhoMean[phaseIdx]) * T[0]
916 + (cellDataJ.pressure(phaseIdx)-temp2*rhoMean[phaseIdx]) * T[1]
917 + (cellData3.pressure(phaseIdx)-temp3*rhoMean[phaseIdx]) * T[2]
918 + (cellData4.pressure(phaseIdx)-temp4*rhoMean[phaseIdx]) * T[3];
919 }
920
921 // regard more interaction regions, if there are more
922 if(interactionRegions != 1)
923 {
924 for(int banana = 1; banana < interactionRegions; banana ++)
925 {
926 // get data for second interaction region
927 problem().variables().getMpfaData3D(intersection, additionalT,
928 globalPosAdditional3, eIdxGlobalAdditional3,
929 globalPosAdditional4, eIdxGlobalAdditional4 ,
930 banana); // offset for second interaction region
931
932 Scalar gravityContributionAdditonal
933 = temp1 * additionalT[0] + temp2 * additionalT[1]
934 + globalPosAdditional3*this->gravity_ * additionalT[2]
935 + globalPosAdditional4*this->gravity_ * additionalT[3];
936 CellData& cellDataA3 = problem().variables().cellData(eIdxGlobalAdditional3);
937 CellData& cellDataA4 = problem().variables().cellData(eIdxGlobalAdditional4);
938
939 for (int phaseIdx = 0; phaseIdx < NumPhases; ++phaseIdx)
940 {
941 potential[phaseIdx] += cellDataI.pressure(phaseIdx) * additionalT[0]
942 + cellDataJ.pressure(phaseIdx) * additionalT[1]
943 + cellDataA3.pressure(phaseIdx) * additionalT[2]
944 + cellDataA4.pressure(phaseIdx) * additionalT[3];
945 potential[phaseIdx] -= gravityContributionAdditonal * rhoMean[phaseIdx];
946 }
947 }
948 }
949
950 // initialize convenience shortcuts
951 PhaseVector lambda(0.), dV(0.), gV(0.);
952
953 //do the upwinding of the mobility depending on the phase potentials
954 std::vector<const CellData*> upwindCellData(NumPhases);
955
956 for (int phaseIdx = 0; phaseIdx < NumPhases; ++phaseIdx)
957 {
958 int eqIdx = phaseIdx + 1;
959 if (potential[phaseIdx] > 0.)
960 upwindCellData[phaseIdx] = &cellDataI;
961 else if (potential[phaseIdx] < 0.)
962 upwindCellData[phaseIdx] = &cellDataJ;
963 else
964 {
965 if(cellDataI.isUpwindCell(intersection.indexInInside(), eqIdx))
966 upwindCellData[phaseIdx] = &cellDataI;
967 else if(cellDataJ.isUpwindCell(intersection.indexInOutside(), eqIdx))
968 upwindCellData[phaseIdx] = &cellDataJ;
969 //else
970 // upwinding is not done!
971 }
972
973 //perform upwinding if desired
974 if(!upwindCellData[phaseIdx])
975 {
976 Scalar averagedMassFraction[NumComponents];
977 for (int compIdx = 0; compIdx < NumComponents; ++compIdx)
978 averagedMassFraction[compIdx]
979 = harmonicMean(cellDataI.massFraction(phaseIdx, compIdx), cellDataJ.massFraction(phaseIdx, compIdx));
980 Scalar averageDensity = harmonicMean(cellDataI.density(phaseIdx), cellDataJ.density(phaseIdx));
981
982 for (int compIdx = 0; compIdx < NumComponents; ++compIdx)
983 {
984 dV[phaseIdx] += dv_dC[compIdx] * averagedMassFraction[compIdx];
985 gV[phaseIdx] += graddv_dC[compIdx] * averagedMassFraction[compIdx];
986 }
987 dV[phaseIdx] *= averageDensity;
988 gV[phaseIdx] *= averageDensity;
989 lambda[phaseIdx] = harmonicMean(cellDataI.mobility(phaseIdx), cellDataJ.mobility(phaseIdx));
990 }
991 else //perform upwinding
992 {
993 for (int compIdx = 0; compIdx < NumComponents; ++compIdx)
994 {
995 dV[phaseIdx] += dv_dC[compIdx] * upwindCellData[phaseIdx]->massFraction(phaseIdx, compIdx);
996 gV[phaseIdx] += graddv_dC[compIdx] * upwindCellData[phaseIdx]->massFraction(phaseIdx, compIdx);
997 }
998 lambda[phaseIdx] = upwindCellData[phaseIdx]->mobility(phaseIdx);
999 dV[phaseIdx] *= upwindCellData[phaseIdx]->density(phaseIdx);
1000 gV[phaseIdx] *= upwindCellData[phaseIdx]->density(phaseIdx);
1001 }
1002 }
1003
1004 /* compute matrix entry: advective fluxes */
1005 /* extend T with other matrix entries and assemble to A_ */
1006 this->A_[eIdxGlobalI][eIdxGlobalI] += (lambda[wPhaseIdx] * dV[wPhaseIdx] + lambda[nPhaseIdx] * dV[nPhaseIdx]) * T[0];
1007 this->A_[eIdxGlobalI][eIdxGlobalJ] += (lambda[wPhaseIdx] * dV[wPhaseIdx] + lambda[nPhaseIdx] * dV[nPhaseIdx]) * T[1];
1008 this->A_[eIdxGlobalI][eIdxGlobal3] += (lambda[wPhaseIdx] * dV[wPhaseIdx] + lambda[nPhaseIdx] * dV[nPhaseIdx]) * T[2];
1009 this->A_[eIdxGlobalI][eIdxGlobal4] += (lambda[wPhaseIdx] * dV[wPhaseIdx] + lambda[nPhaseIdx] * dV[nPhaseIdx]) * T[3];
1010
1011
1012 // add gravity to RHS vector
1013 Scalar gravityContribution = temp1 * T[0] + temp2 * T[1] + temp3 * T[2] + temp4 * T[3];
1014 this->f_[eIdxGlobalI] += (rhoMean[wPhaseIdx] * lambda[wPhaseIdx] * dV[wPhaseIdx]
1015 + rhoMean[nPhaseIdx] * lambda[nPhaseIdx] * dV[nPhaseIdx]) * gravityContribution;
1016
1017 // weithing accounts for the fraction of the subcontrol volume
1018 Scalar weightingFactor = volume / perimeter; // transforms flux through area A -> V * A/perimeter
1019 if(enableVolumeIntegral_) // switch off volume integral for mpfa case
1020 {
1021 // correct for area integral
1022 this->A_[eIdxGlobalI][eIdxGlobalI] -=
1023 weightingFactor * (lambda[wPhaseIdx] * gV[wPhaseIdx] + lambda[nPhaseIdx] * gV[nPhaseIdx]) * T[0];
1024 this->A_[eIdxGlobalI][eIdxGlobalJ] -=
1025 weightingFactor * (lambda[wPhaseIdx] * gV[wPhaseIdx] + lambda[nPhaseIdx] * gV[nPhaseIdx]) * T[1];
1026 this->A_[eIdxGlobalI][eIdxGlobal3] -=
1027 weightingFactor * (lambda[wPhaseIdx] * gV[wPhaseIdx] + lambda[nPhaseIdx] * gV[nPhaseIdx]) * T[2];
1028 this->A_[eIdxGlobalI][eIdxGlobal4] -=
1029 weightingFactor * (lambda[wPhaseIdx] * gV[wPhaseIdx] + lambda[nPhaseIdx] * gV[nPhaseIdx]) * T[3];
1030
1031 // add gravity to RHS vector
1032 this->f_[eIdxGlobalI] -= weightingFactor * gravityContribution *
1033 (rhoMean[wPhaseIdx] * lambda[wPhaseIdx] * gV[wPhaseIdx] + rhoMean[nPhaseIdx] * lambda[nPhaseIdx] * gV[nPhaseIdx]);
1034 }
1035
1036 // capillary pressure flux
1037 Scalar pcGradient = cellDataI.capillaryPressure() * T[0]
1038 + cellDataJ.capillaryPressure() * T[1]
1039 + cellData3.capillaryPressure() * T[2]
1040 + cellData4.capillaryPressure() * T[3];
1041
1042 if (this->pressureType == pw)
1043 pcGradient *= + lambda[nPhaseIdx] * dV[nPhaseIdx]
1044 - enableVolumeIntegral_ * weightingFactor * lambda[nPhaseIdx] * gV[nPhaseIdx];
1045 else if (this->pressureType == pn)
1046 pcGradient *= - lambda[wPhaseIdx] * dV[wPhaseIdx]
1047 + enableVolumeIntegral_ * weightingFactor * lambda[wPhaseIdx] * gV[wPhaseIdx];
1048
1049 this->f_[eIdxGlobalI] += pcGradient;
1050
1051 // regard more interaction regions, if there are more
1052 if(interactionRegions != 1)
1053 {
1054 for(int banana = 1; banana < interactionRegions; banana ++)
1055 {
1056 // get data for second interaction region
1057 problem().variables().getMpfaData3D(intersection, additionalT,
1058 globalPosAdditional3, eIdxGlobalAdditional3,
1059 globalPosAdditional4, eIdxGlobalAdditional4 ,
1060 banana); // offset for second interaction region
1061
1062 Scalar gravityContributionAdditonal
1063 = temp1 * additionalT[0] + temp2 * additionalT[1]
1064 + globalPosAdditional3*this->gravity_ * additionalT[2]
1065 + globalPosAdditional4*this->gravity_ * additionalT[3];
1066 CellData& cellDataA3 = problem().variables().cellData(eIdxGlobalAdditional3);
1067 CellData& cellDataA4 = problem().variables().cellData(eIdxGlobalAdditional4);
1068
1069 /* compute matrix entry: advective fluxes */
1070 /* extend T with other matrix entries and assemble to A_ */
1071 this->A_[eIdxGlobalI][eIdxGlobalI] +=
1072 (lambda[wPhaseIdx] * dV[wPhaseIdx] + lambda[nPhaseIdx] * dV[nPhaseIdx]) * additionalT[0];
1073 this->A_[eIdxGlobalI][eIdxGlobalJ] +=
1074 (lambda[wPhaseIdx] * dV[wPhaseIdx] + lambda[nPhaseIdx] * dV[nPhaseIdx]) * additionalT[1];
1075 this->A_[eIdxGlobalI][eIdxGlobalAdditional3] +=
1076 (lambda[wPhaseIdx] * dV[wPhaseIdx] + lambda[nPhaseIdx] * dV[nPhaseIdx]) * additionalT[2];
1077 this->A_[eIdxGlobalI][eIdxGlobalAdditional4] +=
1078 (lambda[wPhaseIdx] * dV[wPhaseIdx] + lambda[nPhaseIdx] * dV[nPhaseIdx]) * additionalT[3];
1079
1080
1081 // add gravity to RHS vector
1082 this->f_[eIdxGlobalI] += (rhoMean[wPhaseIdx] * lambda[wPhaseIdx] * dV[wPhaseIdx]
1083 + rhoMean[nPhaseIdx] * lambda[nPhaseIdx] * dV[nPhaseIdx]) * gravityContributionAdditonal;
1084
1085 // weithing accounts for the fraction of the subcontrol volume
1086 if(enableVolumeIntegral_) // switch off volume integral for mpfa case
1087 {
1088 // correct for area integral
1089 this->A_[eIdxGlobalI][eIdxGlobalI] -=
1090 weightingFactor * (lambda[wPhaseIdx] * gV[wPhaseIdx] + lambda[nPhaseIdx] * gV[nPhaseIdx]) * additionalT[0];
1091 this->A_[eIdxGlobalI][eIdxGlobalJ] -=
1092 weightingFactor * (lambda[wPhaseIdx] * gV[wPhaseIdx] + lambda[nPhaseIdx] * gV[nPhaseIdx]) * additionalT[1];
1093 this->A_[eIdxGlobalI][eIdxGlobalAdditional3] -=
1094 weightingFactor * (lambda[wPhaseIdx] * gV[wPhaseIdx] + lambda[nPhaseIdx] * gV[nPhaseIdx]) * additionalT[2];
1095 this->A_[eIdxGlobalI][eIdxGlobalAdditional4] -=
1096 weightingFactor * (lambda[wPhaseIdx] * gV[wPhaseIdx] + lambda[nPhaseIdx] * gV[nPhaseIdx]) * additionalT[3];
1097
1098 // add gravity to RHS vector
1099 this->f_[eIdxGlobalI] -= weightingFactor * gravityContribution *
1100 (rhoMean[wPhaseIdx] * lambda[wPhaseIdx] * gV[wPhaseIdx] + rhoMean[nPhaseIdx] * lambda[nPhaseIdx] * gV[nPhaseIdx]);
1101 }
1102
1103 // capillary pressure flux
1104 Scalar addPcGradient = cellDataI.capillaryPressure() * additionalT[0]
1105 + cellDataJ.capillaryPressure() * additionalT[1]
1106 + cellDataA3.capillaryPressure() * additionalT[2]
1107 + cellDataA4.capillaryPressure() * additionalT[3];
1108
1109 if (this->pressureType == pw)
1110 addPcGradient *= + lambda[nPhaseIdx] * dV[nPhaseIdx]
1111 - enableVolumeIntegral_ * weightingFactor * lambda[nPhaseIdx] * gV[nPhaseIdx];
1112 else if (this->pressureType == pn)
1113 addPcGradient *= - lambda[wPhaseIdx] * dV[wPhaseIdx]
1114 + enableVolumeIntegral_ * weightingFactor * lambda[wPhaseIdx] * gV[wPhaseIdx];
1115
1116 this->f_[eIdxGlobalI] += addPcGradient;
1117 }
1118 }
1119}
1120
1121
1140template<class TypeTag>
1141void FV3dPressure2P2CAdaptive<TypeTag>::get1pMpfaFlux(const IntersectionIterator& isIt,
1142 const CellData& cellDataI)
1143{
1144 const auto& intersection = *isIt;
1145
1146 // acess Cell I
1147 auto elementI = intersection.inside();
1148 int eIdxGlobalI = problem().variables().index(elementI);
1149
1150 // get global coordinate of cell center
1151 const GlobalPosition& globalPos = elementI.geometry().center();
1152
1153 // access neighbor
1154 auto neighbor = intersection.outside();
1155 int eIdxGlobalJ = problem().variables().index(neighbor);
1156 CellData& cellDataJ = problem().variables().cellData(eIdxGlobalJ);
1157
1158 // gemotry info of neighbor
1159 const GlobalPosition& globalPosNeighbor = neighbor.geometry().center();
1160
1161 // due to "safety cell" around subdomain, both cells I and J
1162 // have single-phase conditions, although one is in 2p domain.
1163 using std::min;
1164 int phaseIdx = min(cellDataI.subdomain(), cellDataJ.subdomain());
1165
1166 // get average density for gravity flux
1167 Scalar rhoMean = 0.5 * (cellDataI.density(phaseIdx) + cellDataJ.density(phaseIdx));
1168
1169 // 1p => no pC => only 1 pressure, potential
1170 Scalar potential = 0.;
1171
1172 // Prepare MPFA
1174 GlobalPosition globalPos3(0.);
1175 int eIdxGlobal3=-1;
1176 GlobalPosition globalPos4(0.);
1177 int eIdxGlobal4=-1;
1178 TransmissivityMatrix T(0.);
1179
1180 // prepare second interaction region
1181 GlobalPosition globalPosAdditional3(0.);
1182 int eIdxGlobalAdditional3=-1;
1183 GlobalPosition globalPosAdditional4(0.);
1184 int eIdxGlobalAdditional4=-1;
1185
1186 TransmissivityMatrix additionalT(0.);
1187
1188 int interactionRegions
1189 = problem().variables().getMpfaData3D(intersection, T,
1190 globalPos3, eIdxGlobal3, globalPos4, eIdxGlobal4 );
1191 if (interactionRegions == 0)
1192 interactionRegions = problem().pressureModel().computeTransmissibilities(isIt,T,
1193 globalPos3, eIdxGlobal3, globalPos4, eIdxGlobal4 );
1194 if(!interactionRegions)
1195 Dune::dgrave << "something went wrong getting mpfa data on cell " << eIdxGlobalI << std::endl;
1196
1197 // shortcurts mpfa case
1198 CellData& cellData3 = problem().variables().cellData(eIdxGlobal3);
1199 CellData& cellData4 = problem().variables().cellData(eIdxGlobal4);
1200 Scalar temp1 = globalPos * this->gravity_;
1201 Scalar temp2 = globalPosNeighbor * this->gravity_;
1202 Scalar temp3 = globalPos3 * this->gravity_;
1203 Scalar temp4 = globalPos4 * this->gravity_;
1204
1205 potential = (cellDataI.pressure(phaseIdx)-temp1*rhoMean) * T[0]
1206 + (cellDataJ.pressure(phaseIdx)-temp2*rhoMean) * T[1]
1207 + (cellData3.pressure(phaseIdx)-temp3*rhoMean) * T[2]
1208 + (cellData4.pressure(phaseIdx)-temp4*rhoMean) * T[3];
1209
1210 // regard more interaction regions, if there are more
1211 if(interactionRegions != 1)
1212 {
1213 for(int banana = 1; banana < interactionRegions; banana ++)
1214 {
1215 // get data for second interaction region
1216 problem().variables().getMpfaData3D(intersection, additionalT,
1217 globalPosAdditional3, eIdxGlobalAdditional3,
1218 globalPosAdditional4, eIdxGlobalAdditional4 ,
1219 banana); // offset for second interaction region
1220
1221 Scalar gravityContributionAdditonal
1222 = temp1 * additionalT[0] + temp2 * additionalT[1]
1223 + globalPosAdditional3*this->gravity_ * additionalT[2]
1224 + globalPosAdditional4*this->gravity_ * additionalT[3];
1225 CellData& cellDataA3 = problem().variables().cellData(eIdxGlobalAdditional3);
1226 CellData& cellDataA4 = problem().variables().cellData(eIdxGlobalAdditional4);
1227
1228 potential += cellDataI.pressure(phaseIdx) * additionalT[0]
1229 + cellDataJ.pressure(phaseIdx) * additionalT[1]
1230 + cellDataA3.pressure(phaseIdx) * additionalT[2]
1231 + cellDataA4.pressure(phaseIdx) * additionalT[3];
1232 potential -= gravityContributionAdditonal * rhoMean;
1233 }
1234 }
1235
1236 // initialize convenience shortcuts
1237 Scalar lambda(0.);
1238
1239 //do the upwinding of the mobility depending on the phase potentials
1240 if (potential >= 0.)
1241 lambda = cellDataI.mobility(phaseIdx);
1242 else
1243 lambda = cellDataJ.mobility(phaseIdx);
1244
1246 /* extend T with other matrix entries and assemble to A_ */
1247 this->A_[eIdxGlobalI][eIdxGlobalI] += lambda * T[0];
1248 this->A_[eIdxGlobalI][eIdxGlobalJ] += lambda * T[1];
1249 this->A_[eIdxGlobalI][eIdxGlobal3] += lambda * T[2];
1250 this->A_[eIdxGlobalI][eIdxGlobal4] += lambda * T[3];
1251
1252 // add gravity to RHS vector
1253 Scalar gravityContribution = temp1 * T[0] + temp2 * T[1] + temp3 * T[2] + temp4 * T[3];
1254 this->f_[eIdxGlobalI] += lambda * rhoMean * gravityContribution;
1255
1256 // regard more interaction regions, if there are more
1257 if(interactionRegions != 1)
1258 {
1259 for(int banana = 1; banana < interactionRegions; banana ++)
1260 {
1261 // get data for second interaction region
1262 problem().variables().getMpfaData3D(intersection, additionalT,
1263 globalPosAdditional3, eIdxGlobalAdditional3,
1264 globalPosAdditional4, eIdxGlobalAdditional4 ,
1265 banana); // offset for second interaction region
1266
1267 Scalar gravityContributionAdditonal
1268 = temp1 * additionalT[0] + temp2 * additionalT[1]
1269 + globalPosAdditional3*this->gravity_ * additionalT[2]
1270 + globalPosAdditional4*this->gravity_ * additionalT[3];
1271
1273 /* extend T with other matrix entries and assemble to A_ */
1274 this->A_[eIdxGlobalI][eIdxGlobalI] += lambda * additionalT[0];
1275 this->A_[eIdxGlobalI][eIdxGlobalJ] += lambda * additionalT[1];
1276 this->A_[eIdxGlobalI][eIdxGlobalAdditional3] += lambda * additionalT[2];
1277 this->A_[eIdxGlobalI][eIdxGlobalAdditional4] += lambda * additionalT[3];
1278
1279 // add gravity to RHS vector
1280 this->f_[eIdxGlobalI] += lambda * rhoMean* gravityContributionAdditonal;
1281 }
1282 }
1283}
1284
1287
1293template<class TypeTag>
1295{
1296//#define noMultiphysics
1297#ifdef noMultiphysics
1299 return;
1300#endif
1301
1302 if(!fromPostTimestep) // this happens after grid update
1303 {
1304 Scalar maxError = 0.;
1305 // iterate through leaf grid an evaluate c0 at cell center
1306 for (const auto& element : elements(problem().gridView()))
1307 {
1308 int eIdxGlobal = problem().variables().index(element);
1309 CellData& cellData = problem().variables().cellData(eIdxGlobal);
1310
1311 if(cellData.fluidStateType() == 0) // i.e. it is complex
1312 problem().pressureModel().updateMaterialLawsInElement(element, fromPostTimestep);
1313 else
1314 problem().pressureModel().update1pMaterialLawsInElement(element, cellData, fromPostTimestep);
1315 using std::max;
1316 maxError = max(maxError, fabs(cellData.volumeError()));
1317 }
1318 this->maxError_ = maxError/problem().timeManager().timeStepSize();
1319 }
1320 else
1321 {
1322 // resize multiphysics vectors
1323 FVPressure2P2CMultiPhysics<TypeTag>::nextSubdomain.resize(problem().gridView().size(0));
1324
1326 }
1327}
1328
1347template <class TypeTag>
1349 TransmissivityMatrix& T,
1350 GlobalPosition& globalPos4,
1351 int& eIdxGlobal4,
1352 GlobalPosition& globalPos6,
1353 int& eIdxGlobal6)
1354{
1355 const auto& intersection = *isIt;
1356
1357 // get geometry information of cellI = cell1, cellJ = cell2
1358 auto element = intersection.inside();
1359 auto neighbor = intersection.outside();
1360 GlobalPosition globalPos1 = element.geometry().center();
1361 GlobalPosition globalPos2 = neighbor.geometry().center();
1362 DimMatrix K1(problem().spatialParams().intrinsicPermeability(element));
1363 DimMatrix K2(problem().spatialParams().intrinsicPermeability(neighbor));
1364
1365 // determine ID of intersection seen from larger cell
1366 int intersectionID = 0;
1367 if(intersection.inside().level() < intersection.outside().level())
1368 intersectionID = problem().grid().localIdSet().subId(element,
1369 intersection.indexInInside(), 1);
1370 else
1371 DUNE_THROW(Dune::NotImplemented, " ABORT, transmiss calculated from wrong side!!");
1372
1373 std::vector<int> localIrregularCells = irregularCellMap_[intersectionID];
1374
1376 // geometry and Data of face IJ in nomenclature of mpfa
1377 GlobalPosition globalPosFace12 = intersection.geometry().center(); // = 'x'1
1378 GlobalPosition outerNormaln12 = intersection.centerUnitOuterNormal();
1379
1380 /**** a) search for intersection 24 and 26 ************/
1381 auto face24=isIt; // as long as face24 = isIt, it is still not found!
1382 auto face26=isIt; // as long as face26 = isIt, it is still not found!
1383
1384 const auto isEndIt = problem().gridView().iend(neighbor);
1385 for (auto isIt2 = problem().gridView().ibegin(neighbor); isIt2 != isEndIt; ++isIt2)
1386 {
1387 const auto& intersection2 = *isIt2;
1388
1389 // continue if no neighbor or arrived at intersection
1390 if(!(intersection2.neighbor()) || intersection2.outside() == element)
1391 continue;
1392
1393 int currentNeighbor = problem().variables().index(intersection2.outside());
1394
1395 // have we found face24?
1396 if (find(localIrregularCells.begin(), localIrregularCells.end(),
1397 currentNeighbor) != localIrregularCells.end() && face24==isIt)
1398 face24 = isIt2;
1399 else if (find(localIrregularCells.begin(), localIrregularCells.end(),
1400 currentNeighbor) != localIrregularCells.end() && face26==isIt)
1401 {
1402 // we now found both intersections, but we have to investigate orientation:
1403 // Calculate the vector product of the normals in current orientation
1404 GlobalPosition vectorProduct = crossProduct(face24->centerUnitOuterNormal(), intersection2.centerUnitOuterNormal());
1405 // the vector product of the two isNormals for the desired configuration points
1406 // in the direction of outerNormaln12 => ScalarProduct > 0.
1407 if((vectorProduct * outerNormaln12) > 0.)
1408 face26 = isIt2;
1409 else
1410 {
1411 // revert orientation: switch face24 and face26
1412 face26 = face24;
1413 face24 = isIt2;
1414 }
1415 }
1416 }
1417
1418 // get information of cell4
1419 globalPos4 = face24->outside().geometry().center();
1420 eIdxGlobal4 = problem().variables().index(face24->outside());
1421 GlobalPosition outerNormaln24 = face24->centerUnitOuterNormal();
1422 // get absolute permeability of neighbor cell 3
1423 DimMatrix K4(problem().spatialParams().intrinsicPermeability(face24->outside()));
1424
1425 // get information of cell6
1426 globalPos6 = face26->outside().geometry().center();
1427 eIdxGlobal6 = problem().variables().index(face26->outside());
1428 GlobalPosition outerNormaln26 = face26->centerUnitOuterNormal();
1429 // get absolute permeability of neighbor cell 3
1430 DimMatrix K6(problem().spatialParams().intrinsicPermeability(face26->outside()));
1431
1432 /**** b) Get Points on the edges (in plane of isIt), 'x'4 and 'x'5 ***********/
1433 int localFace12 = intersection.indexInOutside(); // isIt is face12
1434 int localFace24 = face24->indexInInside();
1435 int localFace26 = face26->indexInInside();
1436
1437 const auto refElement = referenceElement(neighbor);
1438
1439 //find 'x'5 = edgeCoord1226
1440 int edge1226;
1441 // search through edges of face 12
1442 for(int nectarine=0; nectarine < refElement.size(localFace12, 1, dim-1); nectarine++)
1443 {
1444 // get local Idx of edge on face 12
1445 int localEdgeOn12 = refElement.subEntity(localFace12, 1, nectarine, dim-1);
1446 // search through edges of face 26
1447 for(int plum = 0; plum < refElement.size(localFace26, 1,dim-1); plum++)
1448 {
1449// int localEdge26 = refElement.subEntity(localFace26, 1, plum, dim-1);
1450 if(refElement.subEntity(localFace12, 1, nectarine, dim-1)
1451 == refElement.subEntity(localFace26, 1, plum, dim-1))
1452 {
1453 edge1226 = localEdgeOn12;
1454 break;
1455 }
1456 }
1457 }
1458 GlobalPosition edgeCoord1226 = // 'x'5
1459 neighbor.geometry().global(refElement.position(edge1226, dim-1));
1460
1461 //find 'x'4 = edgeCoord1224
1462 int edge1224;
1463 // search through edges of face 12
1464 for(int nectarine=0; nectarine < refElement.size(localFace12, 1, dim-1); nectarine++)
1465 {
1466 // get local Idx of edge on face 12
1467 int localEdgeOn12 = refElement.subEntity(localFace12, 1, nectarine, dim-1);
1468 // search through edges of face 24
1469 for(int plum = 0; plum < refElement.size(localFace24, 1, dim-1); plum++)
1470 {
1471 int localEdge24 = refElement.subEntity(localFace24, 1, plum, dim-1);
1472 if(localEdgeOn12 == localEdge24)
1473 {
1474 edge1224 = localEdgeOn12;
1475 break;
1476 }
1477 }
1478 }
1479 GlobalPosition edgeCoord1224 = // 'x'4
1480 neighbor.geometry().global(refElement.position(edge1224, dim-1));
1481
1482 //find 'x'6 = edgeCoord2426
1483 int edge2426;
1484 // search through edges of face 24
1485 for(int nectarine=0; nectarine < refElement.size(localFace24, 1, dim-1); nectarine++)
1486 {
1487 // get local Idx of edge on face 24
1488 int localEdgeOn24 = refElement.subEntity(localFace24, 1, nectarine, dim-1);
1489 // search through edges of face 26
1490 for(int plum = 0; plum < refElement.size(localFace26, 1, dim-1); plum++)
1491 {
1492 int localEdge26 = refElement.subEntity(localFace26, 1, plum, dim-1);
1493 if(localEdgeOn24 == localEdge26)
1494 {
1495 edge2426 = localEdgeOn24;
1496 break;
1497 }
1498 }
1499 }
1500 GlobalPosition edgeCoord2426 = // 'x'6
1501 neighbor.geometry().global(refElement.position(edge2426, dim-1));
1502
1504 // center of face in global coordinates, i.e., the midpoint of face 'isIt24'
1505 GlobalPosition globalPosFace24 = face24->geometry().center();
1506 GlobalPosition globalPosFace26 = face26->geometry().center();
1507
1508 // get face volumes
1509 //Area12 = | 'x'1->'x'5 x 'x'1->'x'4 |
1510 Scalar subFaceArea12 = crossProduct(edgeCoord1226-globalPosFace12, edgeCoord1224-globalPosFace12).two_norm();
1511
1512 //Area24 = | 'x'2->'x'4 x 'x'2->'x'6 |
1513 Scalar subFaceArea24 = crossProduct(edgeCoord1224-globalPosFace24, edgeCoord2426-globalPosFace24).two_norm();
1514
1515 //Area26 = | 'x'3->'x'5 x 'x'3->'x'6 |
1516 Scalar subFaceArea26 = crossProduct(edgeCoord1226-globalPosFace26, edgeCoord2426-globalPosFace26).two_norm();
1517
1518 // compute normal vectors for case 2 (idx1, idx2, idx4, idx6)
1519 GlobalPosition nu11C2 = crossProduct(edgeCoord1226-globalPos1, globalPosFace12-globalPos1);
1520 GlobalPosition nu12C2 = crossProduct(edgeCoord1224-globalPos1, edgeCoord1226-globalPos1);
1521 GlobalPosition nu13C2 = crossProduct(globalPosFace12-globalPos1, edgeCoord1224-globalPos1);
1522
1523 GlobalPosition nu21C2 = crossProduct(globalPosFace26-globalPos2, globalPosFace24-globalPos2);
1524 GlobalPosition nu22C2 = crossProduct(globalPosFace12-globalPos2, globalPosFace26-globalPos2);
1525 GlobalPosition nu23C2 = crossProduct(globalPosFace24-globalPos2, globalPosFace12-globalPos2);
1526
1527 GlobalPosition nu41C2 = crossProduct(edgeCoord2426-globalPos4, edgeCoord1224-globalPos4);
1528 GlobalPosition nu42C2 = crossProduct(globalPosFace24-globalPos4, edgeCoord2426-globalPos4);
1529 GlobalPosition nu43C2 = crossProduct(edgeCoord1224-globalPos4, globalPosFace24-globalPos4);
1530
1531 GlobalPosition nu61C2 = crossProduct(globalPosFace26-globalPos6, edgeCoord1226-globalPos6);
1532 GlobalPosition nu62C2 = crossProduct(edgeCoord2426-globalPos6, globalPosFace26-globalPos6);
1533 GlobalPosition nu63C2 = crossProduct(edgeCoord1226-globalPos6, edgeCoord2426-globalPos6);
1534
1535 // compute T, i.e., the volume of the subtetrahedron
1536 Scalar T1C2 = (globalPosFace12-globalPos1) * crossProduct(edgeCoord1224-globalPos1, edgeCoord1226-globalPos1);
1537 Scalar T2C2 = (globalPosFace12-globalPos2) * crossProduct(globalPosFace26-globalPos2, globalPosFace24-globalPos2);
1538 Scalar T4C2 = (globalPosFace24-globalPos4) * crossProduct(edgeCoord2426-globalPos4, edgeCoord1224-globalPos4);
1539 Scalar T6C2 = (globalPosFace26-globalPos6) * crossProduct(edgeCoord1226-globalPos6, edgeCoord2426-globalPos6);
1540
1541 // compute components needed for flux calculation, denoted as 'omega' and 'r'
1542 GlobalPosition K1nu11C2(0);
1543 K1.mv(nu11C2, K1nu11C2);
1544 GlobalPosition K1nu12C2(0);
1545 K1.mv(nu12C2, K1nu12C2);
1546 GlobalPosition K1nu13C2(0);
1547 K1.mv(nu13C2, K1nu13C2);
1548
1549 GlobalPosition K2nu21C2(0);
1550 K2.mv(nu21C2, K2nu21C2);
1551 GlobalPosition K2nu22C2(0);
1552 K2.mv(nu22C2, K2nu22C2);
1553 GlobalPosition K2nu23C2(0);
1554 K2.mv(nu23C2, K2nu23C2);
1555
1556 GlobalPosition K4nu41C2(0);
1557 K4.mv(nu41C2, K4nu41C2);
1558 GlobalPosition K4nu42C2(0);
1559 K4.mv(nu42C2, K4nu42C2);
1560 GlobalPosition K4nu43C2(0);
1561 K4.mv(nu43C2, K4nu43C2);
1562
1563 GlobalPosition K6nu61C2(0);
1564 K6.mv(nu61C2, K6nu61C2);
1565 GlobalPosition K6nu62C2(0);
1566 K6.mv(nu62C2, K6nu62C2);
1567 GlobalPosition K6nu63C2(0);
1568 K6.mv(nu63C2, K6nu63C2);
1569
1570 // upwinding of lambda is not included here to "recycle" it-> only possible if lambda does
1571 // not vary harshly. If it would, refinement indicator would not allow different grid levels here.
1572 Scalar omega111C2 = /*lambda12C2 */ (outerNormaln12 * K1nu11C2) * subFaceArea12/T1C2;
1573 Scalar omega112C2 = /*lambda12C2 */ (outerNormaln12 * K1nu12C2) * subFaceArea12/T1C2;
1574 Scalar omega113C2 = /*lambda12C2 */ (outerNormaln12 * K1nu13C2) * subFaceArea12/T1C2;
1575
1576 Scalar omega121C2 = /*lambda21C2 */ (outerNormaln12 * K2nu21C2) * subFaceArea12/T2C2;
1577 Scalar omega122C2 = /*lambda21C2 */ (outerNormaln12 * K2nu22C2) * subFaceArea12/T2C2;
1578 Scalar omega123C2 = /*lambda21C2 */ (outerNormaln12 * K2nu23C2) * subFaceArea12/T2C2;
1579
1580 Scalar omega221C2 = /*lambda24C2 */ (outerNormaln24 * K2nu21C2) * subFaceArea24/T2C2;
1581 Scalar omega222C2 = /*lambda24C2 */ (outerNormaln24 * K2nu22C2) * subFaceArea24/T2C2;
1582 Scalar omega223C2 = /*lambda24C2 */ (outerNormaln24 * K2nu23C2) * subFaceArea24/T2C2;
1583
1584 Scalar omega241C2 = /*lambda42C2 */ (outerNormaln24 * K4nu41C2) * subFaceArea24/T4C2;
1585 Scalar omega242C2 = /*lambda42C2 */ (outerNormaln24 * K4nu42C2) * subFaceArea24/T4C2;
1586 Scalar omega243C2 = /*lambda42C2 */ (outerNormaln24 * K4nu43C2) * subFaceArea24/T4C2;
1587
1588 Scalar omega321C2 = /*lambda26C2 */ (outerNormaln26 * K2nu21C2) * subFaceArea26/T2C2;
1589 Scalar omega322C2 = /*lambda26C2 */ (outerNormaln26 * K2nu22C2) * subFaceArea26/T2C2;
1590 Scalar omega323C2 = /*lambda26C2 */ (outerNormaln26 * K2nu23C2) * subFaceArea26/T2C2;
1591
1592 Scalar omega361C2 = /*lambda62C2 */ (outerNormaln26 * K6nu61C2) * subFaceArea26/T6C2;
1593 Scalar omega362C2 = /*lambda62C2 */ (outerNormaln26 * K6nu62C2) * subFaceArea26/T6C2;
1594 Scalar omega363C2 = /*lambda62C2 */ (outerNormaln26 * K6nu63C2) * subFaceArea26/T6C2;
1595
1596 Scalar r211C2 = (nu21C2 * (edgeCoord1224-globalPos2))/T2C2;
1597 Scalar r212C2 = (nu21C2 * (edgeCoord1226-globalPos2))/T2C2;
1598 Scalar r213C2 = (nu21C2 * (edgeCoord2426-globalPos2))/T2C2;
1599
1600 Scalar r221C2 = (nu22C2 * (edgeCoord1224-globalPos2))/T2C2;
1601 Scalar r222C2 = (nu22C2 * (edgeCoord1226-globalPos2))/T2C2;
1602 Scalar r223C2 = (nu22C2 * (edgeCoord2426-globalPos2))/T2C2;
1603
1604 Scalar r231C2 = (nu23C2 * (edgeCoord1224-globalPos2))/T2C2;
1605 Scalar r232C2 = (nu23C2 * (edgeCoord1226-globalPos2))/T2C2;
1606 Scalar r233C2 = (nu23C2 * (edgeCoord2426-globalPos2))/T2C2;
1607
1608
1610 // compute transmissibility matrix T = CA^{-1}B+D
1611 DimMatrix C(0), A(0);
1612 Dune::FieldMatrix<Scalar,dim,dim+1> D(0), B(0);
1613
1614 // evaluate matrix C, D, A, B
1615 C[0][0] = -omega121C2;
1616 C[0][1] = -omega122C2;
1617 C[0][2] = -omega123C2;
1618 C[1][0] = -omega221C2;
1619 C[1][1] = -omega222C2;
1620 C[1][2] = -omega223C2;
1621 C[2][0] = -omega321C2;
1622 C[2][1] = -omega322C2;
1623 C[2][2] = -omega323C2;
1624
1625 D[0][1] = omega121C2 + omega122C2 + omega123C2;
1626 D[1][1] = omega221C2 + omega222C2 + omega223C2;
1627 D[2][1] = omega321C2 + omega322C2 + omega323C2;
1628
1629 A[0][0] = omega121C2 - omega112C2 - omega111C2*r211C2 - omega113C2*r212C2;
1630 A[0][1] = omega122C2 - omega111C2*r221C2 - omega113C2*r222C2;
1631 A[0][2] = omega123C2 - omega111C2*r231C2 - omega113C2*r232C2;
1632 A[1][0] = omega221C2 - omega242C2*r211C2 - omega243C2*r213C2;
1633 A[1][1] = omega222C2 - omega241C2 - omega242C2*r221C2 - omega243C2*r223C2;
1634 A[1][2] = omega223C2 - omega242C2*r231C2 - omega243C2*r233C2;
1635 A[2][0] = omega321C2 - omega361C2*r213C2 - omega362C2*r212C2;
1636 A[2][1] = omega322C2 - omega361C2*r223C2 - omega362C2*r222C2;
1637 A[2][2] = omega323C2 - omega363C2 - omega361C2*r233C2 - omega362C2*r232C2;
1638
1639 B[0][0] = -omega111C2 - omega112C2 - omega113C2;
1640 B[0][1] = omega121C2 + omega122C2 + omega123C2 + omega111C2*(1.0 - r211C2 - r221C2 -r231C2)
1641 + omega113C2*(1.0 - r212C2 - r222C2 - r232C2);
1642 B[1][1] = omega221C2 + omega222C2 + omega223C2 + omega242C2*(1.0 - r211C2 - r221C2 - r231C2)
1643 + omega243C2*(1.0 - r213C2 - r223C2 - r233C2);
1644 B[1][2] = -omega241C2 - omega242C2 - omega243C2;
1645 B[2][1] = omega321C2 + omega322C2 + omega323C2 + omega361C2*(1.0 - r213C2 - r223C2 - r233C2)
1646 + omega362C2*(1.0 - r212C2 -r222C2 -r232C2);
1647 B[2][3] = -omega361C2 - omega362C2 -omega363C2;
1648
1649// printmatrix(std::cout, A, "matrix A ", "row", 11, 3);
1650// printmatrix(std::cout, B, "matrix B ", "row", 11, 3);
1651// printmatrix(std::cout, C, "matrix C ", "row", 11, 3);
1652// printmatrix(std::cout, D, "matrix D ", "row", 11, 3);
1653
1654 // compute T
1655 A.invert();
1656 D += B.leftmultiply(C.rightmultiply(A));
1657 T = D[0];
1658
1660 if(maxInteractionVolumes ==1)
1661 {
1662 T *= intersection.geometry().volume()/subFaceArea12 ;
1663
1664 // set your map entry
1665 problem().variables().storeMpfaData3D(intersection, T, globalPos4, eIdxGlobal4, globalPos6, eIdxGlobal6);
1666 return 1; // indicates that only 1 interaction region was regarded
1667 }
1668 else
1669 {
1670 int countInteractionRegions = 1;
1671 //initialize additional transmissitivity matrix
1672 TransmissivityMatrix additionalT(0.);
1673
1674 auto outerCorner = intersection.inside().template subEntity<dim>(0); //initialize with rubbish
1675 // prepare additonal pointer to cells
1676 auto additional2 = intersection.inside(); //initialize with something wrong!
1677 auto additional3 = intersection.inside();
1678 int caseL = -2;
1679
1680 /**** 2nd interaction region: get corner of interest ************/
1681 // search through corners of large cell with isIt
1682 int localIdxLarge = searchCommonVertex_(intersection, outerCorner);
1683
1684 //in the parallel case, skip all border entities
1685 #if HAVE_MPI
1686 if (problem().gridView().comm().size() > 1)
1687 if(outerCorner.partitionType() != Dune::InteriorEntity)
1688 caseL = -1; // abort this specific interaction volume
1689 #endif
1690
1691 // get Interaction Volume object
1692 int vIdxGlobal = problem().variables().index(outerCorner);
1693 InteractionVolume& interactionVolume
1694 = interactionVolumesContainer_->interactionVolume(vIdxGlobal);
1695
1696 // abort if we are on boundary
1697 if(interactionVolume.isBoundaryInteractionVolume())
1698 caseL = -1;
1699
1700 // use Markus mpfa-l implementation
1701 int subVolumeFaceIdx = -1;
1702 bool properFluxDirection = true;
1703 if(caseL == -2)
1704 {
1705 //get Hanging Node type: no hanging node would mean -1
1706 int hangingNodeType = interactionVolume.getHangingNodeType();
1707
1708 if(hangingNodeType == InteractionVolume::noHangingNode)
1709 subVolumeFaceIdx = interactionVolumesContainer_->getMpfaCase8cells(isIt, localIdxLarge, interactionVolume, properFluxDirection);
1710 else if(hangingNodeType == InteractionVolume::sixSmallCells)
1711 subVolumeFaceIdx = interactionVolumesContainer_->getMpfaCase6cells(isIt, interactionVolume, properFluxDirection);
1712 else
1713 Dune::dgrave << "HangingType " << hangingNodeType << " not implemented " << std::endl;
1714
1715 caseL = this->transmissibilityAdapter_(isIt, interactionVolume, subVolumeFaceIdx,
1716 properFluxDirection, additional2, additional3, additionalT);
1717 }
1718
1719 //store everything as second interaction region
1720 if(caseL != -1) //check if we regard 2 interaction regions
1721 {
1722 problem().variables().storeMpfaData3D(intersection, additionalT,
1723 additional2.geometry().center(), problem().variables().index(additional2),
1724 additional3.geometry().center(), problem().variables().index(additional3),
1725 1); // offset for second interaction region
1726 countInteractionRegions++;
1727 }
1728
1729 /***** 3rd and 4th interaction region *******/
1730 if(maxInteractionVolumes>2)
1731 {
1732 // loop through remaining 2 points
1733 std::vector<int> diagonal;
1734 for(int verticeSmall = 0; verticeSmall < intersection.outside().subEntities(dim); ++verticeSmall)
1735 {
1736 auto vSmall = intersection.outside().template subEntity<dim>(verticeSmall);
1737
1738 //in the parallel case, skip all border entities
1739 #if HAVE_MPI
1740 if (problem().gridView().comm().size() > 1)
1741 if(vSmall.partitionType() != Dune::InteriorEntity)
1742 continue;
1743 #endif
1744
1745 // get postion as seen from element
1746 GlobalPosition vertexOnElement
1747 = refElement.position(verticeSmall, dim);
1748
1749 for (int indexOnFace = 0; indexOnFace < 4; indexOnFace++)
1750 {
1751 // get position as seen from interface
1752 GlobalPosition vertexOnInterface
1753 = intersection.geometryInOutside().corner(indexOnFace);
1754
1755 if(vSmall != outerCorner
1756 && ((vertexOnInterface - vertexOnElement).two_norm()<1e-5))
1757 {
1758 int vIdxGlobal2 = problem().variables().index(vSmall);
1759 // acess interactionVolume
1760 InteractionVolume& interactionVolume2
1761 = interactionVolumesContainer_->interactionVolume(vIdxGlobal2);
1762 if(interactionVolume2.isBoundaryInteractionVolume())
1763 continue;
1764
1765 int hangingNodeType = interactionVolume2.getHangingNodeType();
1766 // reset flux direction indicator
1767 properFluxDirection = true;
1768
1769 if(hangingNodeType != InteractionVolume::fourSmallCellsFace)
1770 {
1771 diagonal.push_back(problem().variables().index(vSmall));
1772 // a) take interaction volume and determine fIdx
1773 if(hangingNodeType == InteractionVolume::noHangingNode)
1774 {
1775 //TODO determine current localIdxLarge!!!!
1776 Dune::dgrave << " args, noHangingNode on additional interaction region";
1777 // subVolumeFaceIdx = getMpfaCase8cells_(isIt, localIdxLarge, interactionVolume2, properFluxDirection);
1778 }
1779 else if(hangingNodeType == InteractionVolume::sixSmallCells)
1780 subVolumeFaceIdx = interactionVolumesContainer_->getMpfaCase6cells(isIt,
1781 interactionVolume2, properFluxDirection);
1782 else
1783 subVolumeFaceIdx = interactionVolumesContainer_->getMpfaCase2or4cells(isIt,
1784 interactionVolume2, properFluxDirection);
1785
1786 // b) calculate T, eIdxGlobal3+4
1787 caseL = this->transmissibilityAdapter_(isIt, interactionVolume2, subVolumeFaceIdx,
1788 properFluxDirection, additional2, additional3, additionalT);
1789
1790 // c) store it
1791 //store everything as third/4th interaction region
1792 if(caseL != -1) //check if we regard this interaction region
1793 {
1794 problem().variables().storeMpfaData3D(intersection, additionalT,
1795 additional2.geometry().center(), problem().variables().index(additional2),
1796 additional3.geometry().center(), problem().variables().index(additional3),
1797 countInteractionRegions); // offset for this interaction region
1798 countInteractionRegions++;
1799 }
1800 }
1801 //else we would have type 1, which is handled explicitly in the beginning of this method
1802 }
1803 }
1804 }
1805 }
1806
1807 // set your map entry
1808 problem().variables().storeMpfaData3D(intersection, T, globalPos4, eIdxGlobal4, globalPos6, eIdxGlobal6);
1809
1810 // determine weights
1811 Scalar weight = intersection.geometry().volume()/subFaceArea12; // =4 for 1 interaction region
1812 weight /= static_cast<Scalar>(countInteractionRegions);
1813
1814 // perform weighting of transmissibilies
1815 problem().variables().performTransmissitivityWeighting(intersection, weight);
1816
1817 return countInteractionRegions;
1818 }
1819
1820 return 0;
1821}
1822
1840template<class TypeTag>
1842 InteractionVolume& interactionVolume,
1843 const int& subVolumeFaceIdx,
1844 bool properFluxDirection,
1845 Element& additional2,
1846 Element& additional3,
1847 TransmissivityMatrix& additionalT)
1848{
1849 // abort if we are on boundary
1850 if(interactionVolume.isBoundaryInteractionVolume())
1851 return -1;
1852
1853 //get Hanging Node type: no hanging node would mean -1
1854 int hangingNodeType = interactionVolume.getHangingNodeType();
1855
1856 // prepare necessary variables etc
1857 Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> T(0);
1858 int caseL = -1;
1859 Dune::FieldVector<Scalar, dim> unity(1.);
1860 std::vector<Dune::FieldVector<Scalar, dim> > lambda
1861 = {unity, unity, unity, unity, unity, unity, unity, unity};
1862 Dune::FieldVector<bool, 4> useCases(false);
1863
1864 /*********** calculate transmissibility for that case ******/
1865 switch(subVolumeFaceIdx)
1866 {
1867 case 0:{
1868 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
1869 lambda, 0, 1, 2, 3, 4, 5);
1870
1871 additionalT = T[0];
1872
1873 // determine cells for T-matrix entry 2 and 3
1874 switch (caseL)
1875 {
1876 case 1:{
1877 additional2 = interactionVolume.getSubVolumeElement(2);
1878 additional3 = interactionVolume.getSubVolumeElement(4);
1879 break; }
1880 case 2:{
1881 additional2 = interactionVolume.getSubVolumeElement(3);
1882 additional3 = interactionVolume.getSubVolumeElement(5);
1883 break; }
1884 case 3:{
1885 additional2 = interactionVolume.getSubVolumeElement(3);
1886 additional3 = interactionVolume.getSubVolumeElement(4);
1887 break; }
1888 case 4:{
1889 additional2 = interactionVolume.getSubVolumeElement(2);
1890 additional3 = interactionVolume.getSubVolumeElement(5);
1891 break; }
1892 }
1893 break;
1894 }
1895
1896 case 1:{
1897 if (hangingNodeType == InteractionVolume::twoSmallCells
1898 || hangingNodeType == InteractionVolume::fourSmallCellsDiag )
1899 {
1900 useCases[0] = true;
1901 useCases[1] = false;
1902 useCases[2] = false;
1903 if(hangingNodeType != InteractionVolume::twoSmallCells)
1904 useCases[3] = true; //differs from 2p Implementation
1905 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
1906 lambda, 1, 3, 0, 2, 5, 7, useCases);
1907 }
1908 else
1909 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
1910 lambda, 1, 3, 0, 2, 5, 7);
1911
1912 additionalT = T[0];
1913
1914 // determine cells for T-matrix entry 2 and 3
1915 switch (caseL)
1916 {
1917 case 1:
1918 {
1919 additional2 = interactionVolume.getSubVolumeElement(0);
1920 additional3 = interactionVolume.getSubVolumeElement(5);
1921 break;}
1922 case 2:
1923 {
1924 additional2 = interactionVolume.getSubVolumeElement(2);
1925 additional3 = interactionVolume.getSubVolumeElement(7);
1926 break;}
1927 case 3:
1928 {
1929 additional2 = interactionVolume.getSubVolumeElement(2);
1930 additional3 = interactionVolume.getSubVolumeElement(5);
1931 break;}
1932 case 4:
1933 {
1934 additional2 = interactionVolume.getSubVolumeElement(0);
1935 additional3 = interactionVolume.getSubVolumeElement(7);
1936 break;}
1937 }
1938 break;
1939 }
1940
1941 case 2:
1942 {
1943 assert (hangingNodeType != InteractionVolume::twoSmallCells
1944 && hangingNodeType != InteractionVolume::fourSmallCellsDiag);
1945
1946 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
1947 lambda, 3, 2, 1, 0, 7, 6);
1948
1949 additionalT = T[0];
1950
1951 // determine cells for T-matrix entry 2 and 3
1952 switch (caseL)
1953 {
1954 case 1:
1955 {
1956 additional2 = interactionVolume.getSubVolumeElement(1);
1957 additional3 = interactionVolume.getSubVolumeElement(7);
1958 break;}
1959 case 2:
1960 {
1961 additional2 = interactionVolume.getSubVolumeElement(0);
1962 additional3 = interactionVolume.getSubVolumeElement(6);
1963 break;}
1964 case 3:
1965 {
1966 additional2 = interactionVolume.getSubVolumeElement(0);
1967 additional3 = interactionVolume.getSubVolumeElement(7);
1968 break;}
1969 case 4:
1970 {
1971 additional2 = interactionVolume.getSubVolumeElement(1);
1972 additional3 = interactionVolume.getSubVolumeElement(6);
1973 break;}
1974 }
1975 break;
1976 }
1977
1978 case 3:{
1979 if (hangingNodeType == InteractionVolume::twoSmallCells
1980 || hangingNodeType == InteractionVolume::fourSmallCellsDiag)
1981 {
1982 useCases[0] = false;
1983 useCases[1] = true;
1984 if(hangingNodeType != InteractionVolume::twoSmallCells)
1985 useCases[2] = true; //TODO: warning, hacked from markus!!
1986 useCases[3] = false;
1987 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T,
1988 interactionVolume, lambda, 2, 0, 3, 1, 6, 4, useCases);
1989 }
1990 else
1991 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
1992 lambda, 2, 0, 3, 1, 6, 4);
1993
1994 additionalT = T[0];
1995
1996 // determine cells for T-matrix entry 2 and 3
1997 switch (caseL)
1998 {
1999 case 1:
2000 {
2001 additional2 = interactionVolume.getSubVolumeElement(3);
2002 additional3 = interactionVolume.getSubVolumeElement(6);
2003 break;}
2004 case 2:
2005 {
2006 additional2 = interactionVolume.getSubVolumeElement(1);
2007 additional3 = interactionVolume.getSubVolumeElement(4);
2008 break;}
2009 case 3:
2010 {
2011 additional2 = interactionVolume.getSubVolumeElement(1);
2012 additional3 = interactionVolume.getSubVolumeElement(6);
2013 break;}
2014 case 4:
2015 {
2016 additional2 = interactionVolume.getSubVolumeElement(3);
2017 additional3 = interactionVolume.getSubVolumeElement(4);
2018 break;}
2019 }
2020 break;
2021 }
2022
2023 case 4:{
2024 if (hangingNodeType == InteractionVolume::fourSmallCellsEdge) // should never happen, cause TPFA should be applied
2025 {
2026 assert(problem().variables().index(interactionVolume.getSubVolumeElement(4))
2027 != problem().variables().index(interactionVolume.getSubVolumeElement(5))); // else there would not be a subVolFaceIdx 4
2028 Dune::dgrave << " SubVolumeFace4 in hanging node type 3 should be modelled by"
2029 << " Tpfa!!" <<std::endl; // TODO: or use 1,5,3,4 and case 4
2030 return -1;
2031 }
2032 else
2033 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2034 lambda, 5, 4, 7, 6, 1, 0);
2035
2036 additionalT = T[0];
2037
2038 // determine cells for T-matrix entry 2 and 3
2039 switch (caseL)
2040 {
2041 case 1:{
2042 additional2 = interactionVolume.getSubVolumeElement(7);
2043 additional3 = interactionVolume.getSubVolumeElement(1);
2044 break; }
2045 case 2:{
2046 additional2 = interactionVolume.getSubVolumeElement(6);
2047 additional3 = interactionVolume.getSubVolumeElement(0);
2048 break; }
2049 case 3:{
2050 additional2 = interactionVolume.getSubVolumeElement(6);
2051 additional3 = interactionVolume.getSubVolumeElement(1);
2052 break; }
2053 case 4:{
2054 additional2 = interactionVolume.getSubVolumeElement(7);
2055 additional3 = interactionVolume.getSubVolumeElement(0);
2056 break; }
2057 }
2058 break;
2059 }
2060
2061 case 5:{
2062 if (hangingNodeType == InteractionVolume::fourSmallCellsEdge)
2063 {
2064 assert (problem().variables().index(interactionVolume.getSubVolumeElement(4))
2065 != problem().variables().index(interactionVolume.getSubVolumeElement(6))); // else there would not be a subVolFaceIdx 5
2066 Dune::dgrave << " SubVolumeFace5 in hanging node type 3 should be modelled by"
2067 << " Tpfa!!" <<std::endl; // TODO: or use 1,5,7,0 and case 3
2068 return -1;
2069 }
2070 else if (hangingNodeType == InteractionVolume::sixSmallCells)
2071 {
2072 useCases[0] = false;
2073 useCases[1] = true;
2074 useCases[2] = true;
2075 useCases[3] = false;
2076
2077 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2078 lambda, 7, 5, 6, 4, 3, 1, useCases);
2079 }
2080 else if (hangingNodeType == InteractionVolume::fourSmallCellsDiag)
2081 {
2082 useCases[0] = true;
2083 useCases[1] = false;
2084 useCases[2] = false;
2085 useCases[3] = true;
2086 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2087 lambda, 7, 5, 6, 4, 3, 1, useCases);
2088 }
2089 else
2090 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2091 lambda, 7, 5, 6, 4, 3, 1);
2092
2093 additionalT = T[0];
2094
2095 // determine cells for T-matrix entry 2 and 3
2096 switch (caseL)
2097 {
2098 case 1:
2099 {
2100 additional2 = interactionVolume.getSubVolumeElement(6);
2101 additional3 = interactionVolume.getSubVolumeElement(3);
2102 break;}
2103 case 2:
2104 {
2105 additional2 = interactionVolume.getSubVolumeElement(4);
2106 additional3 = interactionVolume.getSubVolumeElement(1);
2107 break;}
2108 case 3:
2109 {
2110 additional2 = interactionVolume.getSubVolumeElement(4);
2111 additional3 = interactionVolume.getSubVolumeElement(3);
2112 break;}
2113 case 4:
2114 {
2115 additional2 = interactionVolume.getSubVolumeElement(6);
2116 additional3 = interactionVolume.getSubVolumeElement(1);
2117 break;}
2118 }
2119 break;
2120 }
2121
2122 case 6:{
2123 if (hangingNodeType == InteractionVolume::fourSmallCellsEdge)
2124 {
2125 assert (problem().variables().index(interactionVolume.getSubVolumeElement(4))
2126 != problem().variables().index(interactionVolume.getSubVolumeElement(5))); // else there would not be a subVolFaceIdx 4
2127 Dune::dgrave << " SubVolumeFace6 in hanging node type 3 should be modelled by"
2128 << " Tpfa!!" <<std::endl; // TODO: or use 2,6,0,7 and case 4
2129 return -1;
2130 }
2131 else
2132 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2133 lambda, 6, 7, 4, 5, 2, 3);
2134
2135 additionalT = T[0];
2136
2137 // determine cells for T-matrix entry 2 and 3
2138 switch (caseL)
2139 {
2140 case 1:
2141 {
2142 additional2 = interactionVolume.getSubVolumeElement(4);
2143 additional3 = interactionVolume.getSubVolumeElement(2);
2144 break;}
2145 case 2:
2146 {
2147 additional2 = interactionVolume.getSubVolumeElement(5);
2148 additional3 = interactionVolume.getSubVolumeElement(3);
2149 break;}
2150 case 3:
2151 {
2152 additional2 = interactionVolume.getSubVolumeElement(5);
2153 additional3 = interactionVolume.getSubVolumeElement(2);
2154 break;}
2155 case 4:
2156 {
2157 additional2 = interactionVolume.getSubVolumeElement(4);
2158 additional3 = interactionVolume.getSubVolumeElement(3);
2159 break;}
2160 }
2161 break;
2162 }
2163
2164 case 7:
2165 {
2166 if (hangingNodeType == InteractionVolume::fourSmallCellsEdge)
2167 {
2168 assert (problem().variables().index(interactionVolume.getSubVolumeElement(4))
2169 != problem().variables().index(interactionVolume.getSubVolumeElement(6))); // else there would not be a subVolFaceIdx 5
2170 Dune::dgrave << " SubVolumeFace5 in hanging node type 3 should be modelled by"
2171 << " Tpfa!!" <<std::endl; // TODO: or use 4,0,6,1 and case 4
2172 return -1;
2173 }
2174 else if (hangingNodeType == InteractionVolume::sixSmallCells)
2175 {
2176 useCases[0] = true;
2177 useCases[1] = false;
2178 useCases[2] = false;
2179 useCases[3] = true;
2180
2181 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2182 lambda, 4, 6, 5, 7, 0, 2, useCases);
2183 }
2184 else if (hangingNodeType == InteractionVolume::fourSmallCellsDiag)
2185 {
2186 useCases[0] = false;
2187 useCases[1] = true;
2188 useCases[2] = true;
2189 useCases[3] = false;
2190 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2191 lambda, 4, 6, 5, 7, 0, 2, useCases);
2192 }
2193 else
2194 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2195 lambda, 4, 6, 5, 7, 0, 2);
2196
2197 additionalT = T[0];
2198
2199 // determine cells for T-matrix entry 2 and 3
2200 switch (caseL)
2201 {
2202 case 1:
2203 {
2204 additional2 = interactionVolume.getSubVolumeElement(5);
2205 additional3 = interactionVolume.getSubVolumeElement(0);
2206 break;}
2207 case 2:
2208 {
2209 additional2 = interactionVolume.getSubVolumeElement(7);
2210 additional3 = interactionVolume.getSubVolumeElement(2);
2211 break;}
2212 case 3:
2213 {
2214 additional2 = interactionVolume.getSubVolumeElement(7);
2215 additional3 = interactionVolume.getSubVolumeElement(0);
2216 break;}
2217 case 4:
2218 {
2219 additional2 = interactionVolume.getSubVolumeElement(5);
2220 additional3 = interactionVolume.getSubVolumeElement(2);
2221 break;}
2222 }
2223 break;
2224 }
2225
2226 case 8:
2227 {
2228 if(hangingNodeType == InteractionVolume::noHangingNode
2229 || hangingNodeType == InteractionVolume::sixSmallCells)
2230 {
2231 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2232 lambda, 4, 0, 6, 2, 5, 1);
2233 }
2234 else if (hangingNodeType == InteractionVolume::twoSmallCells
2235 || hangingNodeType == InteractionVolume::fourSmallCellsFace)
2236 {
2237 caseL = mpfal3DTransmissibilityCalculator_.transmissibilityCaseTwo(T, interactionVolume,
2238 lambda, 4, 0, 2, 1);
2239 }
2240 else if (hangingNodeType == InteractionVolume::fourSmallCellsDiag
2241 || (hangingNodeType == InteractionVolume::fourSmallCellsEdge
2242 && (problem().variables().index(interactionVolume.getSubVolumeElement(4))
2243 != problem().variables().index(interactionVolume.getSubVolumeElement(6)))) )
2244 {
2245 useCases[0] = false;
2246 useCases[1] = true;
2247 useCases[2] = false;
2248 useCases[3] = true;
2249
2250 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2251 lambda, 4, 0, 6, 2, 5, 1, useCases);
2252 }
2253 else if (hangingNodeType == InteractionVolume::fourSmallCellsEdge)
2254 {
2255 useCases[0] = false;
2256 useCases[1] = true;
2257 useCases[2] = true;
2258 useCases[3] = false;
2259
2260 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2261 lambda, 4, 0, 6, 2, 5, 1, useCases);
2262 }
2263
2264 additionalT = T[0];
2265
2266 // determine cells for T-matrix entry 2 and 3
2267 switch (caseL)
2268 {
2269 case 1:
2270 {
2271 additional2 = interactionVolume.getSubVolumeElement(6);
2272 additional3 = interactionVolume.getSubVolumeElement(5);
2273 break;}
2274 case 2:
2275 {
2276 additional2 = interactionVolume.getSubVolumeElement(2);
2277 additional3 = interactionVolume.getSubVolumeElement(1);
2278 break;}
2279 case 3:
2280 {
2281 additional2 = interactionVolume.getSubVolumeElement(2);
2282 additional3 = interactionVolume.getSubVolumeElement(5);
2283 break;}
2284 case 4:
2285 {
2286 additional2 = interactionVolume.getSubVolumeElement(6);
2287 additional3 = interactionVolume.getSubVolumeElement(1);
2288 break;}
2289 }
2290 break;
2291 }
2292
2293 case 9:
2294 {
2295 if(hangingNodeType == InteractionVolume::noHangingNode
2296 || hangingNodeType == InteractionVolume::sixSmallCells)
2297 {
2298 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2299 lambda, 1, 5, 3, 7, 0, 4);
2300 }
2301 else if (hangingNodeType == InteractionVolume::twoSmallCells || hangingNodeType == InteractionVolume::fourSmallCellsFace)
2302 {
2303 caseL = mpfal3DTransmissibilityCalculator_.transmissibilityCaseOne(T, interactionVolume,
2304 lambda, 1, 5, 3, 0);
2305 }
2306 else if (hangingNodeType == InteractionVolume::fourSmallCellsDiag
2307 || (hangingNodeType == InteractionVolume::fourSmallCellsEdge
2308 &&(problem().variables().index(interactionVolume.getSubVolumeElement(4))
2309 != problem().variables().index(interactionVolume.getSubVolumeElement(6))) ))
2310 {
2311 useCases[0] = true;
2312 useCases[1] = false;
2313 useCases[2] = true;
2314 useCases[3] = false;
2315
2316 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2317 lambda, 1, 5, 3, 7, 0, 4, useCases);
2318 }
2319 else if (hangingNodeType == InteractionVolume::fourSmallCellsEdge
2320 &&(problem().variables().index(interactionVolume.getSubVolumeElement(4))
2321 != problem().variables().index(interactionVolume.getSubVolumeElement(5))) )
2322 {
2323 useCases[0] = true;
2324 useCases[1] = false;
2325 useCases[2] = false;
2326 useCases[3] = true;
2327
2328 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2329 lambda, 1, 5, 3, 7, 0, 4, useCases);
2330 }
2331 else
2332 Dune::dgrave << " Missing case for subVolFaceIdx 9!!" <<std::endl;
2333
2334 additionalT = T[0];
2335
2336 // determine cells for T-matrix entry 2 and 3
2337 switch (caseL)
2338 {
2339 case 1:
2340 {
2341 additional2 = interactionVolume.getSubVolumeElement(3);
2342 additional3 = interactionVolume.getSubVolumeElement(0);
2343 break;}
2344 case 2:
2345 {
2346 additional2 = interactionVolume.getSubVolumeElement(7);
2347 additional3 = interactionVolume.getSubVolumeElement(4);
2348 break;}
2349 case 3:
2350 {
2351 additional2 = interactionVolume.getSubVolumeElement(7);
2352 additional3 = interactionVolume.getSubVolumeElement(0);
2353 break;}
2354 case 4:
2355 {
2356 additional2 = interactionVolume.getSubVolumeElement(3);
2357 additional3 = interactionVolume.getSubVolumeElement(4);
2358 break;}
2359 }
2360 break;
2361 }
2362
2363 case 10:
2364 {
2365 if (hangingNodeType == InteractionVolume::fourSmallCellsFace)
2366 caseL = mpfal3DTransmissibilityCalculator_.transmissibilityCaseTwo(T, interactionVolume,
2367 lambda, 7, 3, 1, 2);
2368 else if ((hangingNodeType == InteractionVolume::fourSmallCellsEdge
2369 &&(problem().variables().index(interactionVolume.getSubVolumeElement(4))
2370 != problem().variables().index(interactionVolume.getSubVolumeElement(6))) )
2371 || hangingNodeType == InteractionVolume::sixSmallCells)
2372 {
2373 useCases[0] = false;
2374 useCases[1] = true;
2375 useCases[2] = false;
2376 useCases[3] = true;
2377
2378 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2379 lambda, 7, 3, 5, 1, 6, 2, useCases);
2380 }
2381 else if (hangingNodeType == InteractionVolume::fourSmallCellsEdge)
2382 {
2383 useCases[0] = false;
2384 useCases[1] = true;
2385 useCases[2] = true;
2386 useCases[3] = false;
2387
2388 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2389 lambda, 7, 3, 5, 1, 6, 2, useCases);
2390 }
2391 else if (hangingNodeType == InteractionVolume::fourSmallCellsDiag)
2392 {
2393 useCases[0] = true;
2394 useCases[1] = false;
2395 useCases[2] = true;
2396 useCases[3] = false;
2397
2398 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2399 lambda, 7, 3, 5, 1, 6, 2, useCases);
2400 }
2401 else
2402 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2403 lambda, 7, 3, 5, 1, 6, 2);
2404
2405 additionalT = T[0];
2406
2407 // determine cells for T-matrix entry 2 and 3
2408 switch (caseL)
2409 {
2410 case 1:
2411 {
2412 additional2 = interactionVolume.getSubVolumeElement(5);
2413 additional3 = interactionVolume.getSubVolumeElement(6);
2414 break;}
2415 case 2:
2416 {
2417 additional2 = interactionVolume.getSubVolumeElement(1);
2418 additional3 = interactionVolume.getSubVolumeElement(2);
2419 break;}
2420 case 3:
2421 {
2422 additional2 = interactionVolume.getSubVolumeElement(1);
2423 additional3 = interactionVolume.getSubVolumeElement(6);
2424 break;}
2425 case 4:
2426 {
2427 additional2 = interactionVolume.getSubVolumeElement(5);
2428 additional3 = interactionVolume.getSubVolumeElement(2);
2429 break;}
2430 }
2431 break;
2432 }
2433
2434 case 11:
2435 {
2436 if(!interactionVolume.isHangingNodeVolume())
2437 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2438 lambda, 2, 6, 0, 4, 3, 7);
2439 else if (hangingNodeType == InteractionVolume::fourSmallCellsFace)
2440 caseL = mpfal3DTransmissibilityCalculator_.transmissibilityCaseOne(T, interactionVolume,
2441 lambda, 2, 6, 0, 3);
2442 else if ((hangingNodeType == InteractionVolume::fourSmallCellsEdge
2443 && (problem().variables().index(interactionVolume.getSubVolumeElement(4))
2444 != problem().variables().index(interactionVolume.getSubVolumeElement(6))))
2445 || hangingNodeType == InteractionVolume::sixSmallCells)
2446 {
2447 useCases[0] = true;
2448 useCases[1] = false;
2449 useCases[2] = true;
2450 useCases[3] = false;
2451
2452 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2453 lambda, 2, 6, 0, 4, 3, 7, useCases);
2454 }
2455 else if (hangingNodeType == InteractionVolume::fourSmallCellsEdge
2456 && (problem().variables().index(interactionVolume.getSubVolumeElement(4))
2457 != problem().variables().index(interactionVolume.getSubVolumeElement(5))) )
2458 {
2459 useCases[0] = true;
2460 useCases[1] = false;
2461 useCases[2] = false;
2462 useCases[3] = true;
2463
2464 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2465 lambda, 2, 6, 0, 4, 3, 7, useCases);
2466 }
2467 else if (hangingNodeType == InteractionVolume::fourSmallCellsDiag)
2468 {
2469 useCases[0] = false;
2470 useCases[1] = true;
2471 useCases[2] = false;
2472 useCases[3] = true;
2473
2474 caseL = mpfal3DTransmissibilityCalculator_.transmissibility(T, interactionVolume,
2475 lambda, 2, 6, 0, 4, 3, 7, useCases);
2476 }
2477
2478 additionalT = T[0];
2479
2480 // determine cells for T-matrix entry 2 and 3
2481 switch (caseL)
2482 {
2483 case 1:
2484 {
2485 additional2 = interactionVolume.getSubVolumeElement(0);
2486 additional3 = interactionVolume.getSubVolumeElement(3);
2487 break;}
2488 case 2:
2489 {
2490 additional2 = interactionVolume.getSubVolumeElement(4);
2491 additional3 = interactionVolume.getSubVolumeElement(7);
2492 break;}
2493 case 3:
2494 {
2495 additional2 = interactionVolume.getSubVolumeElement(4);
2496 additional3 = interactionVolume.getSubVolumeElement(3);
2497 break;}
2498 case 4:
2499 {
2500 additional2 = interactionVolume.getSubVolumeElement(0);
2501 additional3 = interactionVolume.getSubVolumeElement(7);
2502 break;}
2503 }
2504 break;}
2505 }
2506
2507 //if necessary, correct for reversely calculated flux direction
2508 if(!properFluxDirection)
2509 {
2510 // mpfal3DTransmissibilityCalculator_.setTransChoiceThreshold(transChoiceThreshold_);
2511 // a) reverse direction
2512 additionalT *= -1;
2513 // b) swap cell I and J
2514 using std::swap;
2515 swap(additionalT[0], additionalT[1]);
2516 }
2517
2518 return caseL;
2519}
2520
2521
2522}//end namespace Dumux
2523#endif
Define some often used mathematical functions.
Simplifies writing multi-file VTK datasets.
Contains a class to exchange entries of a vector.
Provides methods for transmissibility calculation in 3-d.
Defines the properties required for the adaptive sequential 2p2c models.
Interaction volume container for compositional adaptive 3-d (using MPFA L-method).
Finite volume 2p2c pressure model with multi-physics.
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
Dune::FieldVector< Scalar, 3 > crossProduct(const Dune::FieldVector< Scalar, 3 > &vec1, const Dune::FieldVector< Scalar, 3 > &vec2)
Cross product of two vectors in three-dimensional Euclidean space.
Definition: math.hh:640
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 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
A data handle class to exchange entries of a vector.
Definition: vectorcommdatahandle.hh:78
Provides methods for transmissibility calculation in 3-d.
Definition: 3dtransmissibilitycalculator.hh:51
The finite volume model for the solution of the compositional pressure equation.
Definition: fv3dpressureadaptive.hh:81
void update()
Definition: fv3dpressureadaptive.hh:162
void adaptPressure()
Adapt primary variables vector after adapting the grid.
Definition: fv3dpressureadaptive.hh:213
bool enableMPFA
Enables mpfa on hanging nodes (on by default)
Definition: fv3dpressureadaptive.hh:302
int transmissibilityAdapter_(const IntersectionIterator &isIt, InteractionVolume &interactionVolume, const int &subVolumeFaceIdx, bool properFluxDirection, Element &additional2, Element &additional3, TransmissivityMatrix &additionalT)
Adapter to use the general implementation of the mpfa-l for the compositional models.
Definition: fv3dpressureadaptive.hh:1841
void initializeMatrix()
initializes the matrix to store the system of equations
Definition: fv3dpressureadaptive.hh:313
void initializeMatrixRowSize()
Initialize the row sizes of the sparse global matrix.
Definition: fv3dpressureadaptive.hh:329
FvMpfaL3dTransmissibilityCalculator< TypeTag > mpfal3DTransmissibilityCalculator_
The common implementation to calculate the Transmissibility with the mpfa-L-method.
Definition: fv3dpressureadaptive.hh:308
bool enableVolumeIntegral_
Calculates the volume integral (on by default)
Definition: fv3dpressureadaptive.hh:301
void initializeMatrixIndices()
Determine position of matrix entries.
Definition: fv3dpressureadaptive.hh:578
int computeTransmissibilities(const IntersectionIterator &, TransmissivityMatrix &, GlobalPosition &, int &, GlobalPosition &, int &)
Computes the transmissibility coefficients for the MPFA-l method in 3D.
Definition: fv3dpressureadaptive.hh:1348
void getMpfaFlux(const IntersectionIterator &, const CellData &)
Compute flux through an irregular interface using a mpfa method.
Definition: fv3dpressureadaptive.hh:804
void assemble(bool first)
function which assembles the system of equations to be solved
Definition: fv3dpressureadaptive.hh:643
FV3dPressure2P2CAdaptive(Problem &problem)
Constructs a FVPressure2P2C object.
Definition: fv3dpressureadaptive.hh:248
std::map< int, std::vector< int > > irregularCellMap_
Container to store all cell's Indice with a hanging node.
Definition: fv3dpressureadaptive.hh:300
void initialize(bool solveTwice=false)
Definition: fv3dpressureadaptive.hh:182
void get1pMpfaFlux(const IntersectionIterator &, const CellData &)
Compute single-phase flux through an irregular interface using a mpfa method.
Definition: fv3dpressureadaptive.hh:1141
InteractionVolumeContainer * interactionVolumesContainer_
A pointer to the adaptive interaction volumes container.
Definition: fv3dpressureadaptive.hh:306
void updateMaterialLaws(bool fromPostTimestep=false)
Definition: fv3dpressureadaptive.hh:1294
int maxInteractionVolumes
Maximum number of interaction volumes considered (4 by default)
Definition: fv3dpressureadaptive.hh:303
Interaction volume container for compositional adaptive 3-d (using MPFA L-method) Model.
Definition: fvmpfal3dinteractionvolumecontaineradaptive.hh:46
bool enableVolumeIntegral
Enables the volume integral of the pressure equation.
Definition: fvpressure.hh:184
Problem & problem_
Definition: fvpressure.hh:183
void updateMaterialLaws(bool postTimeStep=false)
Updates secondary variables.
Definition: fvpressurecompositional.hh:706
void update()
Compositional pressure solution routine: update estimate for secants, assemble, solve.
Definition: fvpressurecompositional.hh:130
The finite volume model for the solution of the compositional pressure equation.
Definition: fvpressuremultiphysics.hh:72
void updateMaterialLaws(bool postTimeStep=false)
constitutive functions are updated once if new concentrations are calculated and stored in the variab...
Definition: fvpressuremultiphysics.hh:793
static constexpr int pressureType
gives kind of pressure used ( , , )
Definition: fvpressuremultiphysics.hh:234
typename SolutionTypes::ElementMapper ElementMapper
Definition: fvpressuremultiphysics.hh:226
Class including the information of a 3d interaction volume of an adaptive MPFA L-method that does not...
Definition: linteractionvolume3dadaptive.hh:192
Type of the data container for one interaction volume.
Definition: porousmediumflow/sequential/cellcentered/mpfa/properties.hh:102
Type of the data container for one interaction volume.
Definition: porousmediumflow/sequential/cellcentered/mpfa/properties.hh:104
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
PressureSolution & pressure()
Returns the vector containing the pressure solution.
Definition: sequential/cellcentered/pressure.hh:120
@ rhs
index for the right hand side entry
Definition: sequential/cellcentered/pressure.hh:88
@ matrix
index for the global matrix entry
Definition: sequential/cellcentered/pressure.hh:89
Properties for a MPFA method.