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