diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressure2p.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressure2p.hh index beb3910b8073854adb410518621b1b0e29f85786..8f6f2bad4f7549fceb575a367a08c10e200c1892 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressure2p.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressure2p.hh @@ -22,6 +22,7 @@ #include <dumux/decoupled/common/fv/mpfa/mpfalinteractionvolume.hh> #include <dumux/decoupled/2p/diffusion/diffusionproperties2p.hh> #include <dumux/decoupled/common/fv/mpfa/fvmpfaproperties.hh> +#include "fvmpfal2dtransmissibilitycalculator.hh" /** * @file @@ -136,6 +137,7 @@ public: * */ typedef Dumux::FVMPFALInteractionVolume<TypeTag> InteractionVolume; + typedef Dumux::FvMpfaL2dTransmissibilityCalculator<TypeTag> TransmissibilityCalculator; private: typedef std::vector<InteractionVolume> GlobalInteractionVolumeVector; @@ -396,7 +398,7 @@ public: * \param problem A problem class object */ FvMpfaL2dPressure2p(Problem& problem) : - ParentType(problem), problem_(problem), R_(0), + ParentType(problem), problem_(problem), transmissibilityCalculator_(problem), gravity_(problem.gravity()), maxError_(0.), timeStep_(1.) { @@ -417,13 +419,6 @@ public: DUNE_THROW(Dune::NotImplemented, "Dimension not supported!"); } - // evaluate matrix R - if (dim == 2) - { - R_[0][1] = 1; - R_[1][0] = -1; - } - ErrorTermFactor_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Impet, ErrorTermFactor); ErrorTermLowerBound_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Impet, ErrorTermLowerBound); ErrorTermUpperBound_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Impet, ErrorTermUpperBound); @@ -438,17 +433,10 @@ public: private: Problem& problem_; - DimMatrix R_; + TransmissibilityCalculator transmissibilityCalculator_; protected: - // Calculates tranmissibility matrix - bool calculateTransmissibility( - Dune::FieldMatrix<Scalar,dim,2*dim-dim+1>& transmissibility, - InteractionVolume& interactionVolume, - std::vector<DimVector >& lambda, - int idx1, int idx2, int idx3, int idx4); - GlobalInteractionVolumeVector interactionVolumes_;//!< Global Vector of interaction volumes InnerBoundaryVolumeFaces innerBoundaryVolumeFaces_; //!< Vector marking faces which intersect the boundary @@ -1472,9 +1460,9 @@ void FvMpfaL2dPressure2p<TypeTag>::assemble() Dune::FieldVector<Scalar, 2 * dim - dim + 1> u(0); Dune::FieldMatrix<Scalar,dim,2*dim-dim+1> T(0); - bool rightTriangle = calculateTransmissibility(T, interactionVolume, lambda, 0, 1, 2, 3); + int lType = transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 0, 1, 2, 3); - if (rightTriangle) + if (lType == TransmissibilityCalculator::rightTriangle) { if (innerBoundaryVolumeFaces_[globalIdx1][interactionVolume.getIndexOnElement(0, 0)]) { @@ -1521,9 +1509,9 @@ void FvMpfaL2dPressure2p<TypeTag>::assemble() pcPotential12 = Tu[1]; } - rightTriangle = calculateTransmissibility(T, interactionVolume, lambda, 1, 2, 3, 0); + lType = transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 1, 2, 3, 0); - if (rightTriangle) + if (lType == TransmissibilityCalculator::rightTriangle) { if (innerBoundaryVolumeFaces_[globalIdx2][interactionVolume.getIndexOnElement(1, 0)]) { @@ -1570,9 +1558,9 @@ void FvMpfaL2dPressure2p<TypeTag>::assemble() pcPotential32 = -Tu[1]; } - rightTriangle = calculateTransmissibility(T, interactionVolume, lambda, 2, 3, 0, 1); + lType = transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 2, 3, 0, 1); - if (rightTriangle) + if (lType == TransmissibilityCalculator::rightTriangle) { if (innerBoundaryVolumeFaces_[globalIdx3][interactionVolume.getIndexOnElement(2, 0)]) { @@ -1619,9 +1607,9 @@ void FvMpfaL2dPressure2p<TypeTag>::assemble() pcPotential34 = Tu[1]; } - rightTriangle = calculateTransmissibility(T, interactionVolume, lambda, 3, 0, 1, 2); + lType = transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 3, 0, 1, 2); - if (rightTriangle) + if (lType == TransmissibilityCalculator::rightTriangle) { if (innerBoundaryVolumeFaces_[globalIdx4][interactionVolume.getIndexOnElement(3, 0)]) { @@ -2006,318 +1994,6 @@ void FvMpfaL2dPressure2p<TypeTag>::assemble() return; } -/*! \brief Calculates tranmissibility matrix - * - * Calculates tranmissibility matrix of an L-shape for a certain flux face. - * Automatically selects one of the two possible L-shape (left, or right). - * - * \param transmissibility Matrix for the resulting transmissibility - * \param interactionVolume The interaction volume object (includes geometric information) - * \param lambda Mobilities of cells 1-4 - * \param idx1 Index of cell 1 of the L-stencil - * \param idx2 Index of cell 2 of the L-stencil - * \param idx3 Index of cell 3 of the L-stencil - * \param idx4 Index of cell 4 of the L-stencil - */ -template<class TypeTag> -bool FvMpfaL2dPressure2p<TypeTag>::calculateTransmissibility( - Dune::FieldMatrix<Scalar,dim,2*dim-dim+1>& transmissibility, - InteractionVolume& interactionVolume, - std::vector<DimVector >& lambda, - int idx1, int idx2, int idx3, int idx4) -{ - ElementPointer& elementPointer1 = interactionVolume.getSubVolumeElement(idx1); - ElementPointer& elementPointer2 = interactionVolume.getSubVolumeElement(idx2); - ElementPointer& elementPointer3 = interactionVolume.getSubVolumeElement(idx3); - ElementPointer& elementPointer4 = interactionVolume.getSubVolumeElement(idx4); - - // get global coordinate of cell centers - const GlobalPosition& globalPos1 = elementPointer1->geometry().center(); - const GlobalPosition& globalPos2 = elementPointer2->geometry().center(); - const GlobalPosition& globalPos3 = elementPointer3->geometry().center(); - const GlobalPosition& globalPos4 = elementPointer4->geometry().center(); - - const GlobalPosition& globalPosCenter = interactionVolume.getCenterPosition(); - - const DimMatrix& K1 = problem_.spatialParams().intrinsicPermeability(*elementPointer1); - const DimMatrix& K2 = problem_.spatialParams().intrinsicPermeability(*elementPointer2); - const DimMatrix& K3 = problem_.spatialParams().intrinsicPermeability(*elementPointer3); - const DimMatrix& K4 = problem_.spatialParams().intrinsicPermeability(*elementPointer4); - - const GlobalPosition& globalPosFace12 = interactionVolume.getFacePosition(idx1,0); - const GlobalPosition& globalPosFace23 = interactionVolume.getFacePosition(idx2,0); - - // compute normal vectors nu1-nu7 in triangle R for first half edge - DimVector nu1R1(0); - R_.mv(globalPosFace12-globalPos2 ,nu1R1); - - DimVector nu2R1(0); - R_.mv(globalPos2-globalPosFace23, nu2R1); - - DimVector nu3R1(0); - R_.mv(globalPosFace23-globalPos3, nu3R1); - - DimVector nu4R1(0); - R_.mv(globalPos3-globalPosCenter, nu4R1); - - DimVector nu5R1(0); - R_.mv(globalPosCenter-globalPos1, nu5R1); - - DimVector nu6R1(0); - R_.mv(globalPos1-globalPosFace12, nu6R1); - - DimVector nu7R1(0); - R_.mv(globalPosCenter-globalPos2, nu7R1); - - // compute T, i.e., the area of quadrilateral made by normal vectors 'nu' - DimVector Rnu2R1(0); - R_.mv(nu2R1, Rnu2R1); - Scalar T1R1 = nu1R1 * Rnu2R1; - - DimVector Rnu4R1(0); - R_.mv(nu4R1, Rnu4R1); - Scalar T2R1 = nu3R1 * Rnu4R1; - - DimVector Rnu6R1(0); - R_.mv(nu6R1, Rnu6R1); - Scalar T3R1 = nu5R1 * Rnu6R1; - - // compute components needed for flux calculation, denoted as 'omega' and 'chi' - DimVector K2nu1R1(0); - K2.mv(nu1R1, K2nu1R1); - DimVector K2nu2R1(0); - K2.mv(nu2R1, K2nu2R1); - DimVector K4nu3R1(0); - K3.mv(nu3R1, K4nu3R1); - DimVector K4nu4R1(0); - K3.mv(nu4R1, K4nu4R1); - DimVector K1nu5R1(0); - K1.mv(nu5R1, K1nu5R1); - DimVector K1nu6R1(0); - K1.mv(nu6R1, K1nu6R1); - - DimVector Rnu1R1(0); - R_.mv(nu1R1, Rnu1R1); - - DimVector &outerNormaln1R1 = interactionVolume.getNormal(idx2, 0); - DimVector &outerNormaln2 = interactionVolume.getNormal(idx1, 0); - -// std::cout<<"outerNormaln1R1 = "<<outerNormaln1R1<<"\n"; -// std::cout<<"outerNormaln2 = "<<outerNormaln2<<"\n"; - - Scalar omega111R1 = lambda[idx2][0] * (outerNormaln1R1 * K2nu1R1) * interactionVolume.getFaceArea(idx2, 0)/T1R1; - Scalar omega112R1 = lambda[idx2][0] * (outerNormaln1R1 * K2nu2R1) * interactionVolume.getFaceArea(idx2, 0)/T1R1; - Scalar omega211R1 = lambda[idx2][1] * (outerNormaln2 * K2nu1R1) * interactionVolume.getFaceArea(idx2, 1)/T1R1; - Scalar omega212R1 = lambda[idx2][1] * (outerNormaln2 * K2nu2R1) * interactionVolume.getFaceArea(idx2, 1)/T1R1; - Scalar omega123R1 = lambda[idx3][1] * (outerNormaln1R1 * K4nu3R1) * interactionVolume.getFaceArea(idx3, 1)/T2R1; - Scalar omega124R1 = lambda[idx3][1] * (outerNormaln1R1 * K4nu4R1) * interactionVolume.getFaceArea(idx3, 1)/T2R1; - Scalar omega235R1 = lambda[idx1][0] * (outerNormaln2 * K1nu5R1) * interactionVolume.getFaceArea(idx1, 0)/T3R1; - Scalar omega236R1 = lambda[idx1][0] * (outerNormaln2 * K1nu6R1) * interactionVolume.getFaceArea(idx1, 0)/T3R1; - Scalar chi711R1 = (nu7R1 * Rnu1R1)/T1R1; - Scalar chi712R1 = (nu7R1 * Rnu2R1)/T1R1; - - // compute transmissibility matrix TR1 = CA^{-1}B+D - DimMatrix C(0), A(0); - Dune::FieldMatrix<Scalar,dim,2*dim-dim+1> D(0), B(0); - - // evaluate matrix C, D, A, B - C[0][0] = -omega111R1; - C[0][1] = -omega112R1; - C[1][0] = -omega211R1; - C[1][1] = -omega212R1; - - D[0][0] = omega111R1 + omega112R1; - D[1][0] = omega211R1 + omega212R1; - - A[0][0] = omega111R1 - omega124R1 - omega123R1*chi711R1; - A[0][1] = omega112R1 - omega123R1*chi712R1; - A[1][0] = omega211R1 - omega236R1*chi711R1; - A[1][1] = omega212R1 - omega235R1 - omega236R1*chi712R1; - - B[0][0] = omega111R1 + omega112R1 + omega123R1*(1.0 - chi711R1 - chi712R1); - B[0][1] = -omega123R1 - omega124R1; - B[1][0] = omega211R1 + omega212R1 + omega236R1*(1.0 - chi711R1 - chi712R1); - B[1][2] = -omega235R1 - omega236R1; - -// std::cout<<"AR = "<<A<<"\n"; - - // compute TR1 - A.invert(); - D += B.leftmultiply(C.rightmultiply(A)); - Dune::FieldMatrix<Scalar,dim,2*dim-dim+1> TR1(D); - - - // 2.use triangle L to compute the transmissibility of half edge - const GlobalPosition& globalPosFace14 = interactionVolume.getFacePosition(idx1,1); - -// std::cout<<"globalPosFace14 = "<<globalPosFace14<<"\n"; - - // compute normal vectors nu1-nu7 in triangle L for first half edge - DimVector nu1L1(0); - R_.mv(globalPosFace12-globalPos1 ,nu1L1); - - DimVector nu2L1(0); - R_.mv(globalPos1-globalPosFace14, nu2L1); - - DimVector nu3L1(0); - R_.mv(globalPosFace14-globalPos4, nu3L1); - - DimVector nu4L1(0); - R_.mv(globalPos4-globalPosCenter, nu4L1); - - DimVector nu5L1(0); - R_.mv(globalPosCenter-globalPos2, nu5L1); - - DimVector nu6L1(0); - R_.mv(globalPos2-globalPosFace12, nu6L1); - - DimVector nu7L1(0); - R_.mv(globalPosCenter-globalPos1, nu7L1); - - // compute T, i.e., the area of quadrilateral made by normal vectors 'nu' - DimVector Rnu2L1(0); - R_.mv(nu2L1, Rnu2L1); - Scalar T1L1 = nu1L1 * Rnu2L1; - - DimVector Rnu4L1(0); - R_.mv(nu4L1, Rnu4L1); - Scalar T2L1 = nu3L1 * Rnu4L1; - - DimVector Rnu6L1(0); - R_.mv(nu6L1, Rnu6L1); - Scalar T3L1 = nu5L1 * Rnu6L1; - - // compute components needed for flux calculation, denoted as 'omega' and 'chi' - DimVector K1nu1L1(0); - K1.mv(nu1L1, K1nu1L1); - DimVector K1nu2L1(0); - K1.mv(nu2L1, K1nu2L1); - DimVector K3nu3L1(0); - K4.mv(nu3L1, K3nu3L1); - DimVector K3nu4L1(0); - K4.mv(nu4L1, K3nu4L1); - DimVector K2nu5L1(0); - K2.mv(nu5L1, K2nu5L1); - DimVector K2nu6L1(0); - K2.mv(nu6L1, K2nu6L1); - - DimVector Rnu1L1(0); - R_.mv(nu1L1, Rnu1L1); - - DimVector &outerNormaln1L1 = interactionVolume.getNormal(idx1, 1); -// std::cout<<"outerNormaln1L1 = "<<outerNormaln1L1<<"\n"; - - Scalar omega111L1 = lambda[idx1][1] * (outerNormaln1L1 * K1nu1L1)* interactionVolume.getFaceArea(idx1, 1)/T1L1; - Scalar omega112L1 = lambda[idx1][1] * (outerNormaln1L1 * K1nu2L1)* interactionVolume.getFaceArea(idx1, 1)/T1L1; - Scalar omega211L1 = lambda[idx1][0] * (outerNormaln2 * K1nu1L1)* interactionVolume.getFaceArea(idx1, 0)/T1L1; - Scalar omega212L1 = lambda[idx1][0] * (outerNormaln2 * K1nu2L1)* interactionVolume.getFaceArea(idx1, 0)/T1L1; - Scalar omega123L1 = lambda[idx4][0] * (outerNormaln1L1 * K3nu3L1)* interactionVolume.getFaceArea(idx4, 0)/T2L1; - Scalar omega124L1 = lambda[idx4][0] * (outerNormaln1L1 * K3nu4L1)* interactionVolume.getFaceArea(idx4, 0)/T2L1; - Scalar omega235L1 = lambda[idx2][1] * (outerNormaln2 * K2nu5L1)* interactionVolume.getFaceArea(idx2, 1)/T3L1; - Scalar omega236L1 = lambda[idx2][1] * (outerNormaln2 * K2nu6L1)* interactionVolume.getFaceArea(idx2, 1)/T3L1; - Scalar chi711L1 = (nu7L1 * Rnu1L1)/T1L1; - Scalar chi712L1 = (nu7L1 * Rnu2L1)/T1L1; - - // compute transmissibility matrix TL1 = CA^{-1}B+D - C = 0; - A = 0; - D = 0; - B = 0; - - // evaluate matrix C, D, A, B - C[0][0] = -omega111L1; - C[0][1] = -omega112L1; - C[1][0] = -omega211L1; - C[1][1] = -omega212L1; - - D[0][0] = omega111L1 + omega112L1; - D[1][0] = omega211L1 + omega212L1; - - A[0][0] = omega111L1 - omega124L1 - omega123L1*chi711L1; - A[0][1] = omega112L1 - omega123L1*chi712L1; - A[1][0] = omega211L1 - omega236L1*chi711L1; - A[1][1] = omega212L1 - omega235L1 - omega236L1*chi712L1; - - B[0][0] = omega111L1 + omega112L1 + omega123L1*(1.0 - chi711L1 - chi712L1); - B[0][1] = -omega123L1 - omega124L1; - B[1][0] = omega211L1 + omega212L1 + omega236L1*(1.0 - chi711L1 - chi712L1); - B[1][2] = -omega235L1 - omega236L1; - -// std::cout<<"AL = "<<A<<"\n"; - - // compute TL1 - A.invert(); - D += B.leftmultiply(C.rightmultiply(A)); - Dune::FieldMatrix<Scalar,dim,2*dim-dim+1> TL1(D); - - Scalar sR = std::abs(TR1[1][2] - TR1[1][0]); - Scalar sL = std::abs(TL1[1][0] - TL1[1][2]); - - // 3.decide which triangle (which transmissibility coefficients) to use - if (sR <= sL) - { - transmissibility = TR1; -// if (std::isnan(transmissibility.frobenius_norm())) -// { -// std::cout<<"right transmissibility = "<<transmissibility<<"\n"; -// std::cout<<"globalPos1 = "<<globalPos1<<"\n"; -// std::cout<<"globalPos2 = "<<globalPos2<<"\n"; -// std::cout<<"globalPos3 = "<<globalPos3<<"\n"; -// std::cout<<"globalPos4 = "<<globalPos4<<"\n"; -// std::cout<<"globalPosCenter = "<<globalPosCenter<<"\n"; -// std::cout<<"outerNormaln1L1 = "<<outerNormaln1L1<<"\n"; -// std::cout<<"globalPosFace14 = "<<globalPosFace14<<"\n"; -// std::cout<<"outerNormaln1R1 = "<<outerNormaln1R1<<"\n"; -// std::cout<<"outerNormaln2 = "<<outerNormaln2<<"\n"; -// std::cout<<"globalPosFace12 = "<<globalPosFace12<<"\n"; -// std::cout<<"globalPosFace23 = "<<globalPosFace23<<"\n"; -// std::cout<<"perm1 = "<<K1<<"\n"; -// std::cout<<"perm2 = "<<K2<<"\n"; -// std::cout<<"perm3 = "<<K3<<"\n"; -// std::cout<<"perm4 = "<<K4<<"\n"; -// std::cout<<"lambda = "; -// for (int i = 0; i < lambda.size(); i++) -// { -// std::cout<<lambda[i]<<" "; -// } -// std::cout<<"\n"; -// } -// std::cout<<"transmissibility = "<<transmissibility<<"\n"; - return true; - } - else - { - transmissibility = TL1; -// if (std::isnan(transmissibility.frobenius_norm())) -// { -// std::cout<<"left transmissibility = "<<transmissibility<<"\n"; -// std::cout<<"globalPos1 = "<<globalPos1<<"\n"; -// std::cout<<"globalPos2 = "<<globalPos2<<"\n"; -// std::cout<<"globalPos3 = "<<globalPos3<<"\n"; -// std::cout<<"globalPos4 = "<<globalPos4<<"\n"; -// std::cout<<"globalPosCenter = "<<globalPosCenter<<"\n"; -// std::cout<<"outerNormaln1L1 = "<<outerNormaln1L1<<"\n"; -// std::cout<<"globalPosFace14 = "<<globalPosFace14<<"\n"; -// std::cout<<"outerNormaln1R1 = "<<outerNormaln1R1<<"\n"; -// std::cout<<"outerNormaln2 = "<<outerNormaln2<<"\n"; -// std::cout<<"globalPosFace12 = "<<globalPosFace12<<"\n"; -// std::cout<<"globalPosFace23 = "<<globalPosFace23<<"\n"; -// std::cout<<"perm1 = "<<K1<<"\n"; -// std::cout<<"perm2 = "<<K2<<"\n"; -// std::cout<<"perm3 = "<<K3<<"\n"; -// std::cout<<"perm4 = "<<K4<<"\n"; -// std::cout<<"lambda = "; -// for (int i = 0; i < lambda.size(); i++) -// { -// std::cout<<lambda[i]<<" "; -// } -// std::cout<<"\n"; -// } -// std::cout<<"left transmissibility = "<<transmissibility<<"\n"; - return false; - } -} - /*! \brief Updates constitutive relations and stores them in the variable class * * Stores mobility, fractional flow function and capillary pressure for all grid cells. diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressure2padaptive.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressure2padaptive.hh index 26ea43072ed6de874f108fe4cb90ce472d7133e5..4bf579f4cb8783ee162ef169e1b1d315e93b86a6 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressure2padaptive.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressure2padaptive.hh @@ -22,6 +22,7 @@ #include <dumux/decoupled/common/fv/mpfa/mpfalinteractionvolume.hh> #include <dumux/decoupled/2p/diffusion/diffusionproperties2p.hh> #include <dumux/decoupled/common/fv/mpfa/fvmpfaproperties.hh> +#include "fvmpfal2dtransmissibilitycalculator.hh" /** * @file @@ -136,12 +137,7 @@ class FvMpfaL2dPressure2pAdaptive: public FVPressure<TypeTag> typedef Dune::FieldVector<Scalar, dim> DimVector; public: - enum - { - leftTriangle = -1, - noTransmissibility = 0, - rightTriangle = 1 - }; + /*! \brief Type of the interaction volume objects * @@ -150,6 +146,7 @@ public: * */ typedef Dumux::FVMPFALInteractionVolume<TypeTag> InteractionVolume; + typedef Dumux::FvMpfaL2dTransmissibilityCalculator<TypeTag> TransmissibilityCalculator; private: typedef std::vector<InteractionVolume> GlobalInteractionVolumeVector; @@ -437,7 +434,7 @@ public: * \param problem A problem class object */ FvMpfaL2dPressure2pAdaptive(Problem& problem) : - ParentType(problem), problem_(problem), R_(0), + ParentType(problem), problem_(problem), transmissibilityCalculator_(problem), gravity_(problem.gravity()), maxError_(0.), timeStep_(1.) { @@ -464,13 +461,6 @@ public: DUNE_THROW(Dune::NotImplemented, "Dimension not supported!"); } - // evaluate matrix R - if (dim == 2) - { - R_[0][1] = 1; - R_[1][0] = -1; - } - ErrorTermFactor_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Impet, ErrorTermFactor); ErrorTermLowerBound_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Impet, ErrorTermLowerBound); ErrorTermUpperBound_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Impet, ErrorTermUpperBound); @@ -485,26 +475,7 @@ public: private: Problem& problem_; - DimMatrix R_; - -public: - // Calculates tranmissibility matrix - int calculateTransmissibility(Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1>& transmissibility, - InteractionVolume& interactionVolume, - std::vector<DimVector >& lambda, - int idx1, int idx2, int idx3, int idx4); - - // Calculates tranmissibility matrix of left L-shape - int calculateLeftHNTransmissibility(Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1>& transmissibility, - InteractionVolume& interactionVolume, - std::vector<DimVector >& lambda, - int idx1, int idx2, int idx3); - - // Calculates tranmissibility matrix of right L-shape - int calculateRightHNTransmissibility(Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1>& transmissibility, - InteractionVolume& interactionVolume, - std::vector<DimVector >& lambda, - int idx1, int idx2, int idx3); + TransmissibilityCalculator transmissibilityCalculator_; protected: GlobalInteractionVolumeVector interactionVolumes_;//!< Global Vector of interaction volumes @@ -2021,9 +1992,9 @@ void FvMpfaL2dPressure2pAdaptive<TypeTag>::assemble() Dune::FieldVector<Scalar, 2 * dim - dim + 1> u(0); Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> T(0); - int transmissibilityType = calculateTransmissibility(T, interactionVolume, lambda, 0, 1, 2, 3); + int transmissibilityType = transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 0, 1, 2, 3); - if (transmissibilityType == rightTriangle) + if (transmissibilityType == TransmissibilityCalculator::rightTriangle) { if (innerBoundaryVolumeFaces_[globalIdx1][interactionVolume.getIndexOnElement(0, 0)]) { @@ -2046,7 +2017,7 @@ void FvMpfaL2dPressure2pAdaptive<TypeTag>::assemble() pcFlux[0] = Tu[1]; pcPotential12 = Tu[1]; } - else if (transmissibilityType == leftTriangle) + else if (transmissibilityType == TransmissibilityCalculator::leftTriangle) { if (innerBoundaryVolumeFaces_[globalIdx1][interactionVolume.getIndexOnElement(0, 0)]) { @@ -2070,9 +2041,9 @@ void FvMpfaL2dPressure2pAdaptive<TypeTag>::assemble() pcPotential12 = Tu[1]; } - transmissibilityType = calculateTransmissibility(T, interactionVolume, lambda, 1, 2, 3, 0); + transmissibilityType = transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 1, 2, 3, 0); - if (transmissibilityType == rightTriangle) + if (transmissibilityType == TransmissibilityCalculator::rightTriangle) { if (innerBoundaryVolumeFaces_[globalIdx2][interactionVolume.getIndexOnElement(1, 0)]) { @@ -2095,7 +2066,7 @@ void FvMpfaL2dPressure2pAdaptive<TypeTag>::assemble() pcFlux[1] = Tu[1]; pcPotential32 = -Tu[1]; } - else if (transmissibilityType == leftTriangle) + else if (transmissibilityType == TransmissibilityCalculator::leftTriangle) { if (innerBoundaryVolumeFaces_[globalIdx2][interactionVolume.getIndexOnElement(1, 0)]) { @@ -2119,9 +2090,9 @@ void FvMpfaL2dPressure2pAdaptive<TypeTag>::assemble() pcPotential32 = -Tu[1]; } - transmissibilityType = calculateTransmissibility(T, interactionVolume, lambda, 2, 3, 0, 1); + transmissibilityType = transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 2, 3, 0, 1); - if (transmissibilityType == rightTriangle) + if (transmissibilityType == TransmissibilityCalculator::rightTriangle) { if (innerBoundaryVolumeFaces_[globalIdx3][interactionVolume.getIndexOnElement(2, 0)]) { @@ -2144,7 +2115,7 @@ void FvMpfaL2dPressure2pAdaptive<TypeTag>::assemble() pcFlux[2] = Tu[1]; pcPotential34 = Tu[1]; } - else if (transmissibilityType == leftTriangle) + else if (transmissibilityType == TransmissibilityCalculator::leftTriangle) { if (innerBoundaryVolumeFaces_[globalIdx3][interactionVolume.getIndexOnElement(2, 0)]) { @@ -2168,9 +2139,9 @@ void FvMpfaL2dPressure2pAdaptive<TypeTag>::assemble() pcPotential34 = Tu[1]; } - transmissibilityType = calculateTransmissibility(T, interactionVolume, lambda, 3, 0, 1, 2); + transmissibilityType = transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 3, 0, 1, 2); - if (transmissibilityType == rightTriangle) + if (transmissibilityType == TransmissibilityCalculator::rightTriangle) { if (innerBoundaryVolumeFaces_[globalIdx4][interactionVolume.getIndexOnElement(3, 0)]) { @@ -2193,7 +2164,7 @@ void FvMpfaL2dPressure2pAdaptive<TypeTag>::assemble() pcFlux[3] = Tu[1]; pcPotential14 = -Tu[1]; } - else if (transmissibilityType == leftTriangle) + else if (transmissibilityType == TransmissibilityCalculator::leftTriangle) { if (innerBoundaryVolumeFaces_[globalIdx4][interactionVolume.getIndexOnElement(3, 0)]) { @@ -2381,9 +2352,9 @@ void FvMpfaL2dPressure2pAdaptive<TypeTag>::assemble() Dune::FieldVector<Scalar, 2 * dim - dim + 1> u(0); Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> T(0); - int transmissibilityType = calculateTransmissibility(T, interactionVolume, lambda, 0, 1, 3, 3); + int transmissibilityType = transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 0, 1, 3, 3); - if (transmissibilityType == rightTriangle) + if (transmissibilityType == TransmissibilityCalculator::rightTriangle) { if (innerBoundaryVolumeFaces_[globalIdx1][interactionVolume.getIndexOnElement(0, 0)]) { @@ -2406,7 +2377,7 @@ void FvMpfaL2dPressure2pAdaptive<TypeTag>::assemble() pcFlux[0] = Tu[1]; pcPotential12 = Tu[1]; } - else if (transmissibilityType == leftTriangle) + else if (transmissibilityType == TransmissibilityCalculator::leftTriangle) { if (innerBoundaryVolumeFaces_[globalIdx1][interactionVolume.getIndexOnElement(0, 0)]) { @@ -2434,9 +2405,9 @@ void FvMpfaL2dPressure2pAdaptive<TypeTag>::assemble() DUNE_THROW(Dune::RangeError, "Could not calculate Tranmissibility!"); } - transmissibilityType = calculateLeftHNTransmissibility(T, interactionVolume, lambda, 1, 3, 0); + transmissibilityType = transmissibilityCalculator_.calculateLeftHNTransmissibility(T, interactionVolume, lambda, 1, 3, 0); - if (transmissibilityType == leftTriangle) + if (transmissibilityType == TransmissibilityCalculator::leftTriangle) { if (innerBoundaryVolumeFaces_[globalIdx2][interactionVolume.getIndexOnElement(1, 0)]) { @@ -2464,9 +2435,9 @@ void FvMpfaL2dPressure2pAdaptive<TypeTag>::assemble() DUNE_THROW(Dune::RangeError, "Could not calculate Tranmissibility!"); } - transmissibilityType = calculateRightHNTransmissibility(T, interactionVolume, lambda, 3, 0, 1); + transmissibilityType = transmissibilityCalculator_.calculateRightHNTransmissibility(T, interactionVolume, lambda, 3, 0, 1); - if (transmissibilityType == rightTriangle) + if (transmissibilityType == TransmissibilityCalculator::rightTriangle) { if (innerBoundaryVolumeFaces_[globalIdx1][interactionVolume.getIndexOnElement(0, 1)]) { @@ -2824,550 +2795,6 @@ void FvMpfaL2dPressure2pAdaptive<TypeTag>::assemble() return; } -/*! \brief Calculates tranmissibility matrix - * - * Calculates tranmissibility matrix of an L-shape for a certain flux face. - * Automatically selects one of the two possible L-shape (left, or right). - * - * \param transmissibility Matrix for the resulting transmissibility - * \param interactionVolume The interaction volume object (includes geometric information) - * \param lambda Mobilities of cells 1-4 - * \param idx1 Index of cell 1 of the L-stencil - * \param idx2 Index of cell 2 of the L-stencil - * \param idx3 Index of cell 3 of the L-stencil - * \param idx4 Index of cell 4 of the L-stencil - */ -template<class TypeTag> -int FvMpfaL2dPressure2pAdaptive<TypeTag>::calculateTransmissibility( - Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1>& transmissibility, - InteractionVolume& interactionVolume, - std::vector<DimVector >& lambda, - int idx1, int idx2, int idx3, int idx4) -{ - ElementPointer& elementPointer1 = interactionVolume.getSubVolumeElement(idx1); - ElementPointer& elementPointer2 = interactionVolume.getSubVolumeElement(idx2); - ElementPointer& elementPointer3 = interactionVolume.getSubVolumeElement(idx3); - ElementPointer& elementPointer4 = interactionVolume.getSubVolumeElement(idx4); - - if (elementPointer3 == elementPointer4 && elementPointer1->level() != elementPointer2->level()) - { - return noTransmissibility; - } - - // get global coordinate of cell centers - const GlobalPosition& globalPos1 = elementPointer1->geometry().center(); - const GlobalPosition& globalPos2 = elementPointer2->geometry().center(); - const GlobalPosition& globalPos3 = elementPointer3->geometry().center(); - const GlobalPosition& globalPos4 = elementPointer4->geometry().center(); - - const GlobalPosition& globalPosCenter = interactionVolume.getCenterPosition(); - - const DimMatrix& K1 = problem_.spatialParams().intrinsicPermeability(*elementPointer1); - const DimMatrix& K2 = problem_.spatialParams().intrinsicPermeability(*elementPointer2); - const DimMatrix& K3 = problem_.spatialParams().intrinsicPermeability(*elementPointer3); - const DimMatrix& K4 = problem_.spatialParams().intrinsicPermeability(*elementPointer4); - - const GlobalPosition& globalPosFace12 = interactionVolume.getFacePosition(idx1, 0); - const GlobalPosition& globalPosFace23 = interactionVolume.getFacePosition(idx2, 0); - - // compute normal vectors nu1-nu7 in triangle R for first half edge - DimVector nu1R1(0); - R_.mv(globalPosFace12 - globalPos2, nu1R1); - - DimVector nu2R1(0); - R_.mv(globalPos2 - globalPosFace23, nu2R1); - - DimVector nu3R1(0); - R_.mv(globalPosFace23 - globalPos3, nu3R1); - - DimVector nu4R1(0); - R_.mv(globalPos3 - globalPosCenter, nu4R1); - - DimVector nu5R1(0); - R_.mv(globalPosCenter - globalPos1, nu5R1); - - DimVector nu6R1(0); - R_.mv(globalPos1 - globalPosFace12, nu6R1); - - DimVector nu7R1(0); - R_.mv(globalPosCenter - globalPos2, nu7R1); - - // compute T, i.e., the area of quadrilateral made by normal vectors 'nu' - DimVector Rnu2R1(0); - R_.mv(nu2R1, Rnu2R1); - Scalar T1R1 = nu1R1 * Rnu2R1; - - DimVector Rnu4R1(0); - R_.mv(nu4R1, Rnu4R1); - Scalar T2R1 = nu3R1 * Rnu4R1; - - DimVector Rnu6R1(0); - R_.mv(nu6R1, Rnu6R1); - Scalar T3R1 = nu5R1 * Rnu6R1; - - // compute components needed for flux calculation, denoted as 'omega' and 'chi' - DimVector K2nu1R1(0); - K2.mv(nu1R1, K2nu1R1); - DimVector K2nu2R1(0); - K2.mv(nu2R1, K2nu2R1); - DimVector K4nu3R1(0); - K3.mv(nu3R1, K4nu3R1); - DimVector K4nu4R1(0); - K3.mv(nu4R1, K4nu4R1); - DimVector K1nu5R1(0); - K1.mv(nu5R1, K1nu5R1); - DimVector K1nu6R1(0); - K1.mv(nu6R1, K1nu6R1); - - DimVector Rnu1R1(0); - R_.mv(nu1R1, Rnu1R1); - - DimVector &outerNormaln1R1 = interactionVolume.getNormal(idx2, 0); - DimVector &outerNormaln2 = interactionVolume.getNormal(idx1, 0); - - Scalar omega111R1 = lambda[idx2][0] * (outerNormaln1R1 * K2nu1R1) * interactionVolume.getFaceArea(idx2, 0) / T1R1; - Scalar omega112R1 = lambda[idx2][0] * (outerNormaln1R1 * K2nu2R1) * interactionVolume.getFaceArea(idx2, 0) / T1R1; - Scalar omega211R1 = lambda[idx2][1] * (outerNormaln2 * K2nu1R1) * interactionVolume.getFaceArea(idx2, 1) / T1R1; - Scalar omega212R1 = lambda[idx2][1] * (outerNormaln2 * K2nu2R1) * interactionVolume.getFaceArea(idx2, 1) / T1R1; - Scalar omega123R1 = lambda[idx3][1] * (outerNormaln1R1 * K4nu3R1) * interactionVolume.getFaceArea(idx3, 1) / T2R1; - Scalar omega124R1 = lambda[idx3][1] * (outerNormaln1R1 * K4nu4R1) * interactionVolume.getFaceArea(idx3, 1) / T2R1; - Scalar omega235R1 = lambda[idx1][0] * (outerNormaln2 * K1nu5R1) * interactionVolume.getFaceArea(idx1, 0) / T3R1; - Scalar omega236R1 = lambda[idx1][0] * (outerNormaln2 * K1nu6R1) * interactionVolume.getFaceArea(idx1, 0) / T3R1; - Scalar chi711R1 = (nu7R1 * Rnu1R1) / T1R1; - Scalar chi712R1 = (nu7R1 * Rnu2R1) / T1R1; - - // compute transmissibility matrix TR1 = CA^{-1}B+D - DimMatrix C(0), A(0); - Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> D(0), B(0); - - // evaluate matrix C, D, A, B - C[0][0] = -omega111R1; - C[0][1] = -omega112R1; - C[1][0] = -omega211R1; - C[1][1] = -omega212R1; - - D[0][0] = omega111R1 + omega112R1; - D[1][0] = omega211R1 + omega212R1; - - A[0][0] = omega111R1 - omega124R1 - omega123R1 * chi711R1; - A[0][1] = omega112R1 - omega123R1 * chi712R1; - A[1][0] = omega211R1 - omega236R1 * chi711R1; - A[1][1] = omega212R1 - omega235R1 - omega236R1 * chi712R1; - - B[0][0] = omega111R1 + omega112R1 + omega123R1 * (1.0 - chi711R1 - chi712R1); - B[0][1] = -omega123R1 - omega124R1; - B[1][0] = omega211R1 + omega212R1 + omega236R1 * (1.0 - chi711R1 - chi712R1); - B[1][2] = -omega235R1 - omega236R1; - - // compute TR1 - A.invert(); - D += B.leftmultiply(C.rightmultiply(A)); - Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> TR1(D); - - // 2.use triangle L to compute the transmissibility of half edge - const GlobalPosition& globalPosFace14 = interactionVolume.getFacePosition(idx1, 1); - - // compute normal vectors nu1-nu7 in triangle L for first half edge - DimVector nu1L1(0); - R_.mv(globalPosFace12 - globalPos1, nu1L1); - - DimVector nu2L1(0); - R_.mv(globalPos1 - globalPosFace14, nu2L1); - - DimVector nu3L1(0); - R_.mv(globalPosFace14 - globalPos4, nu3L1); - - DimVector nu4L1(0); - R_.mv(globalPos4 - globalPosCenter, nu4L1); - - DimVector nu5L1(0); - R_.mv(globalPosCenter - globalPos2, nu5L1); - - DimVector nu6L1(0); - R_.mv(globalPos2 - globalPosFace12, nu6L1); - - DimVector nu7L1(0); - R_.mv(globalPosCenter - globalPos1, nu7L1); - - // compute T, i.e., the area of quadrilateral made by normal vectors 'nu' - DimVector Rnu2L1(0); - R_.mv(nu2L1, Rnu2L1); - Scalar T1L1 = nu1L1 * Rnu2L1; - - DimVector Rnu4L1(0); - R_.mv(nu4L1, Rnu4L1); - Scalar T2L1 = nu3L1 * Rnu4L1; - - DimVector Rnu6L1(0); - R_.mv(nu6L1, Rnu6L1); - Scalar T3L1 = nu5L1 * Rnu6L1; - - // compute components needed for flux calculation, denoted as 'omega' and 'chi' - DimVector K1nu1L1(0); - K1.mv(nu1L1, K1nu1L1); - DimVector K1nu2L1(0); - K1.mv(nu2L1, K1nu2L1); - DimVector K3nu3L1(0); - K4.mv(nu3L1, K3nu3L1); - DimVector K3nu4L1(0); - K4.mv(nu4L1, K3nu4L1); - DimVector K2nu5L1(0); - K2.mv(nu5L1, K2nu5L1); - DimVector K2nu6L1(0); - K2.mv(nu6L1, K2nu6L1); - - DimVector Rnu1L1(0); - R_.mv(nu1L1, Rnu1L1); - - DimVector &outerNormaln1L1 = interactionVolume.getNormal(idx1, 1); - - Scalar omega111L1 = lambda[idx1][1] * (outerNormaln1L1 * K1nu1L1) * interactionVolume.getFaceArea(idx1, 1) / T1L1; - Scalar omega112L1 = lambda[idx1][1] * (outerNormaln1L1 * K1nu2L1) * interactionVolume.getFaceArea(idx1, 1) / T1L1; - Scalar omega211L1 = lambda[idx1][0] * (outerNormaln2 * K1nu1L1) * interactionVolume.getFaceArea(idx1, 0) / T1L1; - Scalar omega212L1 = lambda[idx1][0] * (outerNormaln2 * K1nu2L1) * interactionVolume.getFaceArea(idx1, 0) / T1L1; - Scalar omega123L1 = lambda[idx4][0] * (outerNormaln1L1 * K3nu3L1) * interactionVolume.getFaceArea(idx4, 0) / T2L1; - Scalar omega124L1 = lambda[idx4][0] * (outerNormaln1L1 * K3nu4L1) * interactionVolume.getFaceArea(idx4, 0) / T2L1; - Scalar omega235L1 = lambda[idx2][1] * (outerNormaln2 * K2nu5L1) * interactionVolume.getFaceArea(idx2, 1) / T3L1; - Scalar omega236L1 = lambda[idx2][1] * (outerNormaln2 * K2nu6L1) * interactionVolume.getFaceArea(idx2, 1) / T3L1; - Scalar chi711L1 = (nu7L1 * Rnu1L1) / T1L1; - Scalar chi712L1 = (nu7L1 * Rnu2L1) / T1L1; - - // compute transmissibility matrix TL1 = CA^{-1}B+D - C = 0; - A = 0; - D = 0; - B = 0; - - // evaluate matrix C, D, A, B - C[0][0] = -omega111L1; - C[0][1] = -omega112L1; - C[1][0] = -omega211L1; - C[1][1] = -omega212L1; - - D[0][0] = omega111L1 + omega112L1; - D[1][0] = omega211L1 + omega212L1; - - A[0][0] = omega111L1 - omega124L1 - omega123L1 * chi711L1; - A[0][1] = omega112L1 - omega123L1 * chi712L1; - A[1][0] = omega211L1 - omega236L1 * chi711L1; - A[1][1] = omega212L1 - omega235L1 - omega236L1 * chi712L1; - - B[0][0] = omega111L1 + omega112L1 + omega123L1 * (1.0 - chi711L1 - chi712L1); - B[0][1] = -omega123L1 - omega124L1; - B[1][0] = omega211L1 + omega212L1 + omega236L1 * (1.0 - chi711L1 - chi712L1); - B[1][2] = -omega235L1 - omega236L1; - - // compute TL1 - A.invert(); - D += B.leftmultiply(C.rightmultiply(A)); - Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> TL1(D); - - //selection criterion - Scalar sR = std::abs(TR1[1][2] - TR1[1][0]); - Scalar sL = std::abs(TL1[1][0] - TL1[1][2]); - - // 3.decide which triangle (which transmissibility coefficients) to use - if (sR <= sL) - { - transmissibility = TR1; - return rightTriangle; - } - else - { - transmissibility = TL1; - return leftTriangle; - } -} - -/*! \brief Calculates tranmissibility matrix - * - * Calculates tranmissibility matrix of an L-shape for a certain flux face. - * Calculates only the transmissibility of the left L-shape (needed at hanging nodes HN). - * - * \param transmissibilityLeft Matrix for the resulting transmissibility - * \param interactionVolume The interaction volume object (includes geometric information) - * \param lambda Mobilities of cells 1-3 - * \param idx1 Index of cell 1 of the L-stencil - * \param idx2 Index of cell 2 of the L-stencil - * \param idx3 Index of cell 3 of the L-stencil - */ -template<class TypeTag> -int FvMpfaL2dPressure2pAdaptive<TypeTag>::calculateLeftHNTransmissibility( - Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1>& transmissibilityLeft, - InteractionVolume& interactionVolume, - std::vector<DimVector >& lambda, - int idx1, int idx2, int idx3) -{ - ElementPointer& elementPointer1 = interactionVolume.getSubVolumeElement(idx1); - ElementPointer& elementPointer2 = interactionVolume.getSubVolumeElement(idx2); - ElementPointer& elementPointer3 = interactionVolume.getSubVolumeElement(idx3); - - if (elementPointer1->level() != elementPointer3->level()) - { - return noTransmissibility; - } - - // get global coordinate of cell centers - const GlobalPosition& globalPos1 = elementPointer1->geometry().center(); - const GlobalPosition& globalPos2 = elementPointer2->geometry().center(); - const GlobalPosition& globalPos3 = elementPointer3->geometry().center(); - - const GlobalPosition& globalPosCenter = interactionVolume.getCenterPosition(); - - const DimMatrix& K1 = problem_.spatialParams().intrinsicPermeability(*elementPointer1); - const DimMatrix& K2 = problem_.spatialParams().intrinsicPermeability(*elementPointer2); - const DimMatrix& K3 = problem_.spatialParams().intrinsicPermeability(*elementPointer3); - - const GlobalPosition& globalPosFace12 = interactionVolume.getFacePosition(idx1, 0); - DimVector &outerNormaln2 = interactionVolume.getNormal(idx1, 0); - - // compute transmissibility matrix TR1 = CA^{-1}B+D - DimMatrix C(0), A(0); - Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> D(0), B(0); - - // 2.use triangle L to compute the transmissibility of half edge - const GlobalPosition& globalPosFace14 = interactionVolume.getFacePosition(idx1, 1); - - // compute normal vectors nu1-nu7 in triangle L for first half edge - DimVector nu1L1(0); - R_.mv(globalPosFace12 - globalPos1, nu1L1); - - DimVector nu2L1(0); - R_.mv(globalPos1 - globalPosFace14, nu2L1); - - DimVector nu3L1(0); - R_.mv(globalPosFace14 - globalPos3, nu3L1); - - DimVector nu4L1(0); - R_.mv(globalPos3 - globalPosCenter, nu4L1); - - DimVector nu5L1(0); - R_.mv(globalPosCenter - globalPos2, nu5L1); - - DimVector nu6L1(0); - R_.mv(globalPos2 - globalPosFace12, nu6L1); - - DimVector nu7L1(0); - R_.mv(globalPosCenter - globalPos1, nu7L1); - - // compute T, i.e., the area of quadrilateral made by normal vectors 'nu' - DimVector Rnu2L1(0); - R_.mv(nu2L1, Rnu2L1); - Scalar T1L1 = nu1L1 * Rnu2L1; - - DimVector Rnu4L1(0); - R_.mv(nu4L1, Rnu4L1); - Scalar T2L1 = nu3L1 * Rnu4L1; - - DimVector Rnu6L1(0); - R_.mv(nu6L1, Rnu6L1); - Scalar T3L1 = nu5L1 * Rnu6L1; - - // compute components needed for flux calculation, denoted as 'omega' and 'chi' - DimVector K1nu1L1(0); - K1.mv(nu1L1, K1nu1L1); - DimVector K1nu2L1(0); - K1.mv(nu2L1, K1nu2L1); - DimVector K3nu3L1(0); - K3.mv(nu3L1, K3nu3L1); - DimVector K3nu4L1(0); - K3.mv(nu4L1, K3nu4L1); - DimVector K2nu5L1(0); - K2.mv(nu5L1, K2nu5L1); - DimVector K2nu6L1(0); - K2.mv(nu6L1, K2nu6L1); - - DimVector Rnu1L1(0); - R_.mv(nu1L1, Rnu1L1); - - DimVector &outerNormaln1L1 = interactionVolume.getNormal(idx1, 1); - - Scalar omega111L1 = lambda[idx1][1] * (outerNormaln1L1 * K1nu1L1) * interactionVolume.getFaceArea(idx1, 1) / T1L1; - Scalar omega112L1 = lambda[idx1][1] * (outerNormaln1L1 * K1nu2L1) * interactionVolume.getFaceArea(idx1, 1) / T1L1; - Scalar omega211L1 = lambda[idx1][0] * (outerNormaln2 * K1nu1L1) * interactionVolume.getFaceArea(idx1, 0) / T1L1; - Scalar omega212L1 = lambda[idx1][0] * (outerNormaln2 * K1nu2L1) * interactionVolume.getFaceArea(idx1, 0) / T1L1; - Scalar omega123L1 = lambda[idx3][0] * (outerNormaln1L1 * K3nu3L1) * interactionVolume.getFaceArea(idx3, 0) / T2L1; - Scalar omega124L1 = lambda[idx3][0] * (outerNormaln1L1 * K3nu4L1) * interactionVolume.getFaceArea(idx3, 0) / T2L1; - Scalar omega235L1 = lambda[idx2][1] * (outerNormaln2 * K2nu5L1) * interactionVolume.getFaceArea(idx2, 1) / T3L1; - Scalar omega236L1 = lambda[idx2][1] * (outerNormaln2 * K2nu6L1) * interactionVolume.getFaceArea(idx2, 1) / T3L1; - Scalar chi711L1 = (nu7L1 * Rnu1L1) / T1L1; - Scalar chi712L1 = (nu7L1 * Rnu2L1) / T1L1; - - // compute transmissibility matrix TL1 = CA^{-1}B+D - C = 0; - A = 0; - D = 0; - B = 0; - - // evaluate matrix C, D, A, B - C[0][0] = -omega111L1; - C[0][1] = -omega112L1; - C[1][0] = -omega211L1; - C[1][1] = -omega212L1; - - D[0][0] = omega111L1 + omega112L1; - D[1][0] = omega211L1 + omega212L1; - - A[0][0] = omega111L1 - omega124L1 - omega123L1 * chi711L1; - A[0][1] = omega112L1 - omega123L1 * chi712L1; - A[1][0] = omega211L1 - omega236L1 * chi711L1; - A[1][1] = omega212L1 - omega235L1 - omega236L1 * chi712L1; - - B[0][0] = omega111L1 + omega112L1 + omega123L1 * (1.0 - chi711L1 - chi712L1); - B[0][1] = -omega123L1 - omega124L1; - B[1][0] = omega211L1 + omega212L1 + omega236L1 * (1.0 - chi711L1 - chi712L1); - B[1][2] = -omega235L1 - omega236L1; - - // compute TL1 - A.invert(); - D += B.leftmultiply(C.rightmultiply(A)); - Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> TL1(D); - - // 3.decide which triangle (which transmissibility coefficients) to use - transmissibilityLeft = TL1; - return leftTriangle; -} - -/*! \brief Calculates tranmissibility matrix - * - * Calculates tranmissibility matrix of an L-shape for a certain flux face. - * Calculates only the transmissibility of the right L-shape (needed at hanging nodes HN). - * - * \param transmissibilityRight Matrix for the resulting transmissibility - * \param interactionVolume The interaction volume object (includes geometric information) - * \param lambda Mobilities of cells 1-3 - * \param idx1 Index of cell 1 of the L-stencil - * \param idx2 Index of cell 2 of the L-stencil - * \param idx3 Index of cell 3 of the L-stencil - */ -template<class TypeTag> -int FvMpfaL2dPressure2pAdaptive<TypeTag>::calculateRightHNTransmissibility( - Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1>& transmissibilityRight, - InteractionVolume& interactionVolume, - std::vector<DimVector >& lambda, - int idx1, int idx2, int idx3) -{ - ElementPointer& elementPointer1 = interactionVolume.getSubVolumeElement(idx1); - ElementPointer& elementPointer2 = interactionVolume.getSubVolumeElement(idx2); - ElementPointer& elementPointer3 = interactionVolume.getSubVolumeElement(idx3); - - if (elementPointer2->level() != elementPointer3->level()) - { - return noTransmissibility; - } - - // get global coordinate of cell centers - const GlobalPosition& globalPos1 = elementPointer1->geometry().center(); - const GlobalPosition& globalPos2 = elementPointer2->geometry().center(); - const GlobalPosition& globalPos3 = elementPointer3->geometry().center(); - - const GlobalPosition& globalPosCenter = interactionVolume.getCenterPosition(); - - const DimMatrix& K1 = problem_.spatialParams().intrinsicPermeability(*elementPointer1); - const DimMatrix& K2 = problem_.spatialParams().intrinsicPermeability(*elementPointer2); - const DimMatrix& K3 = problem_.spatialParams().intrinsicPermeability(*elementPointer3); - - const GlobalPosition& globalPosFace12 = interactionVolume.getFacePosition(idx1, 0); - const GlobalPosition& globalPosFace23 = interactionVolume.getFacePosition(idx2, 0); - - // compute normal vectors nu1-nu7 in triangle R for first half edge - DimVector nu1R1(0); - R_.mv(globalPosFace12 - globalPos2, nu1R1); - - DimVector nu2R1(0); - R_.mv(globalPos2 - globalPosFace23, nu2R1); - - DimVector nu3R1(0); - R_.mv(globalPosFace23 - globalPos3, nu3R1); - - DimVector nu4R1(0); - R_.mv(globalPos3 - globalPosCenter, nu4R1); - - DimVector nu5R1(0); - R_.mv(globalPosCenter - globalPos1, nu5R1); - - DimVector nu6R1(0); - R_.mv(globalPos1 - globalPosFace12, nu6R1); - - DimVector nu7R1(0); - R_.mv(globalPosCenter - globalPos2, nu7R1); - - // compute T, i.e., the area of quadrilateral made by normal vectors 'nu' - DimVector Rnu2R1(0); - R_.mv(nu2R1, Rnu2R1); - Scalar T1R1 = nu1R1 * Rnu2R1; - - DimVector Rnu4R1(0); - R_.mv(nu4R1, Rnu4R1); - Scalar T2R1 = nu3R1 * Rnu4R1; - - DimVector Rnu6R1(0); - R_.mv(nu6R1, Rnu6R1); - Scalar T3R1 = nu5R1 * Rnu6R1; - - // compute components needed for flux calculation, denoted as 'omega' and 'chi' - DimVector K2nu1R1(0); - K2.mv(nu1R1, K2nu1R1); - DimVector K2nu2R1(0); - K2.mv(nu2R1, K2nu2R1); - DimVector K3nu3R1(0); - K3.mv(nu3R1, K3nu3R1); - DimVector K3nu4R1(0); - K3.mv(nu4R1, K3nu4R1); - DimVector K1nu5R1(0); - K1.mv(nu5R1, K1nu5R1); - DimVector K1nu6R1(0); - K1.mv(nu6R1, K1nu6R1); - - DimVector Rnu1R1(0); - R_.mv(nu1R1, Rnu1R1); - - DimVector &outerNormaln1R1 = interactionVolume.getNormal(idx2, 0); - DimVector &outerNormaln2 = interactionVolume.getNormal(idx1, 0); - - Scalar omega111R1 = lambda[idx2][0] * (outerNormaln1R1 * K2nu1R1) * interactionVolume.getFaceArea(idx2, 0) / T1R1; - Scalar omega112R1 = lambda[idx2][0] * (outerNormaln1R1 * K2nu2R1) * interactionVolume.getFaceArea(idx2, 0) / T1R1; - Scalar omega211R1 = lambda[idx2][1] * (outerNormaln2 * K2nu1R1) * interactionVolume.getFaceArea(idx2, 1) / T1R1; - Scalar omega212R1 = lambda[idx2][1] * (outerNormaln2 * K2nu2R1) * interactionVolume.getFaceArea(idx2, 1) / T1R1; - Scalar omega123R1 = lambda[idx3][1] * (outerNormaln1R1 * K3nu3R1) * interactionVolume.getFaceArea(idx3, 1) / T2R1; - Scalar omega124R1 = lambda[idx3][1] * (outerNormaln1R1 * K3nu4R1) * interactionVolume.getFaceArea(idx3, 1) / T2R1; - Scalar omega235R1 = lambda[idx1][0] * (outerNormaln2 * K1nu5R1) * interactionVolume.getFaceArea(idx1, 0) / T3R1; - Scalar omega236R1 = lambda[idx1][0] * (outerNormaln2 * K1nu6R1) * interactionVolume.getFaceArea(idx1, 0) / T3R1; - Scalar chi711R1 = (nu7R1 * Rnu1R1) / T1R1; - Scalar chi712R1 = (nu7R1 * Rnu2R1) / T1R1; - - // compute transmissibility matrix TR1 = CA^{-1}B+D - DimMatrix C(0), A(0); - Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> D(0), B(0); - - // evaluate matrix C, D, A, B - C[0][0] = -omega111R1; - C[0][1] = -omega112R1; - C[1][0] = -omega211R1; - C[1][1] = -omega212R1; - - D[0][0] = omega111R1 + omega112R1; - D[1][0] = omega211R1 + omega212R1; - - A[0][0] = omega111R1 - omega124R1 - omega123R1 * chi711R1; - A[0][1] = omega112R1 - omega123R1 * chi712R1; - A[1][0] = omega211R1 - omega236R1 * chi711R1; - A[1][1] = omega212R1 - omega235R1 - omega236R1 * chi712R1; - - B[0][0] = omega111R1 + omega112R1 + omega123R1 * (1.0 - chi711R1 - chi712R1); - B[0][1] = -omega123R1 - omega124R1; - B[1][0] = omega211R1 + omega212R1 + omega236R1 * (1.0 - chi711R1 - chi712R1); - B[1][2] = -omega235R1 - omega236R1; - - // compute TR1 - A.invert(); - D += B.leftmultiply(C.rightmultiply(A)); - Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> TR1(D); - - transmissibilityRight = TR1; - return rightTriangle; -} - /*! \brief Updates constitutive relations and stores them in the variable class * * Stores mobility, fractional flow function and capillary pressure for all grid cells. diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressureproperties2p.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressureproperties2p.hh index fb9bf8de72a529472bb482054fa01db704c68b92..6e9979377cd07bb92f577c14451a327834cecf56 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressureproperties2p.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressureproperties2p.hh @@ -40,12 +40,15 @@ NEW_TYPE_TAG(FvMpfaL2dPressureTwoP, INHERITS_FROM(PressureTwoP, MPFAProperties)) } #include "fvmpfal2dpressurevelocity2p.hh" +#include <dumux/decoupled/common/fv/mpfa/fvmpfavelocityintransport.hh> namespace Dumux { namespace Properties { SET_TYPE_PROP(FvMpfaL2dPressureTwoP, PressureModel, Dumux::FvMpfaL2dPressureVelocity2p<TypeTag>); +//! Set velocity reconstruction implementation standard cell centered finite volume schemes as default +SET_TYPE_PROP( FvMpfaL2dPressureTwoP, Velocity, Dumux::FvMpfaVelocityInTransport<TypeTag> ); } }// end of Dune namespace #endif diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressureproperties2padaptive.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressureproperties2padaptive.hh index 3e676f24604729a3f3e9e0a83764e7cb37b910d9..f3929f0379ca11a55c5c683afcb870ebeca842b5 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressureproperties2padaptive.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressureproperties2padaptive.hh @@ -40,12 +40,15 @@ NEW_TYPE_TAG(FvMpfaL2dPressureTwoPAdaptive, INHERITS_FROM(PressureTwoP, MPFAProp } #include "fvmpfal2dpressurevelocity2padaptive.hh" +#include <dumux/decoupled/common/fv/mpfa/fvmpfavelocityintransport.hh> namespace Dumux { namespace Properties { SET_TYPE_PROP(FvMpfaL2dPressureTwoPAdaptive, PressureModel, Dumux::FvMpfaL2dPressureVelocity2pAdaptive<TypeTag>); +//! Set velocity reconstruction implementation standard cell centered finite volume schemes as default +SET_TYPE_PROP( FvMpfaL2dPressureTwoPAdaptive, Velocity, Dumux::FvMpfaVelocityInTransport<TypeTag> ); } }// end of Dune namespace #endif diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressurevelocity2p.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressurevelocity2p.hh index 5d944a059c9d710e5107ef0a632c0075da405812..66522762147bc4fea68081147c522ca498a6468f 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressurevelocity2p.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressurevelocity2p.hh @@ -19,6 +19,7 @@ #define DUMUX_MPFAL2DPRESSUREVELOCITY2P_HH #include "fvmpfal2dpressure2p.hh" +#include "fvmpfal2dvelocity2p.hh" /** * @file @@ -61,6 +62,10 @@ template<class TypeTag> class FvMpfaL2dPressureVelocity2p: public FvMpfaL2dPress typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, CellData) CellData; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP(TypeTag, SolutionTypes) SolutionTypes; + typedef typename SolutionTypes::PrimaryVariables PrimaryVariables; #if DUNE_VERSION_NEWER(DUNE_GRID, 2, 3) typedef typename Dune::ReferenceElements<Scalar, dim> ReferenceElements; @@ -78,23 +83,12 @@ template<class TypeTag> class FvMpfaL2dPressureVelocity2p: public FvMpfaL2dPress typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; - typedef typename GET_PROP(TypeTag, SolutionTypes) SolutionTypes; - typedef typename SolutionTypes::PrimaryVariables PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, CellData) CellData; - - typedef typename GridView::Grid Grid; typedef typename GridView::IndexSet IndexSet; typedef typename GridView::template Codim<0>::Iterator ElementIterator; typedef typename GridView::template Codim<dim>::Iterator VertexIterator; typedef typename GridView::IntersectionIterator IntersectionIterator; - typedef typename Grid::template Codim<0>::EntityPointer ElementPointer; - - typedef typename Grid::template Codim<0>::Entity::Geometry Geometry; - #if DUNE_VERSION_NEWER(DUNE_GRID, 2, 3) - typedef typename Geometry::JacobianTransposed JacobianTransposed; - #else - typedef typename Geometry::Jacobian JacobianTransposed; - #endif + typedef typename GridView::template Codim<0>::EntityPointer ElementPointer; + typedef typename GridView::Intersection Intersection; typedef typename ParentType::InteractionVolume InteractionVolume; @@ -103,10 +97,7 @@ template<class TypeTag> class FvMpfaL2dPressureVelocity2p: public FvMpfaL2dPress pw = Indices::pressureW, pn = Indices::pressureNw, sw = Indices::saturationW, - sn = Indices::saturationNw - }; - enum - { + sn = Indices::saturationNw, wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx, pressureIdx = Indices::pressureIdx, @@ -116,20 +107,8 @@ template<class TypeTag> class FvMpfaL2dPressureVelocity2p: public FvMpfaL2dPress numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; - enum - { - globalCorner = 2, - globalEdge = 3, - neumannNeumann = 0, - dirichletDirichlet = 1, - dirichletNeumann = 2, - neumannDirichlet = 3 - }; - - typedef Dune::FieldVector<Scalar, dim> LocalPosition; typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; - typedef Dune::FieldVector<Scalar, dim> DimVector; public: //! Constructs a FvMpfaL2dPressureVelocity2p object @@ -137,32 +116,31 @@ public: * \param problem A problem class object */ FvMpfaL2dPressureVelocity2p(Problem& problem) : - ParentType(problem), problem_(problem), gravity_(problem.gravity()) + ParentType(problem), problem_(problem), velocity_(problem) { density_[wPhaseIdx] = 0.; density_[nPhaseIdx] = 0.; viscosity_[wPhaseIdx] = 0.; viscosity_[nPhaseIdx] = 0.; - vtkOutputLevel_ = GET_PARAM_FROM_GROUP(TypeTag, int, Vtk, OutputLevel); + calcVelocityInTransport_ = GET_PARAM_FROM_GROUP(TypeTag, bool, MPFA, CalcVelocityInTransport); } //Calculates the velocities at all cell-cell interfaces. void calculateVelocity(); + // Calculates the velocity at a cell-cell interface. + void calculateVelocity(const Intersection&, CellData&); + void calculateVelocityOnBoundary(const Intersection& intersection, CellData& cellData); + void updateVelocity() { this->updateMaterialLaws(); - //reset velocities - int size = problem_.gridView().size(0); - for (int i = 0; i < size; i++) - { - CellData& cellData = problem_.variables().cellData(i); - cellData.fluxData().resetVelocity(); - } + this->storePressureSolution(); - calculateVelocity(); + if (!calculateVelocityInTransport()) + calculateVelocity(); } /*! \brief Initializes pressure and velocity @@ -171,8 +149,6 @@ public: */ void initialize() { - ParentType::initialize(); - ElementIterator element = problem_.gridView().template begin<0>(); FluidState fluidState; fluidState.setPressure(wPhaseIdx, problem_.referencePressure(*element)); @@ -185,7 +161,10 @@ public: viscosity_[wPhaseIdx] = FluidSystem::viscosity(fluidState, wPhaseIdx); viscosity_[nPhaseIdx] = FluidSystem::viscosity(fluidState, nPhaseIdx); - calculateVelocity(); + ParentType::initialize(); + velocity_.initialize(); + if (!calculateVelocityInTransport()) + calculateVelocity(); return; } @@ -198,10 +177,17 @@ public: void update() { ParentType::update(); + if (!calculateVelocityInTransport()) + calculateVelocity(); + } - calculateVelocity(); - - return; + /*! \brief Indicates if velocity is reconstructed in the pressure step or in the transport step + * + * Returns true (In the standard finite volume discretization the velocity is calculated during the saturation transport.) + */ + bool calculateVelocityInTransport() + { + return calcVelocityInTransport_; } /*! \brief Adds velocity output to the output file @@ -218,86 +204,17 @@ public: void addOutputVtkFields(MultiWriter &writer) { ParentType::addOutputVtkFields(writer); - - if (vtkOutputLevel_ > 0) - { - Dune::BlockVector < DimVector > &velocityWetting = *(writer.template allocateManagedBuffer< - Scalar, dim>(problem_.gridView().size(0))); - Dune::BlockVector < DimVector > &velocityNonwetting = - *(writer.template allocateManagedBuffer<Scalar, dim>(problem_.gridView().size(0))); - - // compute update vector - ElementIterator eEndIt = problem_.gridView().template end<0>(); - for (ElementIterator eIt = problem_.gridView().template begin<0>(); eIt != eEndIt; ++eIt) - { - // cell index - int globalIdx = problem_.variables().index(*eIt); - - CellData& cellData = problem_.variables().cellData(globalIdx); - - Dune::FieldVector < Scalar, 2 * dim > fluxW(0); - Dune::FieldVector < Scalar, 2 * dim > fluxNw(0); - // run through all intersections with neighbors and boundary - IntersectionIterator isEndIt = problem_.gridView().iend(*eIt); - for (IntersectionIterator isIt = problem_.gridView().ibegin(*eIt); isIt != isEndIt; ++isIt) - { - int isIndex = isIt->indexInInside(); - - fluxW[isIndex] = isIt->geometry().volume() - * (isIt->centerUnitOuterNormal() * cellData.fluxData().velocity(wPhaseIdx, isIndex)); - fluxNw[isIndex] = - isIt->geometry().volume() - * (isIt->centerUnitOuterNormal() - * cellData.fluxData().velocity(nPhaseIdx, isIndex)); - } - - DimVector refVelocity(0); - for (int i = 0; i < dim; i++) - refVelocity[i] = 0.5 * (fluxW[2*i + 1] - fluxW[2*i]); - - const DimVector localPos = - ReferenceElements::general(eIt->geometry().type()).position(0, 0); - - // get the transposed Jacobian of the element mapping - const JacobianTransposed jacobianT = eIt->geometry().jacobianTransposed(localPos); - - // calculate the element velocity by the Piola transformation - DimVector elementVelocity(0); - jacobianT.umtv(refVelocity, elementVelocity); - elementVelocity /= eIt->geometry().integrationElement(localPos); - - velocityWetting[globalIdx] = elementVelocity; - - refVelocity = 0; - for (int i = 0; i < dim; i++) - refVelocity[i] = 0.5 * (fluxNw[2*i + 1] - fluxNw[2*i]); - - // calculate the element velocity by the Piola transformation - elementVelocity = 0; - jacobianT.umtv(refVelocity, elementVelocity); - elementVelocity /= eIt->geometry().integrationElement(localPos); - - velocityNonwetting[globalIdx] = elementVelocity; - } - - writer.attachCellData(velocityWetting, "wetting-velocity", dim); - writer.attachCellData(velocityNonwetting, "non-wetting-velocity", dim); - - } - return; + velocity_.addOutputVtkFields(writer); } private: Problem& problem_; - const GlobalPosition& gravity_; //!< vector including the gravity constant + FvMpfaL2dVelocity2p<TypeTag> velocity_; Scalar density_[numPhases]; Scalar viscosity_[numPhases]; + bool calcVelocityInTransport_; - int vtkOutputLevel_; - - static constexpr Scalar threshold_ = 1e-15; - static const int velocityType_ = GET_PROP_VALUE(TypeTag, VelocityFormulation); //!< gives kind of velocity used (\f$ 0 = v_w\f$, \f$ 1 = v_n\f$, \f$ 2 = v_t\f$) static const int pressureType_ = GET_PROP_VALUE(TypeTag, PressureFormulation); //!< gives kind of pressure used (\f$ 0 = p_w\f$, \f$ 1 = p_n\f$, \f$ 2 = p_{global}\f$) static const int saturationType_ = GET_PROP_VALUE(TypeTag, SaturationFormulation); //!< gives kind of saturation used (\f$ 0 = S_w\f$, \f$ 1 = S_n\f$) }; @@ -338,604 +255,305 @@ void FvMpfaL2dPressureVelocity2p<TypeTag>::calculateVelocity() CellData& cellData3 = problem_.variables().cellData(globalIdx3); CellData& cellData4 = problem_.variables().cellData(globalIdx4); - // get pressure values - Dune::FieldVector < Scalar, 2 * dim > potW(0); - Dune::FieldVector < Scalar, 2 * dim > potNw(0); + velocity_.calculateInnerInteractionVolumeVelocity(interactionVolume, cellData1, cellData2, cellData3, cellData4, this->innerBoundaryVolumeFaces_); - potW[0] = cellData1.potential(wPhaseIdx); - potW[1] = cellData2.potential(wPhaseIdx); - potW[2] = cellData3.potential(wPhaseIdx); - potW[3] = cellData4.potential(wPhaseIdx); + } + // at least one face on boundary! + else + { + for (int elemIdx = 0; elemIdx < 2 * dim; elemIdx++) + { + bool isOutside = false; + for (int faceIdx = 0; faceIdx < dim; faceIdx++) + { + int intVolFaceIdx = interactionVolume.getFaceIndexFromSubVolume(elemIdx, faceIdx); + if (interactionVolume.isOutsideFace(intVolFaceIdx)) + { + isOutside = true; + break; + } + } + if (isOutside) + { + continue; + } + ElementPointer & elementPointer = interactionVolume.getSubVolumeElement(elemIdx); - potNw[0] = cellData1.potential(nPhaseIdx); - potNw[1] = cellData2.potential(nPhaseIdx); - potNw[2] = cellData3.potential(nPhaseIdx); - potNw[3] = cellData4.potential(nPhaseIdx); + // cell index + int globalIdx = problem_.variables().index(*elementPointer); + //get the cell Data + CellData& cellData = problem_.variables().cellData(globalIdx); - //get mobilities of the phases - Dune::FieldVector<Scalar, numPhases> lambda1(cellData1.mobility(wPhaseIdx)); - lambda1[nPhaseIdx] = cellData1.mobility(nPhaseIdx); + velocity_.calculateBoundaryInteractionVolumeVelocity(interactionVolume, cellData, elemIdx); + } - //compute total mobility of cell 1 - Scalar lambdaTotal1 = lambda1[wPhaseIdx] + lambda1[nPhaseIdx]; + } // end boundaries - //get mobilities of the phases - Dune::FieldVector<Scalar, numPhases> lambda2(cellData2.mobility(wPhaseIdx)); - lambda2[nPhaseIdx] = cellData2.mobility(nPhaseIdx); + } // end vertex iterator - //compute total mobility of cell 1 - Scalar lambdaTotal2 = lambda2[wPhaseIdx] + lambda2[nPhaseIdx]; +// } + return; +} // end method calcTotalVelocity - //get mobilities of the phases - Dune::FieldVector<Scalar, numPhases> lambda3(cellData3.mobility(wPhaseIdx)); - lambda3[nPhaseIdx] = cellData3.mobility(nPhaseIdx); - //compute total mobility of cell 1 - Scalar lambdaTotal3 = lambda3[wPhaseIdx] + lambda3[nPhaseIdx]; +template<class TypeTag> +void FvMpfaL2dPressureVelocity2p<TypeTag>::calculateVelocity(const Intersection& intersection, CellData& cellData) +{ + int numVertices = intersection.geometry().corners(); - //get mobilities of the phases - Dune::FieldVector<Scalar, numPhases> lambda4(cellData4.mobility(wPhaseIdx)); - lambda4[nPhaseIdx] = cellData4.mobility(nPhaseIdx); + ElementPointer elementPtrI = intersection.inside(); + ElementPointer elementPtrJ = intersection.outside(); - //compute total mobility of cell 1 - Scalar lambdaTotal4 = lambda4[wPhaseIdx] + lambda4[nPhaseIdx]; + int globalIdxI = problem_.variables().index(*elementPtrI); + int globalIdxJ = problem_.variables().index(*elementPtrJ); - std::vector < DimVector > lambda(2 * dim); + CellData& cellDataJ = problem_.variables().cellData(globalIdxJ); - lambda[0][0] = lambdaTotal1; - lambda[0][1] = lambdaTotal1; - lambda[1][0] = lambdaTotal2; - lambda[1][1] = lambdaTotal2; - lambda[2][0] = lambdaTotal3; - lambda[2][1] = lambdaTotal3; - lambda[3][0] = lambdaTotal4; - lambda[3][1] = lambdaTotal4; + const ReferenceElement& referenceElement = ReferenceElements::general(elementPtrI->geometry().type()); - Scalar potentialDiffW12 = 0; - Scalar potentialDiffW14 = 0; - Scalar potentialDiffW32 = 0; - Scalar potentialDiffW34 = 0; + int indexInInside = intersection.indexInInside(); + int indexInOutside = intersection.indexInOutside(); - Scalar potentialDiffNw12 = 0; - Scalar potentialDiffNw14 = 0; - Scalar potentialDiffNw32 = 0; - Scalar potentialDiffNw34 = 0; + Dune::FieldVector<CellData, 4> cellDataTemp; - //flux vector - Dune::FieldVector < Scalar, 2 * dim > fluxW(0); - Dune::FieldVector < Scalar, 2 * dim > fluxNw(0); + for (int vIdx = 0; vIdx < numVertices; vIdx++) + { + int localVertIdx = referenceElement.subEntity(indexInInside, dim - 1, vIdx, dim); - Dune::FieldMatrix < Scalar, dim, 2 * dim - dim + 1 > T(0); - DimVector Tu(0); - Dune::FieldVector<Scalar, 2 * dim - dim + 1> u(0); + int globalVertIdx = problem_.variables().index( + *((*elementPtrI).template subEntity < dim > (localVertIdx))); - bool rightTriangle = this->calculateTransmissibility(T, interactionVolume, lambda, 0, 1, 2, 3); + InteractionVolume& interactionVolume = this->interactionVolumes_[globalVertIdx]; - if (rightTriangle) - { - u[0] = potW[1]; - u[1] = potW[2]; - u[2] = potW[0]; + if (interactionVolume.isInnerVolume()) + { - T.mv(u, Tu); + ElementPointer & elementPointer1 = interactionVolume.getSubVolumeElement(0); + ElementPointer & elementPointer2 = interactionVolume.getSubVolumeElement(1); + ElementPointer & elementPointer3 = interactionVolume.getSubVolumeElement(2); + ElementPointer & elementPointer4 = interactionVolume.getSubVolumeElement(3); - fluxW[0] = Tu[1]; - potentialDiffW12 = Tu[1]; + // cell index + int globalIdx[4]; + globalIdx[0] = problem_.variables().index(*elementPointer1); + globalIdx[1] = problem_.variables().index(*elementPointer2); + globalIdx[2] = problem_.variables().index(*elementPointer3); + globalIdx[3] = problem_.variables().index(*elementPointer4); - u[0] = potNw[1]; - u[1] = potNw[2]; - u[2] = potNw[0]; + //get the cell Data + cellDataTemp[0] = problem_.variables().cellData(globalIdx[0]); + cellDataTemp[1] = problem_.variables().cellData(globalIdx[1]); + cellDataTemp[2] = problem_.variables().cellData(globalIdx[2]); + cellDataTemp[3] = problem_.variables().cellData(globalIdx[3]); - T.mv(u, Tu); + velocity_.calculateInnerInteractionVolumeVelocity(interactionVolume, cellDataTemp[0], cellDataTemp[1], cellDataTemp[2], cellDataTemp[3], this->innerBoundaryVolumeFaces_); - fluxNw[0] = Tu[1]; - potentialDiffNw12 = Tu[1]; - } - else + for (int i = 0; i < 4; i++) + { + if (globalIdx[i] == globalIdxI) { - u[0] = potW[0]; - u[1] = potW[3]; - u[2] = potW[1]; - - T.mv(u, Tu); - - fluxW[0] = Tu[1]; - potentialDiffW12 = Tu[1]; - - u[0] = potNw[0]; - u[1] = potNw[3]; - u[2] = potNw[1]; - - T.mv(u, Tu); - - fluxNw[0] = Tu[1]; - potentialDiffNw12 = Tu[1]; + cellData.fluxData().setVelocity(wPhaseIdx, indexInInside, cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInInside)); + cellData.fluxData().setVelocity(nPhaseIdx, indexInInside, cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInInside)); + cellData.fluxData().setUpwindPotential(wPhaseIdx, indexInInside, cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInInside)); + cellData.fluxData().setUpwindPotential(nPhaseIdx, indexInInside, cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInInside)); } - - rightTriangle = this->calculateTransmissibility(T, interactionVolume, lambda, 1, 2, 3, 0); - - if (rightTriangle) + else if (globalIdx[i] == globalIdxJ) { - u[0] = potW[2]; - u[1] = potW[3]; - u[2] = potW[1]; - - T.mv(u, Tu); - - fluxW[1] = Tu[1]; - potentialDiffW32 = -Tu[1]; - - u[0] = potNw[2]; - u[1] = potNw[3]; - u[2] = potNw[1]; - - T.mv(u, Tu); - - fluxNw[1] = Tu[1]; - potentialDiffNw32 = -Tu[1]; + cellDataJ.fluxData().setVelocity(wPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInOutside)); + cellDataJ.fluxData().setVelocity(nPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInOutside)); + cellDataJ.fluxData().setUpwindPotential(wPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInOutside)); + cellDataJ.fluxData().setUpwindPotential(nPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInOutside)); } - else - { - u[0] = potW[1]; - u[1] = potW[0]; - u[2] = potW[2]; - - T.mv(u, Tu); - - fluxW[1] = Tu[1]; - potentialDiffW32 = -Tu[1]; + } + } + } + cellData.fluxData().setVelocityMarker(indexInInside); + cellDataJ.fluxData().setVelocityMarker(indexInOutside); +} - u[0] = potNw[1]; - u[1] = potNw[0]; - u[2] = potNw[2]; +template<class TypeTag> +void FvMpfaL2dPressureVelocity2p<TypeTag>::calculateVelocityOnBoundary(const Intersection& intersection, CellData& cellData) +{ + ElementPointer element = intersection.inside(); - T.mv(u, Tu); + //get face index + int isIndex = intersection.indexInInside(); - fluxNw[1] = Tu[1]; - potentialDiffNw32 = -Tu[1]; - } + //get face normal + const Dune::FieldVector<Scalar, dim>& unitOuterNormal = intersection.centerUnitOuterNormal(); - rightTriangle = this->calculateTransmissibility(T, interactionVolume, lambda, 2, 3, 0, 1); + BoundaryTypes bcType; + //get boundary type + problem_.boundaryTypes(bcType, intersection); + PrimaryVariables boundValues(0.0); - if (rightTriangle) - { - u[0] = potW[3]; - u[1] = potW[0]; - u[2] = potW[2]; + if (bcType.isDirichlet(pressEqIdx)) + { + problem_.dirichlet(boundValues, intersection); - T.mv(u, Tu); + // get global coordinates of cell centers + const GlobalPosition& globalPosI = element->geometry().center(); - fluxW[2] = Tu[1]; - potentialDiffW34 = Tu[1]; + // center of face in global coordinates + const GlobalPosition& globalPosJ = intersection.geometry().center(); - u[0] = potNw[3]; - u[1] = potNw[0]; - u[2] = potNw[2]; + // get mobilities and fractional flow factors + Scalar lambdaWI = cellData.mobility(wPhaseIdx); + Scalar lambdaNwI = cellData.mobility(nPhaseIdx); - T.mv(u, Tu); + // get capillary pressure + Scalar pcI = cellData.capillaryPressure(); - fluxNw[2] = Tu[1]; - potentialDiffNw34 = Tu[1]; - } - else - { - u[0] = potW[2]; - u[1] = potW[1]; - u[2] = potW[3]; + // distance vector between barycenters + GlobalPosition distVec = globalPosJ - globalPosI; - T.mv(u, Tu); + // compute distance between cell centers + Scalar dist = distVec.two_norm(); - fluxW[2] = Tu[1]; - potentialDiffW34 = Tu[1]; + //permeability vector at boundary + // compute vectorized permeabilities + DimMatrix meanPermeability(0); - u[0] = potNw[2]; - u[1] = potNw[1]; - u[2] = potNw[3]; + problem_.spatialParams().meanK(meanPermeability, problem_.spatialParams().intrinsicPermeability(*element)); - T.mv(u, Tu); + Dune::FieldVector<Scalar, dim> permeability(0); + meanPermeability.mv(unitOuterNormal, permeability); - fluxNw[2] = Tu[1]; - potentialDiffNw34 = Tu[1]; + //determine saturation at the boundary -> if no saturation is known directly at the boundary use the cell saturation + Scalar satW = 0; + Scalar satNw = 0; + if (bcType.isDirichlet(satEqIdx)) + { + switch (saturationType_) + { + case sw: + { + satW = boundValues[saturationIdx]; + satNw = 1 - boundValues[saturationIdx]; + break; } - - rightTriangle = this->calculateTransmissibility(T, interactionVolume, lambda, 3, 0, 1, 2); - - if (rightTriangle) + case sn: { - u[0] = potW[0]; - u[1] = potW[1]; - u[2] = potW[3]; + satW = 1 - boundValues[saturationIdx]; + satNw = boundValues[saturationIdx]; + break; + } + } + } + else + { + satW = cellData.saturation(wPhaseIdx); + satNw = cellData.saturation(nPhaseIdx); + } - T.mv(u, Tu); + Scalar pressBound = boundValues[pressureIdx]; + Scalar pcBound = MaterialLaw::pc(problem_.spatialParams().materialLawParams(*element), satW); - fluxW[3] = Tu[1]; - potentialDiffW14 = -Tu[1]; + //determine phase pressures from primary pressure variable + Scalar pressWBound = 0; + Scalar pressNwBound = 0; + if (pressureType_ == pw) + { + pressWBound = pressBound; + pressNwBound = pressBound + pcBound; + } + else if (pressureType_ == pn) + { + pressWBound = pressBound - pcBound; + pressNwBound = pressBound; + } - u[0] = potNw[0]; - u[1] = potNw[1]; - u[2] = potNw[3]; + Scalar lambdaWBound = MaterialLaw::krw(problem_.spatialParams().materialLawParams(*element), satW) + / viscosity_[wPhaseIdx]; + Scalar lambdaNwBound = MaterialLaw::krn(problem_.spatialParams().materialLawParams(*element), satW) + / viscosity_[nPhaseIdx]; - T.mv(u, Tu); + Scalar potentialDiffW = cellData.fluxData().upwindPotential(wPhaseIdx, isIndex); + Scalar potentialDiffNw = cellData.fluxData().upwindPotential(nPhaseIdx, isIndex); - fluxNw[3] = Tu[1]; - potentialDiffNw14 = -Tu[1]; - } - else - { - u[0] = potW[3]; - u[1] = potW[2]; - u[2] = potW[0]; + //calculate potential gradient + potentialDiffW = (cellData.pressure(wPhaseIdx) - pressWBound); + potentialDiffNw = (cellData.pressure(nPhaseIdx) - pressNwBound); - T.mv(u, Tu); + potentialDiffW += density_[wPhaseIdx] * (distVec * problem_.gravity()); + potentialDiffNw += density_[nPhaseIdx] * (distVec * problem_.gravity()); - fluxW[3] = Tu[1]; - potentialDiffW14 = -Tu[1]; + //store potential gradients for further calculations + cellData.fluxData().setUpwindPotential(wPhaseIdx, isIndex, potentialDiffW); + cellData.fluxData().setUpwindPotential(nPhaseIdx, isIndex, potentialDiffNw); - u[0] = potNw[3]; - u[1] = potNw[2]; - u[2] = potNw[0]; + //do the upwinding of the mobility depending on the phase potentials + Scalar lambdaW = (potentialDiffW > 0.) ? lambdaWI : lambdaWBound; + lambdaW = (potentialDiffW == 0) ? 0.5 * (lambdaWI + lambdaWBound) : lambdaW; + Scalar lambdaNw = (potentialDiffNw > 0.) ? lambdaNwI : lambdaNwBound; + lambdaNw = (potentialDiffNw == 0) ? 0.5 * (lambdaNwI + lambdaNwBound) : lambdaNw; - T.mv(u, Tu); - fluxNw[3] = Tu[1]; - potentialDiffNw14 = -Tu[1]; - } + Scalar scalarPerm = permeability.two_norm(); - //store potentials for further calculations (saturation, ...) - cellData1.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(0, 0), potentialDiffW12); - cellData1.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(0, 0), potentialDiffNw12); - cellData1.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(0, 1), potentialDiffW14); - cellData1.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(0, 1), potentialDiffNw14); - cellData2.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(1, 0), -potentialDiffW32); - cellData2.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(1, 0), -potentialDiffNw32); - cellData2.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(1, 1), -potentialDiffW12); - cellData2.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(1, 1), -potentialDiffNw12); - cellData3.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(2, 0), potentialDiffW34); - cellData3.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(2, 0), potentialDiffNw34); - cellData3.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(2, 1), potentialDiffW32); - cellData3.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(2, 1), potentialDiffNw32); - cellData4.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(3, 0), -potentialDiffW14); - cellData4.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(3, 0), -potentialDiffNw14); - cellData4.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(3, 1), -potentialDiffW34); - cellData4.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(3, 1), -potentialDiffNw34); - - //compute mobilities of face 1 - Dune::FieldVector<Scalar, numPhases> lambda12Upw(0.0); - lambda12Upw[wPhaseIdx] = (potentialDiffW12 >= 0) ? lambda1[wPhaseIdx] : lambda2[wPhaseIdx]; - lambda12Upw[nPhaseIdx] = (potentialDiffNw12 >= 0) ? lambda1[nPhaseIdx] : lambda2[nPhaseIdx]; - - //compute mobilities of face 4 - Dune::FieldVector<Scalar, numPhases> lambda14Upw(0.0); - lambda14Upw[wPhaseIdx] = (potentialDiffW14 >= 0) ? lambda1[wPhaseIdx] : lambda4[wPhaseIdx]; - lambda14Upw[nPhaseIdx] = (potentialDiffNw14 >= 0) ? lambda1[nPhaseIdx] : lambda4[nPhaseIdx]; - - //compute mobilities of face 2 - Dune::FieldVector<Scalar, numPhases> lambda32Upw(0.0); - lambda32Upw[wPhaseIdx] = (potentialDiffW32 >= 0) ? lambda3[wPhaseIdx] : lambda2[wPhaseIdx]; - lambda32Upw[nPhaseIdx] = (potentialDiffNw32 >= 0) ? lambda3[nPhaseIdx] : lambda2[nPhaseIdx]; - - //compute mobilities of face 3 - Dune::FieldVector<Scalar, numPhases> lambda34Upw(0.0); - lambda34Upw[wPhaseIdx] = (potentialDiffW34 >= 0) ? lambda3[wPhaseIdx] : lambda4[wPhaseIdx]; - lambda34Upw[nPhaseIdx] = (potentialDiffNw34 >= 0) ? lambda3[nPhaseIdx] : lambda4[nPhaseIdx]; - - for (int i = 0; i < numPhases; i++) - { - // evaluate parts of velocity --> always take the normal for which the flux is calculated! - DimVector vel12 = interactionVolume.getNormal(0, 0); - DimVector vel14 = interactionVolume.getNormal(3, 0); - DimVector vel23 = interactionVolume.getNormal(1, 0); - DimVector vel21 = interactionVolume.getNormal(0, 0); - DimVector vel34 = interactionVolume.getNormal(2, 0); - DimVector vel32 = interactionVolume.getNormal(1, 0); - DimVector vel41 = interactionVolume.getNormal(3, 0); - DimVector vel43 = interactionVolume.getNormal(2, 0); - - Dune::FieldVector<Scalar, 2 * dim> flux(0); - switch (i) - { - case wPhaseIdx: - { - flux = fluxW; - break; - } - case nPhaseIdx: - { - flux = fluxNw; - break; - } - } + //calculate the gravity term + Dune::FieldVector<Scalar, dimWorld> velocityW(unitOuterNormal); + Dune::FieldVector<Scalar, dimWorld> velocityNw(unitOuterNormal); - vel12 *= flux[0] / (2 * interactionVolume.getFaceArea(0, 0)); //divide by 2 because the flux is related to the half face! - vel14 *= flux[3] / (2 * interactionVolume.getFaceArea(0, 1)); - vel23 *= flux[1] / (2 * interactionVolume.getFaceArea(1, 0)); - vel21 *= flux[0] / (2 * interactionVolume.getFaceArea(1, 1)); - vel34 *= flux[2] / (2 * interactionVolume.getFaceArea(2, 0)); - vel32 *= flux[1] / (2 * interactionVolume.getFaceArea(2, 1)); - vel41 *= flux[3] / (2 * interactionVolume.getFaceArea(3, 0)); - vel43 *= flux[2] / (2 * interactionVolume.getFaceArea(3, 1)); - - Scalar lambdaT12 = lambda12Upw[wPhaseIdx] + lambda12Upw[nPhaseIdx]; - Scalar lambdaT14 = lambda14Upw[wPhaseIdx] + lambda14Upw[nPhaseIdx]; - Scalar lambdaT32 = lambda32Upw[wPhaseIdx] + lambda32Upw[nPhaseIdx]; - Scalar lambdaT34 = lambda34Upw[wPhaseIdx] + lambda34Upw[nPhaseIdx]; - Scalar fracFlow12 = (lambdaT12 > threshold_) ? lambda12Upw[i] / (lambdaT12) : 0.0; - Scalar fracFlow14 = (lambdaT14 > threshold_) ? lambda14Upw[i] / (lambdaT14) : 0.0; - Scalar fracFlow32 = (lambdaT32 > threshold_) ? lambda32Upw[i] / (lambdaT32) : 0.0; - Scalar fracFlow34 = (lambdaT34 > threshold_) ? lambda34Upw[i] / (lambdaT34) : 0.0; - - vel12 *= fracFlow12; - vel14 *= fracFlow14; - vel23 *= fracFlow32; - vel21 *= fracFlow12; - vel34 *= fracFlow34; - vel32 *= fracFlow32; - vel41 *= fracFlow14; - vel43 *= fracFlow34; - - if (this->innerBoundaryVolumeFaces_[globalIdx1][interactionVolume.getIndexOnElement(0, 0)]) - { - vel12 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx1][interactionVolume.getIndexOnElement(0, 1)]) - { - vel14 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx2][interactionVolume.getIndexOnElement(1, 0)]) - { - vel23 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx2][interactionVolume.getIndexOnElement(1, 1)]) - { - vel21 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx3][interactionVolume.getIndexOnElement(2, 0)]) - { - vel34 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx3][interactionVolume.getIndexOnElement(2, 1)]) - { - vel32 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx4][interactionVolume.getIndexOnElement(3, 0)]) - { - vel41 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx4][interactionVolume.getIndexOnElement(3, 1)]) - { - vel43 *= 2; - } + //calculate unit distVec + distVec /= dist; + Scalar areaScaling = (unitOuterNormal * distVec); + //this treatment of g allows to account for gravity flux through faces where the face normal has no z component (e.g. parallelepiped grids) + Scalar gravityTermW = (problem_.gravity() * distVec) * density_[wPhaseIdx] * areaScaling; + Scalar gravityTermNw = (problem_.gravity() * distVec) * density_[nPhaseIdx] * areaScaling; - //store velocities - cellData1.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(0, 0), vel12); - cellData1.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(0, 1), vel14); - cellData2.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(1, 0), vel23); - cellData2.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(1, 1), vel21); - cellData3.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(2, 0), vel34); - cellData3.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(2, 1), vel32); - cellData4.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(3, 0), vel41); - cellData4.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(3, 1), vel43); - } - //set velocity marker - cellData1.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(0, 0)); - cellData1.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(0, 1)); - cellData2.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(1, 0)); - cellData2.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(1, 1)); - cellData3.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(2, 0)); - cellData3.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(2, 1)); - cellData4.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(3, 0)); - cellData4.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(3, 1)); + //calculate velocity depending on the pressure used -> use pc = pn - pw + switch (pressureType_) + { + case pw: + { + velocityW *= lambdaW * scalarPerm * ((cellData.pressure(wPhaseIdx) - pressBound) / dist + gravityTermW); + velocityNw *= lambdaNw * scalarPerm * ((cellData.pressure(wPhaseIdx) - pressBound) / dist + gravityTermNw) + + 0.5 * (lambdaNwI + lambdaNwBound) * scalarPerm * (pcI - pcBound) / dist; + break; } - - // at least one face on boundary! - else + case pn: { - for (int elemIdx = 0; elemIdx < 2 * dim; elemIdx++) - { - bool isOutside = false; - for (int faceIdx = 0; faceIdx < dim; faceIdx++) - { - int intVolFaceIdx = interactionVolume.getFaceIndexFromSubVolume(elemIdx, faceIdx); - if (interactionVolume.isOutsideFace(intVolFaceIdx)) - { - isOutside = true; - break; - } - } - if (isOutside) - { - continue; - } - - ElementPointer & elementPointer = interactionVolume.getSubVolumeElement(elemIdx); + velocityW *= lambdaW * scalarPerm * ((cellData.pressure(nPhaseIdx) - pressBound) / dist + gravityTermW) + - 0.5 * (lambdaWI + lambdaWBound) * scalarPerm * (pcI - pcBound) / dist; + velocityNw *= lambdaNw * scalarPerm * ((cellData.pressure(nPhaseIdx) - pressBound) / dist + gravityTermNw); + break; + } + } - // get global coordinate of cell centers - const GlobalPosition& globalPos = elementPointer->geometry().center(); + //store velocities + cellData.fluxData().setVelocity(wPhaseIdx, isIndex, velocityW); + cellData.fluxData().setVelocity(nPhaseIdx, isIndex, velocityNw); + cellData.fluxData().setVelocityMarker(isIndex); - // cell index - int globalIdx = problem_.variables().index(*elementPointer); + } //end dirichlet boundary - //get the cell Data - CellData& cellData = problem_.variables().cellData(globalIdx); + else if (bcType.isNeumann(pressEqIdx)) + { + problem_.neumann(boundValues, intersection); - //permeability vector at boundary - DimMatrix permeability(problem_.spatialParams().intrinsicPermeability(*elementPointer)); + Dune::FieldVector<Scalar, dimWorld> velocityW(unitOuterNormal); + Dune::FieldVector<Scalar, dimWorld> velocityNw(unitOuterNormal); - //get mobilities of the phases - Dune::FieldVector<Scalar, numPhases> lambda(cellData.mobility(wPhaseIdx)); - lambda[nPhaseIdx] = cellData.mobility(nPhaseIdx); + velocityW *= boundValues[wPhaseIdx]; + velocityNw *= boundValues[nPhaseIdx]; - for (int faceIdx = 0; faceIdx < dim; faceIdx++) - { - int intVolFaceIdx = interactionVolume.getFaceIndexFromSubVolume(elemIdx, faceIdx); + velocityW /= density_[wPhaseIdx]; + velocityNw /= density_[nPhaseIdx]; - if (interactionVolume.isBoundaryFace(intVolFaceIdx)) - { - if (interactionVolume.getBoundaryType(intVolFaceIdx).isDirichlet(pressEqIdx)) - { - int boundaryFaceIdx = interactionVolume.getIndexOnElement(elemIdx, faceIdx); - - const ReferenceElement& referenceElement = ReferenceElements::general( - elementPointer->geometry().type()); - - const LocalPosition& localPos = referenceElement.position(boundaryFaceIdx, 1); - - const GlobalPosition& globalPosFace = elementPointer->geometry().global(localPos); - - DimVector distVec(globalPosFace - globalPos); - Scalar dist = distVec.two_norm(); - DimVector unitDistVec(distVec); - unitDistVec /= dist; - - // get pc and lambda at the boundary - Scalar satWBound = cellData.saturation(wPhaseIdx); - //check boundary sat at face 1 - if (interactionVolume.getBoundaryType(intVolFaceIdx).isDirichlet(satEqIdx)) - { - Scalar satBound = interactionVolume.getDirichletValues(intVolFaceIdx)[saturationIdx]; - switch (saturationType_) - { - case sw: - { - satWBound = satBound; - break; - } - case sn: - { - satWBound = 1 - satBound; - break; - } - } - - } - - Scalar pcBound = MaterialLaw::pc( - problem_.spatialParams().materialLawParams(*elementPointer), satWBound); - - Scalar gravityDiffBound = (problem_.bBoxMax() - globalPosFace) * problem_.gravity() - * (density_[nPhaseIdx] - density_[wPhaseIdx]); - - pcBound += gravityDiffBound; - - Dune::FieldVector<Scalar, numPhases> lambdaBound( - MaterialLaw::krw(problem_.spatialParams().materialLawParams(*elementPointer), - satWBound)); - lambdaBound[nPhaseIdx] = MaterialLaw::krn( - problem_.spatialParams().materialLawParams(*elementPointer), satWBound); - lambdaBound[wPhaseIdx] /= viscosity_[wPhaseIdx]; - lambdaBound[nPhaseIdx] /= viscosity_[nPhaseIdx]; - - Scalar gdeltaZ = (problem_.bBoxMax()-globalPosFace) * gravity_; - Scalar potentialBoundW = interactionVolume.getDirichletValues(intVolFaceIdx)[pressureIdx] + density_[wPhaseIdx]*gdeltaZ; - Scalar potentialBoundNw = potentialBoundW; - - //calculate potential gradients - switch (pressureType_) - { - case pw: - { - potentialBoundNw += pcBound; - break; - } - case pn: - { - //calculate potential gradients - potentialBoundW -= pcBound; - break; - } - } - - Scalar potentialDiffW = (cellData.potential(wPhaseIdx) - potentialBoundW) / dist; - Scalar potentialDiffNw = (cellData.potential(nPhaseIdx) - potentialBoundNw) / dist; - - //store potentials for further calculations (saturation, ...) - cellData.fluxData().addUpwindPotential(wPhaseIdx, boundaryFaceIdx, potentialDiffW); - cellData.fluxData().addUpwindPotential(nPhaseIdx, boundaryFaceIdx, potentialDiffNw); - - //calculated phase velocities from advective velocities -> capillary pressure velocity already added in pressure part! - DimVector velocityW(0); - DimVector velocityNw(0); - - // calculate capillary pressure gradient - DimVector pressGradient = unitDistVec; - pressGradient *= (cellData.potential(wPhaseIdx) - potentialBoundW) / dist; - permeability.mv(pressGradient, velocityW); - - pressGradient = unitDistVec; - pressGradient *= (cellData.potential(nPhaseIdx) - potentialBoundNw) / dist; - permeability.mv(pressGradient, velocityNw); - - velocityW *= (potentialDiffW >= 0.) ? lambda[wPhaseIdx] : lambdaBound[wPhaseIdx]; - velocityNw *= (potentialDiffNw >= 0.) ? lambda[nPhaseIdx] : lambdaBound[nPhaseIdx]; - - //velocity is calculated from two vertices of one intersection! - velocityW *= 0.5; - velocityNw *= 0.5; - - //store velocities - velocityW += cellData.fluxData().velocity(wPhaseIdx, boundaryFaceIdx); - velocityNw += cellData.fluxData().velocity(nPhaseIdx, boundaryFaceIdx); - cellData.fluxData().setVelocity(wPhaseIdx, boundaryFaceIdx, velocityW); - cellData.fluxData().setVelocity(nPhaseIdx, boundaryFaceIdx, velocityNw); - cellData.fluxData().setVelocityMarker(boundaryFaceIdx); - - } - else if (interactionVolume.getBoundaryType(intVolFaceIdx).isNeumann(pressEqIdx)) - { - int boundaryFaceIdx = interactionVolume.getIndexOnElement(elemIdx, faceIdx); - - const ReferenceElement& referenceElement = ReferenceElements::general( - elementPointer->geometry().type()); - - const LocalPosition& localPos = referenceElement.position(boundaryFaceIdx, 1); - - const GlobalPosition& globalPosFace = elementPointer->geometry().global(localPos); - - DimVector distVec(globalPosFace - globalPos); - Scalar dist = distVec.two_norm(); - DimVector unitDistVec(distVec); - unitDistVec /= dist; - - // get neumann boundary value - PrimaryVariables boundValues(interactionVolume.getNeumannValues(intVolFaceIdx)); - - boundValues[wPhaseIdx] /= density_[wPhaseIdx]; - boundValues[nPhaseIdx] /= density_[nPhaseIdx]; - - DimVector velocityW(unitDistVec); - DimVector velocityNw(unitDistVec); - - velocityW *= boundValues[wPhaseIdx] / (2 * interactionVolume.getFaceArea(elemIdx, faceIdx)); - velocityNw *= boundValues[nPhaseIdx] - / (2 * interactionVolume.getFaceArea(elemIdx, faceIdx)); - - //store potentials for further calculations (saturation, ...) - cellData.fluxData().addUpwindPotential(wPhaseIdx, boundaryFaceIdx, boundValues[wPhaseIdx]); - cellData.fluxData().addUpwindPotential(nPhaseIdx, boundaryFaceIdx, boundValues[nPhaseIdx]); - - //store velocities - velocityW += cellData.fluxData().velocity(wPhaseIdx, boundaryFaceIdx); - velocityNw += cellData.fluxData().velocity(nPhaseIdx, boundaryFaceIdx); - cellData.fluxData().setVelocity(wPhaseIdx, boundaryFaceIdx, velocityW); - cellData.fluxData().setVelocity(nPhaseIdx, boundaryFaceIdx, velocityNw); - cellData.fluxData().setVelocityMarker(boundaryFaceIdx); - } - else - { - DUNE_THROW(Dune::NotImplemented, - "No valid boundary condition type defined for pressure equation!"); - } - } - } - } - - } // end boundaries - - } // end vertex iterator + //store potential gradients for further calculations + cellData.fluxData().setUpwindPotential(wPhaseIdx, isIndex, boundValues[wPhaseIdx]); + cellData.fluxData().setUpwindPotential(nPhaseIdx, isIndex, boundValues[nPhaseIdx]); -// } - return; -} // end method calcTotalVelocity + cellData.fluxData().setVelocity(wPhaseIdx, isIndex, velocityW); + cellData.fluxData().setVelocity(nPhaseIdx, isIndex, velocityNw); + cellData.fluxData().setVelocityMarker(isIndex); + } //end neumann boundary + else + { + DUNE_THROW(Dune::NotImplemented, "No valid boundary condition type defined for pressure equation!"); + } +} } // end of Dune namespace diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressurevelocity2padaptive.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressurevelocity2padaptive.hh index e1ebac067681653c203a019371dbe26f2ac3da3c..ebb22295398e45f2174687217e5d281959379eb6 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressurevelocity2padaptive.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressurevelocity2padaptive.hh @@ -19,6 +19,7 @@ #define DUMUX_MPFAL2DPRESSUREVELOCITIES2P_ADAPTIVE_HH #include "fvmpfal2dpressure2padaptive.hh" +#include "fvmpfal2dvelocity2padaptive.hh" /** * @file @@ -63,6 +64,10 @@ template<class TypeTag> class FvMpfaL2dPressureVelocity2pAdaptive: public FvMpfa typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, CellData) CellData; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP(TypeTag, SolutionTypes) SolutionTypes; + typedef typename SolutionTypes::PrimaryVariables PrimaryVariables; #if DUNE_VERSION_NEWER(DUNE_GRID, 2, 3) typedef typename Dune::ReferenceElements<Scalar, dim> ReferenceElements; @@ -80,17 +85,13 @@ template<class TypeTag> class FvMpfaL2dPressureVelocity2pAdaptive: public FvMpfa typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; - typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; - typedef typename GET_PROP(TypeTag, SolutionTypes) SolutionTypes; - typedef typename SolutionTypes::PrimaryVariables PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, CellData) CellData; - typedef typename GridView::Grid Grid; typedef typename GridView::IndexSet IndexSet; typedef typename GridView::template Codim<0>::Iterator ElementIterator; typedef typename GridView::template Codim<dim>::Iterator VertexIterator; typedef typename GridView::IntersectionIterator IntersectionIterator; typedef typename Grid::template Codim<0>::EntityPointer ElementPointer; + typedef typename GridView::Intersection Intersection; typedef typename Grid::template Codim<0>::Entity::Geometry Geometry; #if DUNE_VERSION_NEWER(DUNE_GRID, 2, 3) @@ -119,23 +120,6 @@ template<class TypeTag> class FvMpfaL2dPressureVelocity2pAdaptive: public FvMpfa numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; - enum - { - globalCorner = 2, - globalEdge = 3, - neumannNeumann = 0, - dirichletDirichlet = 1, - dirichletNeumann = 2, - neumannDirichlet = 3 - }; - enum - { - leftTriangle = ParentType::leftTriangle, - noTransmissibility = ParentType::noTransmissibility, - rightTriangle = ParentType::rightTriangle - }; - - typedef Dune::FieldVector<Scalar, dim> LocalPosition; typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; typedef Dune::FieldVector<Scalar, dim> DimVector; @@ -146,32 +130,31 @@ public: * \param problem A problem class object */ FvMpfaL2dPressureVelocity2pAdaptive(Problem& problem) : - ParentType(problem), problem_(problem), gravity_(problem.gravity()) + ParentType(problem), problem_(problem), velocity_(problem) { density_[wPhaseIdx] = 0.; density_[nPhaseIdx] = 0.; viscosity_[wPhaseIdx] = 0.; viscosity_[nPhaseIdx] = 0.; - vtkOutputLevel_ = GET_PARAM_FROM_GROUP(TypeTag, int, Vtk, OutputLevel); + calcVelocityInTransport_ = GET_PARAM_FROM_GROUP(TypeTag, bool, MPFA, CalcVelocityInTransport); } //Calculates the velocities at all cell-cell interfaces. void calculateVelocity(); + // Calculates the velocity at a cell-cell interface. + void calculateVelocity(const Intersection&, CellData&); + void calculateVelocityOnBoundary(const Intersection& intersection, CellData& cellData); + void updateVelocity() { this->updateMaterialLaws(); - //reset velocities - int size = problem_.gridView().size(0); - for (int i = 0; i < size; i++) - { - CellData& cellData = problem_.variables().cellData(i); - cellData.fluxData().resetVelocity(); - } + this->storePressureSolution(); - calculateVelocity(); + if (!calculateVelocityInTransport()) + calculateVelocity(); } /*! \brief Initializes pressure and velocity @@ -180,8 +163,6 @@ public: */ void initialize() { - ParentType::initialize(); - ElementIterator element = problem_.gridView().template begin<0>(); FluidState fluidState; fluidState.setPressure(wPhaseIdx, problem_.referencePressure(*element)); @@ -194,7 +175,10 @@ public: viscosity_[wPhaseIdx] = FluidSystem::viscosity(fluidState, wPhaseIdx); viscosity_[nPhaseIdx] = FluidSystem::viscosity(fluidState, nPhaseIdx); - calculateVelocity(); + ParentType::initialize(); + velocity_.initialize(); + if (!calculateVelocityInTransport()) + calculateVelocity(); return; } @@ -207,10 +191,17 @@ public: void update() { ParentType::update(); + if (!calculateVelocityInTransport()) + calculateVelocity(); + } - calculateVelocity(); - - return; + /*! \brief Indicates if velocity is reconstructed in the pressure step or in the transport step + * + * Returns true (In the standard finite volume discretization the velocity is calculated during the saturation transport.) + */ + bool calculateVelocityInTransport() + { + return calcVelocityInTransport_; } /*! \brief Adds velocity output to the output file @@ -227,85 +218,17 @@ public: void addOutputVtkFields(MultiWriter &writer) { ParentType::addOutputVtkFields(writer); - - if (vtkOutputLevel_ > 0) - { - Dune::BlockVector < DimVector > &velocityWetting = *(writer.template allocateManagedBuffer< - Scalar, dim>(problem_.gridView().size(0))); - Dune::BlockVector < DimVector > &velocityNonwetting = - *(writer.template allocateManagedBuffer<Scalar, dim>(problem_.gridView().size(0))); - - // compute update vector - ElementIterator eEndIt = problem_.gridView().template end<0>(); - for (ElementIterator eIt = problem_.gridView().template begin<0>(); eIt != eEndIt; ++eIt) - { - // cell index - int globalIdx = problem_.variables().index(*eIt); - - CellData& cellData = problem_.variables().cellData(globalIdx); - - Dune::FieldVector < Scalar, 2 * dim > fluxW(0); - Dune::FieldVector < Scalar, 2 * dim > fluxNw(0); - // run through all intersections with neighbors and boundary - IntersectionIterator isEndIt = problem_.gridView().iend(*eIt); - for (IntersectionIterator isIt = problem_.gridView().ibegin(*eIt); isIt != isEndIt; ++isIt) - { - int isIndex = isIt->indexInInside(); - - fluxW[isIndex] += isIt->geometry().volume() - * (isIt->centerUnitOuterNormal() * cellData.fluxData().velocity(wPhaseIdx, isIndex)); - fluxNw[isIndex] += - isIt->geometry().volume() - * (isIt->centerUnitOuterNormal() - * cellData.fluxData().velocity(nPhaseIdx, isIndex)); - } - - DimVector refVelocity(0); - for (int i = 0; i < dim; i++) - refVelocity[i] = 0.5 * (fluxW[2*i + 1] - fluxW[2*i]); - - const DimVector localPos = - ReferenceElements::general(eIt->geometry().type()).position(0, 0); - - // get the transposed Jacobian of the element mapping - const JacobianTransposed jacobianT = eIt->geometry().jacobianTransposed(localPos); - - // calculate the element velocity by the Piola transformation - DimVector elementVelocity(0); - jacobianT.umtv(refVelocity, elementVelocity); - elementVelocity /= eIt->geometry().integrationElement(localPos); - - velocityWetting[globalIdx] = elementVelocity; - - refVelocity = 0; - for (int i = 0; i < dim; i++) - refVelocity[i] = 0.5 * (fluxNw[2*i + 1] - fluxNw[2*i]); - - // calculate the element velocity by the Piola transformation - elementVelocity = 0; - jacobianT.umtv(refVelocity, elementVelocity); - elementVelocity /= eIt->geometry().integrationElement(localPos); - - velocityNonwetting[globalIdx] = elementVelocity; - } - - writer.attachCellData(velocityWetting, "wetting-velocity", dim); - writer.attachCellData(velocityNonwetting, "non-wetting-velocity", dim); - } - return; + velocity_.addOutputVtkFields(writer); } private: Problem& problem_; - const GlobalPosition& gravity_; //!< vector including the gravity constant + FvMpfaL2dVelocity2pAdaptive<TypeTag> velocity_; Scalar density_[numPhases]; Scalar viscosity_[numPhases]; + bool calcVelocityInTransport_; - int vtkOutputLevel_; - - static constexpr Scalar threshold_ = 1e-15; - static const int velocityType_ = GET_PROP_VALUE(TypeTag, VelocityFormulation); //!< gives kind of velocity used (\f$ 0 = v_w\f$, \f$ 1 = v_n\f$, \f$ 2 = v_t\f$) static const int pressureType_ = GET_PROP_VALUE(TypeTag, PressureFormulation); //!< gives kind of pressure used (\f$ 0 = p_w\f$, \f$ 1 = p_n\f$, \f$ 2 = p_{global}\f$) static const int saturationType_ = GET_PROP_VALUE(TypeTag, SaturationFormulation); //!< gives kind of saturation used (\f$ 0 = S_w\f$, \f$ 1 = S_n\f$) }; @@ -319,26 +242,6 @@ private: template<class TypeTag> void FvMpfaL2dPressureVelocity2pAdaptive<TypeTag>::calculateVelocity() { -// std::cout<<"velocityW = \n"; -// for (int i = 0; i<problem_.gridView().size(0);i++) -// { -// std::cout<<i<<": "; -// for (int j=0; j<4; j++) -// { -// std::cout<<" ("<<j<<") "<<problem_.variables().cellData(i).fluxData().velocity(wPhaseIdx, j); -// } -// std::cout<<"\n"; -// } -// std::cout<<"velocityNw = \n"; -// for (int i = 0; i<problem_.gridView().size(0);i++) -// { -// std::cout<<i<<": "; -// for (int j=0; j<4; j++) -// { -// std::cout<<" ("<<j<<") "<<problem_.variables().cellData(i).fluxData().velocity(nPhaseIdx, j); -// } -// std::cout<<"\n"; -// } // run through all elements VertexIterator vEndIt = problem_.gridView().template end<dim>(); for (VertexIterator vIt = problem_.gridView().template begin<dim>(); vIt != vEndIt; ++vIt) @@ -356,11 +259,6 @@ void FvMpfaL2dPressureVelocity2pAdaptive<TypeTag>::calculateVelocity() ElementPointer & elementPointer3 = interactionVolume.getSubVolumeElement(2); ElementPointer & elementPointer4 = interactionVolume.getSubVolumeElement(3); - int level1 = elementPointer1->level(); - int level2 = elementPointer2->level(); - int level3 = elementPointer3->level(); - int level4 = elementPointer4->level(); - // cell index int globalIdx1 = problem_.variables().index(*elementPointer1); int globalIdx2 = problem_.variables().index(*elementPointer2); @@ -373,426 +271,157 @@ void FvMpfaL2dPressureVelocity2pAdaptive<TypeTag>::calculateVelocity() CellData& cellData3 = problem_.variables().cellData(globalIdx3); CellData& cellData4 = problem_.variables().cellData(globalIdx4); - // get pressure values - Dune::FieldVector < Scalar, 2 * dim > potW(0); - Dune::FieldVector < Scalar, 2 * dim > potNw(0); - - potW[0] = cellData1.potential(wPhaseIdx); - potW[1] = cellData2.potential(wPhaseIdx); - potW[2] = cellData3.potential(wPhaseIdx); - potW[3] = cellData4.potential(wPhaseIdx); - - potNw[0] = cellData1.potential(nPhaseIdx); - potNw[1] = cellData2.potential(nPhaseIdx); - potNw[2] = cellData3.potential(nPhaseIdx); - potNw[3] = cellData4.potential(nPhaseIdx); - - //get mobilities of the phases - Dune::FieldVector<Scalar, numPhases> lambda1(cellData1.mobility(wPhaseIdx)); - lambda1[nPhaseIdx] = cellData1.mobility(nPhaseIdx); - - //compute total mobility of cell 1 - Scalar lambdaTotal1 = lambda1[wPhaseIdx] + lambda1[nPhaseIdx]; - - //get mobilities of the phases - Dune::FieldVector<Scalar, numPhases> lambda2(cellData2.mobility(wPhaseIdx)); - lambda2[nPhaseIdx] = cellData2.mobility(nPhaseIdx); - - //compute total mobility of cell 1 - Scalar lambdaTotal2 = lambda2[wPhaseIdx] + lambda2[nPhaseIdx]; - - //get mobilities of the phases - Dune::FieldVector<Scalar, numPhases> lambda3(cellData3.mobility(wPhaseIdx)); - lambda3[nPhaseIdx] = cellData3.mobility(nPhaseIdx); - - //compute total mobility of cell 1 - Scalar lambdaTotal3 = lambda3[wPhaseIdx] + lambda3[nPhaseIdx]; + velocity_.calculateInnerInteractionVolumeVelocity(interactionVolume, cellData1, cellData2, cellData3, cellData4, this->innerBoundaryVolumeFaces_); - //get mobilities of the phases - Dune::FieldVector<Scalar, numPhases> lambda4(cellData4.mobility(wPhaseIdx)); - lambda4[nPhaseIdx] = cellData4.mobility(nPhaseIdx); - - //compute total mobility of cell 1 - Scalar lambdaTotal4 = lambda4[wPhaseIdx] + lambda4[nPhaseIdx]; - - std::vector < DimVector > lambda(2 * dim); - - lambda[0][0] = lambdaTotal1; - lambda[0][1] = lambdaTotal1; - lambda[1][0] = lambdaTotal2; - lambda[1][1] = lambdaTotal2; - lambda[2][0] = lambdaTotal3; - lambda[2][1] = lambdaTotal3; - lambda[3][0] = lambdaTotal4; - lambda[3][1] = lambdaTotal4; - - Scalar potentialDiffW12 = 0; - Scalar potentialDiffW14 = 0; - Scalar potentialDiffW32 = 0; - Scalar potentialDiffW34 = 0; + } + else if (interactionVolume.getElementNumber() == 3) + { + ElementPointer & elementPointer1 = interactionVolume.getSubVolumeElement(0); + ElementPointer & elementPointer2 = interactionVolume.getSubVolumeElement(1); + ElementPointer & elementPointer4 = interactionVolume.getSubVolumeElement(3); - Scalar potentialDiffNw12 = 0; - Scalar potentialDiffNw14 = 0; - Scalar potentialDiffNw32 = 0; - Scalar potentialDiffNw34 = 0; + // cell index + int globalIdx1 = problem_.variables().index(*elementPointer1); + int globalIdx2 = problem_.variables().index(*elementPointer2); + int globalIdx4 = problem_.variables().index(*elementPointer4); - //flux vector - Dune::FieldVector<Scalar, 2 * dim> fluxW(0); - Dune::FieldVector<Scalar, 2 * dim> fluxNw(0); + //get the cell Data + CellData& cellData1 = problem_.variables().cellData(globalIdx1); + CellData& cellData2 = problem_.variables().cellData(globalIdx2); + CellData& cellData4 = problem_.variables().cellData(globalIdx4); - Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> T(0); - DimVector Tu(0); - Dune::FieldVector<Scalar, 2 * dim - dim + 1> u(0); + velocity_.calculateHangingNodeInteractionVolumeVelocity(interactionVolume, cellData1, cellData2, cellData4, this->innerBoundaryVolumeFaces_); - int transmissibilityType = this->calculateTransmissibility(T, interactionVolume, lambda, 0, 1, 2, 3); + } + else + { + DUNE_THROW(Dune::NotImplemented, "Unknown interactionvolume type!"); + } + } - if (transmissibilityType == rightTriangle) + // at least one face on boundary! + else + { + for (int elemIdx = 0; elemIdx < 2 * dim; elemIdx++) + { + bool isOutside = false; + for (int faceIdx = 0; faceIdx < dim; faceIdx++) { - u[0] = potW[1]; - u[1] = potW[2]; - u[2] = potW[0]; - - T.mv(u, Tu); - - fluxW[0] = Tu[1]; - potentialDiffW12 = Tu[1]; - - u[0] = potNw[1]; - u[1] = potNw[2]; - u[2] = potNw[0]; - - T.mv(u, Tu); - - fluxNw[0] = Tu[1]; - potentialDiffNw12 = Tu[1]; + int intVolFaceIdx = interactionVolume.getFaceIndexFromSubVolume(elemIdx, faceIdx); + if (interactionVolume.isOutsideFace(intVolFaceIdx)) + { + isOutside = true; + break; + } } - else if (transmissibilityType == leftTriangle) + if (isOutside) { - u[0] = potW[0]; - u[1] = potW[3]; - u[2] = potW[1]; - - T.mv(u, Tu); - - fluxW[0] = Tu[1]; - potentialDiffW12 = Tu[1]; - - u[0] = potNw[0]; - u[1] = potNw[3]; - u[2] = potNw[1]; - - T.mv(u, Tu); - - fluxNw[0] = Tu[1]; - potentialDiffNw12 = Tu[1]; + continue; } + ElementPointer & elementPointer = interactionVolume.getSubVolumeElement(elemIdx); - transmissibilityType = this->calculateTransmissibility(T, interactionVolume, lambda, 1, 2, 3, 0); - - if (transmissibilityType == rightTriangle) - { - u[0] = potW[2]; - u[1] = potW[3]; - u[2] = potW[1]; - - T.mv(u, Tu); + // cell index + int globalIdx = problem_.variables().index(*elementPointer); + //get the cell Data + CellData& cellData = problem_.variables().cellData(globalIdx); - fluxW[1] = Tu[1]; - potentialDiffW32 = -Tu[1]; + velocity_.calculateBoundaryInteractionVolumeVelocity(interactionVolume, cellData, elemIdx); + } - u[0] = potNw[2]; - u[1] = potNw[3]; - u[2] = potNw[1]; + } // end boundaries - T.mv(u, Tu); + } // end vertex iterator + return; +} // end method calcTotalVelocity - fluxNw[1] = Tu[1]; - potentialDiffNw32 = -Tu[1]; - } - else if (transmissibilityType == leftTriangle) - { - u[0] = potW[1]; - u[1] = potW[0]; - u[2] = potW[2]; +template<class TypeTag> +void FvMpfaL2dPressureVelocity2pAdaptive<TypeTag>::calculateVelocity(const Intersection& intersection, CellData& cellData) +{ + int numVertices = intersection.geometry().corners(); - T.mv(u, Tu); + ElementPointer elementPtrI = intersection.inside(); + ElementPointer elementPtrJ = intersection.outside(); - fluxW[1] = Tu[1]; - potentialDiffW32 = -Tu[1]; + int levelI = elementPtrI->level(); + int levelJ = elementPtrJ->level(); - u[0] = potNw[1]; - u[1] = potNw[0]; - u[2] = potNw[2]; + int globalIdxI = problem_.variables().index(*elementPtrI); + int globalIdxJ = problem_.variables().index(*elementPtrJ); - T.mv(u, Tu); + CellData& cellDataJ = problem_.variables().cellData(globalIdxJ); - fluxNw[1] = Tu[1]; - potentialDiffNw32 = -Tu[1]; - } + const ReferenceElement& referenceElement = ReferenceElements::general(elementPtrI->geometry().type()); - transmissibilityType = this->calculateTransmissibility(T, interactionVolume, lambda, 2, 3, 0, 1); + int indexInInside = intersection.indexInInside(); + int indexInOutside = intersection.indexInOutside(); - if (transmissibilityType == rightTriangle) - { - u[0] = potW[3]; - u[1] = potW[0]; - u[2] = potW[2]; + int faceIdx = indexInInside; - T.mv(u, Tu); + if (levelI < levelJ) + faceIdx = indexInOutside; - fluxW[2] = Tu[1]; - potentialDiffW34 = Tu[1]; + std::vector<CellData> cellDataTemp(0); - u[0] = potNw[3]; - u[1] = potNw[0]; - u[2] = potNw[2]; + if (levelI != levelJ) + { + DimVector vel(0); + cellData.fluxData().setVelocity(wPhaseIdx, indexInInside, vel); + cellData.fluxData().setVelocity(nPhaseIdx, indexInInside, vel); + cellData.fluxData().setUpwindPotential(wPhaseIdx, indexInInside, 0); + cellData.fluxData().setUpwindPotential(nPhaseIdx, indexInInside, 0); + + cellDataJ.fluxData().setVelocity(wPhaseIdx, indexInOutside, vel); + cellDataJ.fluxData().setVelocity(nPhaseIdx, indexInOutside, vel); + cellDataJ.fluxData().setUpwindPotential(wPhaseIdx, indexInOutside, 0); + cellDataJ.fluxData().setUpwindPotential(nPhaseIdx, indexInOutside, 0); + } - T.mv(u, Tu); + for (int vIdx = 0; vIdx < numVertices; vIdx++) + { + int localVertIdx = referenceElement.subEntity(faceIdx, dim - 1, vIdx, dim); - fluxNw[2] = Tu[1]; - potentialDiffNw34 = Tu[1]; - } - else if (transmissibilityType == leftTriangle) + int globalVertIdx = 0; + if (levelI >= levelJ) { - u[0] = potW[2]; - u[1] = potW[1]; - u[2] = potW[3]; - - T.mv(u, Tu); - - fluxW[2] = Tu[1]; - potentialDiffW34 = Tu[1]; - - u[0] = potNw[2]; - u[1] = potNw[1]; - u[2] = potNw[3]; - - T.mv(u, Tu); - - fluxNw[2] = Tu[1]; - potentialDiffNw34 = Tu[1]; + globalVertIdx = problem_.variables().index( + *((*elementPtrI).template subEntity < dim > (localVertIdx))); } - - transmissibilityType = this->calculateTransmissibility(T, interactionVolume, lambda, 3, 0, 1, 2); - - if (transmissibilityType == rightTriangle) + else { - u[0] = potW[0]; - u[1] = potW[1]; - u[2] = potW[3]; - - T.mv(u, Tu); - - fluxW[3] = Tu[1]; - potentialDiffW14 = -Tu[1]; - - u[0] = potNw[0]; - u[1] = potNw[1]; - u[2] = potNw[3]; - - T.mv(u, Tu); - - fluxNw[3] = Tu[1]; - potentialDiffNw14 = -Tu[1]; + globalVertIdx = problem_.variables().index( + *((*elementPtrJ).template subEntity < dim > (localVertIdx))); } - else if (transmissibilityType == leftTriangle) - { - u[0] = potW[3]; - u[1] = potW[2]; - u[2] = potW[0]; - T.mv(u, Tu); - - fluxW[3] = Tu[1]; - potentialDiffW14 = -Tu[1]; - - u[0] = potNw[3]; - u[1] = potNw[2]; - u[2] = potNw[0]; + InteractionVolume& interactionVolume = this->interactionVolumes_[globalVertIdx]; - T.mv(u, Tu); + if (interactionVolume.isInnerVolume()) + { + // cell index vector + std::vector<int> globalIdx(0); - fluxNw[3] = Tu[1]; - potentialDiffNw14 = -Tu[1]; - } + if (interactionVolume.getElementNumber() == 4) + { + ElementPointer & elementPointer1 = interactionVolume.getSubVolumeElement(0); + ElementPointer & elementPointer2 = interactionVolume.getSubVolumeElement(1); + ElementPointer & elementPointer3 = interactionVolume.getSubVolumeElement(2); + ElementPointer & elementPointer4 = interactionVolume.getSubVolumeElement(3); - //store potentials for further calculations (saturation, ...) - cellData1.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(0, 0), potentialDiffW12); - cellData1.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(0, 0), potentialDiffNw12); - cellData1.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(0, 1), potentialDiffW14); - cellData1.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(0, 1), potentialDiffNw14); - cellData2.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(1, 0), -potentialDiffW32); - cellData2.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(1, 0), -potentialDiffNw32); - cellData2.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(1, 1), -potentialDiffW12); - cellData2.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(1, 1), -potentialDiffNw12); - cellData3.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(2, 0), potentialDiffW34); - cellData3.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(2, 0), potentialDiffNw34); - cellData3.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(2, 1), potentialDiffW32); - cellData3.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(2, 1), potentialDiffNw32); - cellData4.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(3, 0), -potentialDiffW14); - cellData4.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(3, 0), -potentialDiffNw14); - cellData4.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(3, 1), -potentialDiffW34); - cellData4.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(3, 1), -potentialDiffNw34); - - //compute mobilities of face 1 - Dune::FieldVector<Scalar, numPhases> lambda12Upw(0.0); - lambda12Upw[wPhaseIdx] = (potentialDiffW12 >= 0) ? lambda1[wPhaseIdx] : lambda2[wPhaseIdx]; - lambda12Upw[nPhaseIdx] = (potentialDiffNw12 >= 0) ? lambda1[nPhaseIdx] : lambda2[nPhaseIdx]; - - //compute mobilities of face 4 - Dune::FieldVector<Scalar, numPhases> lambda14Upw(0.0); - lambda14Upw[wPhaseIdx] = (potentialDiffW14 >= 0) ? lambda1[wPhaseIdx] : lambda4[wPhaseIdx]; - lambda14Upw[nPhaseIdx] = (potentialDiffNw14 >= 0) ? lambda1[nPhaseIdx] : lambda4[nPhaseIdx]; - - //compute mobilities of face 2 - Dune::FieldVector<Scalar, numPhases> lambda32Upw(0.0); - lambda32Upw[wPhaseIdx] = (potentialDiffW32 >= 0) ? lambda3[wPhaseIdx] : lambda2[wPhaseIdx]; - lambda32Upw[nPhaseIdx] = (potentialDiffNw32 >= 0) ? lambda3[nPhaseIdx] : lambda2[nPhaseIdx]; - - //compute mobilities of face 3 - Dune::FieldVector<Scalar, numPhases> lambda34Upw(0.0); - lambda34Upw[wPhaseIdx] = (potentialDiffW34 >= 0) ? lambda3[wPhaseIdx] : lambda4[wPhaseIdx]; - lambda34Upw[nPhaseIdx] = (potentialDiffNw34 >= 0) ? lambda3[nPhaseIdx] : lambda4[nPhaseIdx]; - - for (int i = 0; i < numPhases; i++) - { - // evaluate parts of velocity --> always take the normal for which the flux is calculated! - DimVector vel12 = interactionVolume.getNormal(0, 0); - DimVector vel14 = interactionVolume.getNormal(3, 0); - DimVector vel23 = interactionVolume.getNormal(1, 0); - DimVector vel21 = interactionVolume.getNormal(0, 0); - DimVector vel34 = interactionVolume.getNormal(2, 0); - DimVector vel32 = interactionVolume.getNormal(1, 0); - DimVector vel41 = interactionVolume.getNormal(3, 0); - DimVector vel43 = interactionVolume.getNormal(2, 0); - - Dune::FieldVector<Scalar, 2 * dim> flux(0); - switch (i) - { - case wPhaseIdx: - { - flux = fluxW; - break; - } - case nPhaseIdx: - { - flux = fluxNw; - break; - } - } + globalIdx.resize(4); - vel12 *= flux[0] / (2 * interactionVolume.getFaceArea(0, 0)); //divide by 2 because the flux is related to the half face! - vel14 *= flux[3] / (2 * interactionVolume.getFaceArea(0, 1)); - vel23 *= flux[1] / (2 * interactionVolume.getFaceArea(1, 0)); - vel21 *= flux[0] / (2 * interactionVolume.getFaceArea(1, 1)); - vel34 *= flux[2] / (2 * interactionVolume.getFaceArea(2, 0)); - vel32 *= flux[1] / (2 * interactionVolume.getFaceArea(2, 1)); - vel41 *= flux[3] / (2 * interactionVolume.getFaceArea(3, 0)); - vel43 *= flux[2] / (2 * interactionVolume.getFaceArea(3, 1)); + globalIdx[0] = problem_.variables().index(*elementPointer1); + globalIdx[1] = problem_.variables().index(*elementPointer2); + globalIdx[2] = problem_.variables().index(*elementPointer3); + globalIdx[3] = problem_.variables().index(*elementPointer4); - if (level1 < level2) - { - vel12 *= 0.5; - } - else if (level2 < level1) - { - vel21 *= 0.5; - } - if (level2 < level3) - { - vel23 *= 0.5; - } - else if (level3 < level2) - { - vel32 *= 0.5; - } - if (level3 < level4) - { - vel34 *= 0.5; - } - else if (level4 < level3) - { - vel43 *= 0.5; - } - if (level4 < level1) - { - vel41 *= 0.5; - } - else if (level1 < level4) - { - vel14 *= 0.5; - } + //cell Data vector + cellDataTemp.resize(4); - Scalar lambdaT12 = lambda12Upw[wPhaseIdx] + lambda12Upw[nPhaseIdx]; - Scalar lambdaT14 = lambda14Upw[wPhaseIdx] + lambda14Upw[nPhaseIdx]; - Scalar lambdaT32 = lambda32Upw[wPhaseIdx] + lambda32Upw[nPhaseIdx]; - Scalar lambdaT34 = lambda34Upw[wPhaseIdx] + lambda34Upw[nPhaseIdx]; - Scalar fracFlow12 = (lambdaT12 > threshold_) ? lambda12Upw[i] / (lambdaT12) : 0.0; - Scalar fracFlow14 = (lambdaT14 > threshold_) ? lambda14Upw[i] / (lambdaT14) : 0.0; - Scalar fracFlow32 = (lambdaT32 > threshold_) ? lambda32Upw[i] / (lambdaT32) : 0.0; - Scalar fracFlow34 = (lambdaT34 > threshold_) ? lambda34Upw[i] / (lambdaT34) : 0.0; - - vel12 *= fracFlow12; - vel14 *= fracFlow14; - vel23 *= fracFlow32; - vel21 *= fracFlow12; - vel34 *= fracFlow34; - vel32 *= fracFlow32; - vel41 *= fracFlow14; - vel43 *= fracFlow34; - - if (this->innerBoundaryVolumeFaces_[globalIdx1][interactionVolume.getIndexOnElement(0, 0)]) - { - vel12 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx1][interactionVolume.getIndexOnElement(0, 1)]) - { - vel14 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx2][interactionVolume.getIndexOnElement(1, 0)]) - { - vel23 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx2][interactionVolume.getIndexOnElement(1, 1)]) - { - vel21 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx3][interactionVolume.getIndexOnElement(2, 0)]) - { - vel34 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx3][interactionVolume.getIndexOnElement(2, 1)]) - { - vel32 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx4][interactionVolume.getIndexOnElement(3, 0)]) - { - vel41 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx4][interactionVolume.getIndexOnElement(3, 1)]) - { - vel43 *= 2; - } + cellDataTemp[0] = problem_.variables().cellData(globalIdx[0]); + cellDataTemp[1] = problem_.variables().cellData(globalIdx[1]); + cellDataTemp[2] = problem_.variables().cellData(globalIdx[2]); + cellDataTemp[3] = problem_.variables().cellData(globalIdx[3]); - //store velocities - cellData1.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(0, 0), vel12); - cellData1.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(0, 1), vel14); - cellData2.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(1, 0), vel23); - cellData2.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(1, 1), vel21); - cellData3.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(2, 0), vel34); - cellData3.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(2, 1), vel32); - cellData4.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(3, 0), vel41); - cellData4.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(3, 1), vel43); - } - //set velocity marker - cellData1.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(0, 0)); - cellData1.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(0, 1)); - cellData2.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(1, 0)); - cellData2.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(1, 1)); - cellData3.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(2, 0)); - cellData3.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(2, 1)); - cellData4.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(3, 0)); - cellData4.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(3, 1)); + velocity_.calculateInnerInteractionVolumeVelocity(interactionVolume, cellDataTemp[0], cellDataTemp[1], cellDataTemp[2], cellDataTemp[3], this->innerBoundaryVolumeFaces_); } else if (interactionVolume.getElementNumber() == 3) { @@ -800,501 +429,262 @@ void FvMpfaL2dPressureVelocity2pAdaptive<TypeTag>::calculateVelocity() ElementPointer & elementPointer2 = interactionVolume.getSubVolumeElement(1); ElementPointer & elementPointer4 = interactionVolume.getSubVolumeElement(3); - // cell index - int globalIdx1 = problem_.variables().index(*elementPointer1); - int globalIdx2 = problem_.variables().index(*elementPointer2); - int globalIdx4 = problem_.variables().index(*elementPointer4); - - //get the cell Data - CellData& cellData1 = problem_.variables().cellData(globalIdx1); - CellData& cellData2 = problem_.variables().cellData(globalIdx2); - CellData& cellData4 = problem_.variables().cellData(globalIdx4); - - // get pressure values - Dune::FieldVector < Scalar, 2 * dim > potW(0); - Dune::FieldVector < Scalar, 2 * dim > potNw(0); - - potW[0] = cellData1.potential(wPhaseIdx); - potW[1] = cellData2.potential(wPhaseIdx); - potW[2] = cellData4.potential(wPhaseIdx); + globalIdx.resize(3); - potNw[0] = cellData1.potential(nPhaseIdx); - potNw[1] = cellData2.potential(nPhaseIdx); - potNw[2] = cellData4.potential(nPhaseIdx); + globalIdx[0] = problem_.variables().index(*elementPointer1); + globalIdx[1] = problem_.variables().index(*elementPointer2); + globalIdx[2] = problem_.variables().index(*elementPointer4); - //get mobilities of the phases - Dune::FieldVector<Scalar, numPhases> lambda1(cellData1.mobility(wPhaseIdx)); - lambda1[nPhaseIdx] = cellData1.mobility(nPhaseIdx); + //cell Data vector + cellDataTemp.resize(3); - //compute total mobility of cell 1 - Scalar lambdaTotal1 = lambda1[wPhaseIdx] + lambda1[nPhaseIdx]; + cellDataTemp[0] = problem_.variables().cellData(globalIdx[0]); + cellDataTemp[1] = problem_.variables().cellData(globalIdx[1]); + cellDataTemp[2] = problem_.variables().cellData(globalIdx[2]); - //get mobilities of the phases - Dune::FieldVector<Scalar, numPhases> lambda2(cellData2.mobility(wPhaseIdx)); - lambda2[nPhaseIdx] = cellData2.mobility(nPhaseIdx); - //compute total mobility of cell 1 - Scalar lambdaTotal2 = lambda2[wPhaseIdx] + lambda2[nPhaseIdx]; - - //get mobilities of the phases - Dune::FieldVector<Scalar, numPhases> lambda4(cellData4.mobility(wPhaseIdx)); - lambda4[nPhaseIdx] = cellData4.mobility(nPhaseIdx); - - //compute total mobility of cell 1 - Scalar lambdaTotal4 = lambda4[wPhaseIdx] + lambda4[nPhaseIdx]; - - std::vector < DimVector > lambda(4); - - lambda[0][0] = lambdaTotal1; - lambda[0][1] = lambdaTotal1; - lambda[1][0] = lambdaTotal2; - lambda[1][1] = lambdaTotal2; - lambda[3][0] = lambdaTotal4; - lambda[3][1] = lambdaTotal4; - - Scalar potentialDiffW12 = 0; - Scalar potentialDiffW14 = 0; - Scalar potentialDiffW24 = 0; + velocity_.calculateHangingNodeInteractionVolumeVelocity(interactionVolume, cellDataTemp[0], cellDataTemp[1], cellDataTemp[2], this->innerBoundaryVolumeFaces_); + } + else + { + DUNE_THROW(Dune::NotImplemented, "Unknown interactionvolume type!"); + } - Scalar potentialDiffNw12 = 0; - Scalar potentialDiffNw14 = 0; - Scalar potentialDiffNw24 = 0; + int size = cellDataTemp.size(); + for (int i = 0; i < size; i++) + { + if (globalIdx[i] == globalIdxI) + { + if (levelI >= levelJ) + { + cellData.fluxData().setVelocity(wPhaseIdx, indexInInside, cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInInside)); + cellData.fluxData().setVelocity(nPhaseIdx, indexInInside, cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInInside)); + cellData.fluxData().setUpwindPotential(wPhaseIdx, indexInInside, cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInInside)); + cellData.fluxData().setUpwindPotential(nPhaseIdx, indexInInside, cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInInside)); + + if (levelI > levelJ) + { + cellDataJ.fluxData().setVelocity(wPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInInside)); + cellDataJ.fluxData().setVelocity(nPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInInside)); + cellDataJ.fluxData().setUpwindPotential(wPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInInside)); + cellDataJ.fluxData().setUpwindPotential(nPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInInside)); + + } + } - //flux vector - Dune::FieldVector<Scalar, 3> fluxW(0); - Dune::FieldVector<Scalar, 3> fluxNw(0); + } + else if (globalIdx[i] == globalIdxJ) + { + if (levelJ >= levelI) + { + cellDataJ.fluxData().setVelocity(wPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInOutside)); + cellDataJ.fluxData().setVelocity(nPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInOutside)); + cellDataJ.fluxData().setUpwindPotential(wPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInOutside)); + cellDataJ.fluxData().setUpwindPotential(nPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInOutside)); - Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> T(0); - DimVector Tu(0); - Dune::FieldVector<Scalar, 2 * dim - dim + 1> u(0); + if (levelJ > levelI) + { + cellData.fluxData().setVelocity(wPhaseIdx, indexInInside, cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInOutside)); + cellData.fluxData().setVelocity(nPhaseIdx, indexInInside, cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInOutside)); + cellData.fluxData().setUpwindPotential(wPhaseIdx, indexInInside, cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInOutside)); + cellData.fluxData().setUpwindPotential(nPhaseIdx, indexInInside, cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInOutside)); - int transmissibilityType = this->calculateTransmissibility(T, interactionVolume, lambda, 0, 1, 3, 3); + } + } + } + } + } + } + if (levelI == levelJ) + { + cellData.fluxData().setVelocityMarker(indexInInside); + cellDataJ.fluxData().setVelocityMarker(indexInOutside); + } +} - if (transmissibilityType == rightTriangle) - { - u[0] = potW[1]; - u[1] = potW[2]; - u[2] = potW[0]; +template<class TypeTag> +void FvMpfaL2dPressureVelocity2pAdaptive<TypeTag>::calculateVelocityOnBoundary(const Intersection& intersection, CellData& cellData) +{ + ElementPointer element = intersection.inside(); - T.mv(u, Tu); + //get face index + int isIndex = intersection.indexInInside(); - fluxW[0] = Tu[1]; - potentialDiffW12 = Tu[1]; + //get face normal + const Dune::FieldVector<Scalar, dim>& unitOuterNormal = intersection.centerUnitOuterNormal(); - u[0] = potNw[1]; - u[1] = potNw[2]; - u[2] = potNw[0]; + BoundaryTypes bcType; + //get boundary type + problem_.boundaryTypes(bcType, intersection); + PrimaryVariables boundValues(0.0); - T.mv(u, Tu); + if (bcType.isDirichlet(pressEqIdx)) + { + problem_.dirichlet(boundValues, intersection); - fluxNw[0] = Tu[1]; - potentialDiffNw12 = Tu[1]; - } - else if (transmissibilityType == leftTriangle) - { - u[0] = potW[0]; - u[1] = potW[2]; - u[2] = potW[1]; + // get global coordinates of cell centers + const GlobalPosition& globalPosI = element->geometry().center(); - T.mv(u, Tu); + // center of face in global coordinates + const GlobalPosition& globalPosJ = intersection.geometry().center(); - fluxW[0] = Tu[1]; - potentialDiffW12 = Tu[1]; + // get mobilities and fractional flow factors + Scalar lambdaWI = cellData.mobility(wPhaseIdx); + Scalar lambdaNwI = cellData.mobility(nPhaseIdx); - u[0] = potNw[0]; - u[1] = potNw[2]; - u[2] = potNw[1]; + // get capillary pressure + Scalar pcI = cellData.capillaryPressure(); - T.mv(u, Tu); + // distance vector between barycenters + GlobalPosition distVec = globalPosJ - globalPosI; - fluxNw[0] = Tu[1]; - potentialDiffNw12 = Tu[1]; - } + // compute distance between cell centers + Scalar dist = distVec.two_norm(); - transmissibilityType = this->calculateLeftHNTransmissibility(T, interactionVolume, lambda, 1, 3, 0); + //permeability vector at boundary + // compute vectorized permeabilities + DimMatrix meanPermeability(0); - if (transmissibilityType == leftTriangle) - { - u[0] = potW[1]; - u[1] = potW[0]; - u[2] = potW[2]; + problem_.spatialParams().meanK(meanPermeability, problem_.spatialParams().intrinsicPermeability(*element)); - T.mv(u, Tu); + Dune::FieldVector<Scalar, dim> permeability(0); + meanPermeability.mv(unitOuterNormal, permeability); - fluxW[1] = Tu[1]; - potentialDiffW24 = Tu[1]; + //determine saturation at the boundary -> if no saturation is known directly at the boundary use the cell saturation + Scalar satW = 0; + Scalar satNw = 0; + if (bcType.isDirichlet(satEqIdx)) + { + switch (saturationType_) + { + case sw: + { + satW = boundValues[saturationIdx]; + satNw = 1 - boundValues[saturationIdx]; + break; + } + case sn: + { + satW = 1 - boundValues[saturationIdx]; + satNw = boundValues[saturationIdx]; + break; + } + } + } + else + { + satW = cellData.saturation(wPhaseIdx); + satNw = cellData.saturation(nPhaseIdx); + } - u[0] = potNw[1]; - u[1] = potNw[0]; - u[2] = potNw[2]; + Scalar pressBound = boundValues[pressureIdx]; + Scalar pcBound = MaterialLaw::pc(problem_.spatialParams().materialLawParams(*element), satW); - T.mv(u, Tu); + //determine phase pressures from primary pressure variable + Scalar pressWBound = 0; + Scalar pressNwBound = 0; + if (pressureType_ == pw) + { + pressWBound = pressBound; + pressNwBound = pressBound + pcBound; + } + else if (pressureType_ == pn) + { + pressWBound = pressBound - pcBound; + pressNwBound = pressBound; + } - fluxNw[1] = Tu[1]; - potentialDiffNw24 = Tu[1]; - } + Scalar lambdaWBound = MaterialLaw::krw(problem_.spatialParams().materialLawParams(*element), satW) + / viscosity_[wPhaseIdx]; + Scalar lambdaNwBound = MaterialLaw::krn(problem_.spatialParams().materialLawParams(*element), satW) + / viscosity_[nPhaseIdx]; - transmissibilityType = this->calculateRightHNTransmissibility(T, interactionVolume, lambda, 3, 0, 1); + Scalar potentialDiffW = cellData.fluxData().upwindPotential(wPhaseIdx, isIndex); + Scalar potentialDiffNw = cellData.fluxData().upwindPotential(nPhaseIdx, isIndex); - if (transmissibilityType == rightTriangle) - { - u[0] = potW[0]; - u[1] = potW[1]; - u[2] = potW[2]; + //calculate potential gradient + potentialDiffW = (cellData.pressure(wPhaseIdx) - pressWBound); + potentialDiffNw = (cellData.pressure(nPhaseIdx) - pressNwBound); - T.mv(u, Tu); + potentialDiffW += density_[wPhaseIdx] * (distVec * problem_.gravity()); + potentialDiffNw += density_[nPhaseIdx] * (distVec * problem_.gravity()); - fluxW[2] = Tu[1]; - potentialDiffW14 = -Tu[1]; + //store potential gradients for further calculations + cellData.fluxData().setUpwindPotential(wPhaseIdx, isIndex, potentialDiffW); + cellData.fluxData().setUpwindPotential(nPhaseIdx, isIndex, potentialDiffNw); - u[0] = potNw[0]; - u[1] = potNw[1]; - u[2] = potNw[2]; + //do the upwinding of the mobility depending on the phase potentials + Scalar lambdaW = (potentialDiffW > 0.) ? lambdaWI : lambdaWBound; + lambdaW = (potentialDiffW == 0) ? 0.5 * (lambdaWI + lambdaWBound) : lambdaW; + Scalar lambdaNw = (potentialDiffNw > 0.) ? lambdaNwI : lambdaNwBound; + lambdaNw = (potentialDiffNw == 0) ? 0.5 * (lambdaNwI + lambdaNwBound) : lambdaNw; - T.mv(u, Tu); - fluxNw[2] = Tu[1]; - potentialDiffNw14 = -Tu[1]; - } + Scalar scalarPerm = permeability.two_norm(); - //store potentials for further calculations (saturation, ...) -> maybe add new potential to old one!! - cellData1.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(0, 0), potentialDiffW12); - cellData1.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(0, 0), potentialDiffNw12); - cellData1.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(0, 1), potentialDiffW14); - cellData1.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(0, 1), potentialDiffNw14); - cellData2.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(1, 0), potentialDiffW24); - cellData2.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(1, 0), potentialDiffNw24); - cellData2.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(1, 1), -potentialDiffW12); - cellData2.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(1, 1), -potentialDiffNw12); - cellData4.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(3, 0), -potentialDiffW14); - cellData4.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(3, 0), -potentialDiffNw14); - cellData4.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(3, 1), -potentialDiffW24); - cellData4.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(3, 1), -potentialDiffNw24); - - //compute mobilities of face 1 - Dune::FieldVector<Scalar, numPhases> lambda12Upw(0.0); - lambda12Upw[wPhaseIdx] = (potentialDiffW12 >= 0) ? lambda1[wPhaseIdx] : lambda2[wPhaseIdx]; - lambda12Upw[nPhaseIdx] = (potentialDiffNw12 >= 0) ? lambda1[nPhaseIdx] : lambda2[nPhaseIdx]; - - //compute mobilities of face 4 - Dune::FieldVector<Scalar, numPhases> lambda14Upw(0.0); - lambda14Upw[wPhaseIdx] = (potentialDiffW14 >= 0) ? lambda1[wPhaseIdx] : lambda4[wPhaseIdx]; - lambda14Upw[nPhaseIdx] = (potentialDiffNw14 >= 0) ? lambda1[nPhaseIdx] : lambda4[nPhaseIdx]; - - //compute mobilities of face 2 - Dune::FieldVector<Scalar, numPhases> lambda24Upw(0.0); - lambda24Upw[wPhaseIdx] = (potentialDiffW24 >= 0) ? lambda2[wPhaseIdx] : lambda4[wPhaseIdx]; - lambda24Upw[nPhaseIdx] = (potentialDiffNw24 >= 0) ? lambda2[nPhaseIdx] : lambda4[nPhaseIdx]; - - for (int i = 0; i < numPhases; i++) - { - // evaluate parts of velocity --> always take the normal for which the flux is calculated! - DimVector vel12 = interactionVolume.getNormal(0, 0); - DimVector vel14 = interactionVolume.getNormal(3, 0); - DimVector vel24 = interactionVolume.getNormal(1, 0); - DimVector vel21 = interactionVolume.getNormal(0, 0); - DimVector vel41 = interactionVolume.getNormal(3, 0); - DimVector vel42 = interactionVolume.getNormal(1, 0); - - Dune::FieldVector<Scalar, 3> flux(0); - switch (i) - { - case wPhaseIdx: - { - flux = fluxW; - break; - } - case nPhaseIdx: - { - flux = fluxNw; - break; - } - } + //calculate the gravity term + Dune::FieldVector<Scalar, dimWorld> velocityW(unitOuterNormal); + Dune::FieldVector<Scalar, dimWorld> velocityNw(unitOuterNormal); - vel12 *= flux[0] / (2 * interactionVolume.getFaceArea(0, 0)); //divide by 2 because the flux is related to the half face! - vel14 *= flux[2] / (2 * interactionVolume.getFaceArea(3, 0)); - vel24 *= flux[1] / (2 * interactionVolume.getFaceArea(1, 0)); - vel21 *= flux[0] / (2 * interactionVolume.getFaceArea(0, 0)); - vel41 *= flux[2] / (4 * interactionVolume.getFaceArea(3, 0)); - vel42 *= flux[1] / (4 * interactionVolume.getFaceArea(1, 0)); - - Scalar lambdaT12 = lambda12Upw[wPhaseIdx] + lambda12Upw[nPhaseIdx]; - Scalar lambdaT14 = lambda14Upw[wPhaseIdx] + lambda14Upw[nPhaseIdx]; - Scalar lambdaT24 = lambda24Upw[wPhaseIdx] + lambda24Upw[nPhaseIdx]; - Scalar fracFlow12 = (lambdaT12 > threshold_) ? lambda12Upw[i] / (lambdaT12) : 0.0; - Scalar fracFlow14 = (lambdaT14 > threshold_) ? lambda14Upw[i] / (lambdaT14) : 0.0; - Scalar fracFlow24 = (lambdaT24 > threshold_) ? lambda24Upw[i] / (lambdaT24) : 0.0; - - vel12 *= fracFlow12; - vel14 *= fracFlow14; - vel24 *= fracFlow24; - vel21 *= fracFlow12; - vel41 *= fracFlow14; - vel42 *= fracFlow24; - - if (this->innerBoundaryVolumeFaces_[globalIdx1][interactionVolume.getIndexOnElement(0, 0)]) - { - vel12 *= 2; - vel21 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx1][interactionVolume.getIndexOnElement(0, 1)]) - { - vel14 *= 2; - vel41 *= 2; - } - if (this->innerBoundaryVolumeFaces_[globalIdx2][interactionVolume.getIndexOnElement(1, 0)]) - { - vel24 *= 2; - vel42 *= 2; - } + //calculate unit distVec + distVec /= dist; + Scalar areaScaling = (unitOuterNormal * distVec); + //this treatment of g allows to account for gravity flux through faces where the face normal has no z component (e.g. parallelepiped grids) + Scalar gravityTermW = (problem_.gravity() * distVec) * density_[wPhaseIdx] * areaScaling; + Scalar gravityTermNw = (problem_.gravity() * distVec) * density_[nPhaseIdx] * areaScaling; - //store velocities - //set velocity - cellData1.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(0, 0), vel12); - cellData1.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(0, 1), vel14); - cellData2.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(1, 0), vel24); - cellData2.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(1, 1), vel21); - cellData4.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(3, 0), vel41); - cellData4.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(3, 1), vel42); - } - //set velocity marker - cellData1.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(0, 0)); - cellData1.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(0, 1)); - cellData2.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(1, 0)); - cellData2.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(1, 1)); - cellData4.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(3, 0)); - cellData4.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(3, 1)); - } - else - { - DUNE_THROW(Dune::NotImplemented, "Unknown interactionvolume type!"); - } + //calculate velocity depending on the pressure used -> use pc = pn - pw + switch (pressureType_) + { + case pw: + { + velocityW *= lambdaW * scalarPerm * ((cellData.pressure(wPhaseIdx) - pressBound) / dist + gravityTermW); + velocityNw *= lambdaNw * scalarPerm * ((cellData.pressure(wPhaseIdx) - pressBound) / dist + gravityTermNw) + + 0.5 * (lambdaNwI + lambdaNwBound) * scalarPerm * (pcI - pcBound) / dist; + break; } - - // at least one face on boundary! - else + case pn: { - for (int elemIdx = 0; elemIdx < 2 * dim; elemIdx++) - { - bool isOutside = false; - for (int faceIdx = 0; faceIdx < dim; faceIdx++) - { - int intVolFaceIdx = interactionVolume.getFaceIndexFromSubVolume(elemIdx, faceIdx); - if (interactionVolume.isOutsideFace(intVolFaceIdx)) - { - isOutside = true; - break; - } - } - if (isOutside) - { - continue; - } - - ElementPointer & elementPointer = interactionVolume.getSubVolumeElement(elemIdx); - - // get global coordinate of cell centers - const GlobalPosition& globalPos = elementPointer->geometry().center(); + velocityW *= lambdaW * scalarPerm * ((cellData.pressure(nPhaseIdx) - pressBound) / dist + gravityTermW) + - 0.5 * (lambdaWI + lambdaWBound) * scalarPerm * (pcI - pcBound) / dist; + velocityNw *= lambdaNw * scalarPerm * ((cellData.pressure(nPhaseIdx) - pressBound) / dist + gravityTermNw); + break; + } + } - // cell index - int globalIdx = problem_.variables().index(*elementPointer); + //store velocities + cellData.fluxData().setVelocity(wPhaseIdx, isIndex, velocityW); + cellData.fluxData().setVelocity(nPhaseIdx, isIndex, velocityNw); + cellData.fluxData().setVelocityMarker(isIndex); - //get the cell Data - CellData& cellData = problem_.variables().cellData(globalIdx); + } //end dirichlet boundary - //permeability vector at boundary - DimMatrix permeability(problem_.spatialParams().intrinsicPermeability(*elementPointer)); + else if (bcType.isNeumann(pressEqIdx)) + { + problem_.neumann(boundValues, intersection); - //get mobilities of the phases - Dune::FieldVector<Scalar, numPhases> lambda(cellData.mobility(wPhaseIdx)); - lambda[nPhaseIdx] = cellData.mobility(nPhaseIdx); + Dune::FieldVector<Scalar, dimWorld> velocityW(unitOuterNormal); + Dune::FieldVector<Scalar, dimWorld> velocityNw(unitOuterNormal); - for (int faceIdx = 0; faceIdx < dim; faceIdx++) - { - int intVolFaceIdx = interactionVolume.getFaceIndexFromSubVolume(elemIdx, faceIdx); + velocityW *= boundValues[wPhaseIdx]; + velocityNw *= boundValues[nPhaseIdx]; - if (interactionVolume.isBoundaryFace(intVolFaceIdx)) - { - if (interactionVolume.getBoundaryType(intVolFaceIdx).isDirichlet(pressEqIdx)) - { - int boundaryFaceIdx = interactionVolume.getIndexOnElement(elemIdx, faceIdx); - - const ReferenceElement& referenceElement = ReferenceElements::general( - elementPointer->geometry().type()); - - const LocalPosition& localPos = referenceElement.position(boundaryFaceIdx, 1); - - const GlobalPosition& globalPosFace = elementPointer->geometry().global(localPos); - - DimVector distVec(globalPosFace - globalPos); - Scalar dist = distVec.two_norm(); - DimVector unitDistVec(distVec); - unitDistVec /= dist; - - // get pc and lambda at the boundary - Scalar satWBound = cellData.saturation(wPhaseIdx); - //check boundary sat at face 1 - if (interactionVolume.getBoundaryType(intVolFaceIdx).isDirichlet(satEqIdx)) - { - Scalar satBound = interactionVolume.getDirichletValues(intVolFaceIdx)[saturationIdx]; - switch (saturationType_) - { - case sw: - { - satWBound = satBound; - break; - } - case sn: - { - satWBound = 1 - satBound; - break; - } - } - - } - - Scalar pcBound = MaterialLaw::pc( - problem_.spatialParams().materialLawParams(*elementPointer), satWBound); - - Scalar gravityDiffBound = (problem_.bBoxMax() - globalPosFace) * problem_.gravity() - * (density_[nPhaseIdx] - density_[wPhaseIdx]); - - pcBound += gravityDiffBound; - - Dune::FieldVector<Scalar, numPhases> lambdaBound( - MaterialLaw::krw(problem_.spatialParams().materialLawParams(*elementPointer), - satWBound)); - lambdaBound[nPhaseIdx] = MaterialLaw::krn( - problem_.spatialParams().materialLawParams(*elementPointer), satWBound); - lambdaBound[wPhaseIdx] /= viscosity_[wPhaseIdx]; - lambdaBound[nPhaseIdx] /= viscosity_[nPhaseIdx]; - - Scalar gdeltaZ = (problem_.bBoxMax()-globalPosFace) * gravity_; - Scalar potentialBoundW = interactionVolume.getDirichletValues(intVolFaceIdx)[pressureIdx] + density_[wPhaseIdx]*gdeltaZ; - Scalar potentialBoundNw = potentialBoundW; - - //calculate potential gradients - switch (pressureType_) - { - case pw: - { - potentialBoundNw += pcBound; - break; - } - case pn: - { - //calculate potential gradients - potentialBoundW -= pcBound; - break; - } - } - - - Scalar potentialDiffW = (cellData.potential(wPhaseIdx) - potentialBoundW) / dist; - Scalar potentialDiffNw = (cellData.potential(nPhaseIdx) - potentialBoundNw) / dist; - - //store potentials for further calculations (saturation, ...) - cellData.fluxData().addUpwindPotential(wPhaseIdx, boundaryFaceIdx, potentialDiffW); - cellData.fluxData().addUpwindPotential(nPhaseIdx, boundaryFaceIdx, potentialDiffNw); - - //calculated phase velocities from advective velocities -> capillary pressure velocity already added in pressure part! - DimVector velocityW(0); - DimVector velocityNw(0); - - // calculate capillary pressure gradient - DimVector pressGradient = unitDistVec; - pressGradient *= (cellData.potential(wPhaseIdx) - potentialBoundW) / dist; - permeability.mv(pressGradient, velocityW); - - pressGradient = unitDistVec; - pressGradient *= (cellData.potential(nPhaseIdx) - potentialBoundNw) / dist; - permeability.mv(pressGradient, velocityNw); - - velocityW *= (potentialDiffW >= 0.) ? lambda[wPhaseIdx] : lambdaBound[wPhaseIdx]; - velocityNw *= (potentialDiffNw >= 0.) ? lambda[nPhaseIdx] : lambdaBound[nPhaseIdx]; - - //velocity is calculated from two vertices of one intersection! - velocityW *= 0.5; - velocityNw *= 0.5; - - //store velocities - cellData.fluxData().addVelocity(wPhaseIdx, boundaryFaceIdx, velocityW); - cellData.fluxData().addVelocity(nPhaseIdx, boundaryFaceIdx, velocityNw); - cellData.fluxData().setVelocityMarker(boundaryFaceIdx); - - } - else if (interactionVolume.getBoundaryType(intVolFaceIdx).isNeumann(pressEqIdx)) - { - int boundaryFaceIdx = interactionVolume.getIndexOnElement(elemIdx, faceIdx); - - const ReferenceElement& referenceElement = ReferenceElements::general( - elementPointer->geometry().type()); - - const LocalPosition& localPos = referenceElement.position(boundaryFaceIdx, 1); - - const GlobalPosition& globalPosFace = elementPointer->geometry().global(localPos); - - DimVector distVec(globalPosFace - globalPos); - Scalar dist = distVec.two_norm(); - DimVector unitDistVec(distVec); - unitDistVec /= dist; - - // get neumann boundary value - PrimaryVariables boundValues(interactionVolume.getNeumannValues(intVolFaceIdx)); - - boundValues[wPhaseIdx] /= density_[wPhaseIdx]; - boundValues[nPhaseIdx] /= density_[nPhaseIdx]; - - DimVector velocityW(unitDistVec); - DimVector velocityNw(unitDistVec); - - velocityW *= boundValues[wPhaseIdx] / (2 * interactionVolume.getFaceArea(elemIdx, faceIdx)); - velocityNw *= boundValues[nPhaseIdx] - / (2 * interactionVolume.getFaceArea(elemIdx, faceIdx)); - - //store potentials for further calculations (saturation, ...) - cellData.fluxData().addUpwindPotential(wPhaseIdx, boundaryFaceIdx, boundValues[wPhaseIdx]); - cellData.fluxData().addUpwindPotential(nPhaseIdx, boundaryFaceIdx, boundValues[nPhaseIdx]); - - //store velocities - cellData.fluxData().addVelocity(wPhaseIdx, boundaryFaceIdx, velocityW); - cellData.fluxData().addVelocity(nPhaseIdx, boundaryFaceIdx, velocityNw); - cellData.fluxData().setVelocityMarker(boundaryFaceIdx); - } - else - { - DUNE_THROW(Dune::NotImplemented, - "No valid boundary condition type defined for pressure equation!"); - } - } - } - } + velocityW /= density_[wPhaseIdx]; + velocityNw /= density_[nPhaseIdx]; - } // end boundaries + //store potential gradients for further calculations + cellData.fluxData().setUpwindPotential(wPhaseIdx, isIndex, boundValues[wPhaseIdx]); + cellData.fluxData().setUpwindPotential(nPhaseIdx, isIndex, boundValues[nPhaseIdx]); - } // end vertex iterator -// std::cout<<"velocityW = \n"; -// for (int i = 0; i<problem_.gridView().size(0);i++) -// { -// std::cout<<i<<": "; -// for (int j=0; j<4; j++) -// { -// std::cout<<" ("<<j<<") "<<problem_.variables().cellData(i).fluxData().velocity(wPhaseIdx, j); -// } -// std::cout<<"\n"; -// } -// std::cout<<"velocityNw = \n"; -// for (int i = 0; i<problem_.gridView().size(0);i++) -// { -// std::cout<<i<<": "; -// for (int j=0; j<4; j++) -// { -// std::cout<<" ("<<j<<") "<<problem_.variables().cellData(i).fluxData().velocity(nPhaseIdx, j); -// } -// std::cout<<"\n"; -// } - return; -} // end method calcTotalVelocity + cellData.fluxData().setVelocity(wPhaseIdx, isIndex, velocityW); + cellData.fluxData().setVelocity(nPhaseIdx, isIndex, velocityNw); + cellData.fluxData().setVelocityMarker(isIndex); + } //end neumann boundary + else + { + DUNE_THROW(Dune::NotImplemented, "No valid boundary condition type defined for pressure equation!"); + } +} } // end of Dune namespace diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dtransmissibilitycalculator.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dtransmissibilitycalculator.hh new file mode 100644 index 0000000000000000000000000000000000000000..70bbffb27f14eae738f34c2b5ecb96a7e9c655c3 --- /dev/null +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dtransmissibilitycalculator.hh @@ -0,0 +1,646 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +#ifndef DUMUX_FVMPFAL2D_TRANSMISSIBILITYCALCULATOR_HH +#define DUMUX_FVMPFAL2D_TRANSMISSIBILITYCALCULATOR_HH + +// dumux environment +#include <dumux/decoupled/common/pressureproperties.hh> +#include <dumux/decoupled/common/fv/mpfa/fvmpfaproperties.hh> +#include <dumux/decoupled/common/fv/mpfa/mpfalinteractionvolume.hh> + +/** + * @file + * @brief Provides methods for transmissibility calculation + */ + +namespace Dumux +{ +//! \ingroup FVPressure2p +/*! Provides methods for transmissibility calculation. + */ +template<class TypeTag> +class FvMpfaL2dTransmissibilityCalculator +{ + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + enum + { + dim = GridView::dimension, dimWorld = GridView::dimensionworld + }; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + + typedef typename GridView::template Codim<0>::EntityPointer ElementPointer; + + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; + + typedef Dune::FieldVector<Scalar, dim> DimVector; + + typedef typename Dumux::FVMPFALInteractionVolume<TypeTag> InteractionVolume; + +public: + typedef Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> TransmissibilityType; + + enum + { + leftTriangle = -1, + noTransmissibility = 0, + rightTriangle = 1 + }; + + // Calculates tranmissibility matrix + int calculateTransmissibility( + TransmissibilityType& transmissibility, + InteractionVolume& interactionVolume, + std::vector<DimVector >& lambda, + int idx1, int idx2, int idx3, int idx4); + + // Calculates tranmissibility matrix of left L-shape + int calculateLeftHNTransmissibility(TransmissibilityType& transmissibility, + InteractionVolume& interactionVolume, + std::vector<DimVector >& lambda, + int idx1, int idx2, int idx3); + + // Calculates tranmissibility matrix of right L-shape + int calculateRightHNTransmissibility(TransmissibilityType& transmissibility, + InteractionVolume& interactionVolume, + std::vector<DimVector >& lambda, + int idx1, int idx2, int idx3); + + + FvMpfaL2dTransmissibilityCalculator(Problem& problem) : + problem_(problem), R_(0) + { + if (dim != 2) + { + DUNE_THROW(Dune::NotImplemented, "Dimension not supported!"); + } + + // evaluate matrix R + if (dim == 2) + { + R_[0][1] = 1; + R_[1][0] = -1; + } + } + +private: + Problem& problem_; + DimMatrix R_; +}; + +/*! \brief Calculates tranmissibility matrix + * + * Calculates tranmissibility matrix of an L-shape for a certain flux face. + * Automatically selects one of the two possible L-shape (left, or right). + * + * \param transmissibility Matrix for the resulting transmissibility + * \param interactionVolume The interaction volume object (includes geometric information) + * \param lambda Mobilities of cells 1-4 + * \param idx1 Index of cell 1 of the L-stencil + * \param idx2 Index of cell 2 of the L-stencil + * \param idx3 Index of cell 3 of the L-stencil + * \param idx4 Index of cell 4 of the L-stencil + */ +template<class TypeTag> +int FvMpfaL2dTransmissibilityCalculator<TypeTag>::calculateTransmissibility( + TransmissibilityType& transmissibility, + InteractionVolume& interactionVolume, + std::vector<DimVector >& lambda, + int idx1, int idx2, int idx3, int idx4) +{ + ElementPointer& elementPointer1 = interactionVolume.getSubVolumeElement(idx1); + ElementPointer& elementPointer2 = interactionVolume.getSubVolumeElement(idx2); + ElementPointer& elementPointer3 = interactionVolume.getSubVolumeElement(idx3); + ElementPointer& elementPointer4 = interactionVolume.getSubVolumeElement(idx4); + + if (elementPointer3 == elementPointer4 && elementPointer1->level() != elementPointer2->level()) + { + return noTransmissibility; + } + + // get global coordinate of cell centers + const GlobalPosition& globalPos1 = elementPointer1->geometry().center(); + const GlobalPosition& globalPos2 = elementPointer2->geometry().center(); + const GlobalPosition& globalPos3 = elementPointer3->geometry().center(); + const GlobalPosition& globalPos4 = elementPointer4->geometry().center(); + + const GlobalPosition& globalPosCenter = interactionVolume.getCenterPosition(); + + const DimMatrix& K1 = problem_.spatialParams().intrinsicPermeability(*elementPointer1); + const DimMatrix& K2 = problem_.spatialParams().intrinsicPermeability(*elementPointer2); + const DimMatrix& K3 = problem_.spatialParams().intrinsicPermeability(*elementPointer3); + const DimMatrix& K4 = problem_.spatialParams().intrinsicPermeability(*elementPointer4); + + const GlobalPosition& globalPosFace12 = interactionVolume.getFacePosition(idx1, 0); + const GlobalPosition& globalPosFace23 = interactionVolume.getFacePosition(idx2, 0); + + // compute normal vectors nu1-nu7 in triangle R for first half edge + DimVector nu1R1(0); + R_.mv(globalPosFace12 - globalPos2, nu1R1); + + DimVector nu2R1(0); + R_.mv(globalPos2 - globalPosFace23, nu2R1); + + DimVector nu3R1(0); + R_.mv(globalPosFace23 - globalPos3, nu3R1); + + DimVector nu4R1(0); + R_.mv(globalPos3 - globalPosCenter, nu4R1); + + DimVector nu5R1(0); + R_.mv(globalPosCenter - globalPos1, nu5R1); + + DimVector nu6R1(0); + R_.mv(globalPos1 - globalPosFace12, nu6R1); + + DimVector nu7R1(0); + R_.mv(globalPosCenter - globalPos2, nu7R1); + + // compute T, i.e., the area of quadrilateral made by normal vectors 'nu' + DimVector Rnu2R1(0); + R_.mv(nu2R1, Rnu2R1); + Scalar T1R1 = nu1R1 * Rnu2R1; + + DimVector Rnu4R1(0); + R_.mv(nu4R1, Rnu4R1); + Scalar T2R1 = nu3R1 * Rnu4R1; + + DimVector Rnu6R1(0); + R_.mv(nu6R1, Rnu6R1); + Scalar T3R1 = nu5R1 * Rnu6R1; + + // compute components needed for flux calculation, denoted as 'omega' and 'chi' + DimVector K2nu1R1(0); + K2.mv(nu1R1, K2nu1R1); + DimVector K2nu2R1(0); + K2.mv(nu2R1, K2nu2R1); + DimVector K4nu3R1(0); + K3.mv(nu3R1, K4nu3R1); + DimVector K4nu4R1(0); + K3.mv(nu4R1, K4nu4R1); + DimVector K1nu5R1(0); + K1.mv(nu5R1, K1nu5R1); + DimVector K1nu6R1(0); + K1.mv(nu6R1, K1nu6R1); + + DimVector Rnu1R1(0); + R_.mv(nu1R1, Rnu1R1); + + DimVector &outerNormaln1R1 = interactionVolume.getNormal(idx2, 0); + DimVector &outerNormaln2 = interactionVolume.getNormal(idx1, 0); + + Scalar omega111R1 = lambda[idx2][0] * (outerNormaln1R1 * K2nu1R1) * interactionVolume.getFaceArea(idx2, 0) / T1R1; + Scalar omega112R1 = lambda[idx2][0] * (outerNormaln1R1 * K2nu2R1) * interactionVolume.getFaceArea(idx2, 0) / T1R1; + Scalar omega211R1 = lambda[idx2][1] * (outerNormaln2 * K2nu1R1) * interactionVolume.getFaceArea(idx2, 1) / T1R1; + Scalar omega212R1 = lambda[idx2][1] * (outerNormaln2 * K2nu2R1) * interactionVolume.getFaceArea(idx2, 1) / T1R1; + Scalar omega123R1 = lambda[idx3][1] * (outerNormaln1R1 * K4nu3R1) * interactionVolume.getFaceArea(idx3, 1) / T2R1; + Scalar omega124R1 = lambda[idx3][1] * (outerNormaln1R1 * K4nu4R1) * interactionVolume.getFaceArea(idx3, 1) / T2R1; + Scalar omega235R1 = lambda[idx1][0] * (outerNormaln2 * K1nu5R1) * interactionVolume.getFaceArea(idx1, 0) / T3R1; + Scalar omega236R1 = lambda[idx1][0] * (outerNormaln2 * K1nu6R1) * interactionVolume.getFaceArea(idx1, 0) / T3R1; + Scalar chi711R1 = (nu7R1 * Rnu1R1) / T1R1; + Scalar chi712R1 = (nu7R1 * Rnu2R1) / T1R1; + + // compute transmissibility matrix TR1 = CA^{-1}B+D + DimMatrix C(0), A(0); + Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> D(0), B(0); + + // evaluate matrix C, D, A, B + C[0][0] = -omega111R1; + C[0][1] = -omega112R1; + C[1][0] = -omega211R1; + C[1][1] = -omega212R1; + + D[0][0] = omega111R1 + omega112R1; + D[1][0] = omega211R1 + omega212R1; + + A[0][0] = omega111R1 - omega124R1 - omega123R1 * chi711R1; + A[0][1] = omega112R1 - omega123R1 * chi712R1; + A[1][0] = omega211R1 - omega236R1 * chi711R1; + A[1][1] = omega212R1 - omega235R1 - omega236R1 * chi712R1; + + B[0][0] = omega111R1 + omega112R1 + omega123R1 * (1.0 - chi711R1 - chi712R1); + B[0][1] = -omega123R1 - omega124R1; + B[1][0] = omega211R1 + omega212R1 + omega236R1 * (1.0 - chi711R1 - chi712R1); + B[1][2] = -omega235R1 - omega236R1; + + // compute TR1 + A.invert(); + D += B.leftmultiply(C.rightmultiply(A)); + Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> TR1(D); + + // 2.use triangle L to compute the transmissibility of half edge + const GlobalPosition& globalPosFace14 = interactionVolume.getFacePosition(idx1, 1); + + // compute normal vectors nu1-nu7 in triangle L for first half edge + DimVector nu1L1(0); + R_.mv(globalPosFace12 - globalPos1, nu1L1); + + DimVector nu2L1(0); + R_.mv(globalPos1 - globalPosFace14, nu2L1); + + DimVector nu3L1(0); + R_.mv(globalPosFace14 - globalPos4, nu3L1); + + DimVector nu4L1(0); + R_.mv(globalPos4 - globalPosCenter, nu4L1); + + DimVector nu5L1(0); + R_.mv(globalPosCenter - globalPos2, nu5L1); + + DimVector nu6L1(0); + R_.mv(globalPos2 - globalPosFace12, nu6L1); + + DimVector nu7L1(0); + R_.mv(globalPosCenter - globalPos1, nu7L1); + + // compute T, i.e., the area of quadrilateral made by normal vectors 'nu' + DimVector Rnu2L1(0); + R_.mv(nu2L1, Rnu2L1); + Scalar T1L1 = nu1L1 * Rnu2L1; + + DimVector Rnu4L1(0); + R_.mv(nu4L1, Rnu4L1); + Scalar T2L1 = nu3L1 * Rnu4L1; + + DimVector Rnu6L1(0); + R_.mv(nu6L1, Rnu6L1); + Scalar T3L1 = nu5L1 * Rnu6L1; + + // compute components needed for flux calculation, denoted as 'omega' and 'chi' + DimVector K1nu1L1(0); + K1.mv(nu1L1, K1nu1L1); + DimVector K1nu2L1(0); + K1.mv(nu2L1, K1nu2L1); + DimVector K3nu3L1(0); + K4.mv(nu3L1, K3nu3L1); + DimVector K3nu4L1(0); + K4.mv(nu4L1, K3nu4L1); + DimVector K2nu5L1(0); + K2.mv(nu5L1, K2nu5L1); + DimVector K2nu6L1(0); + K2.mv(nu6L1, K2nu6L1); + + DimVector Rnu1L1(0); + R_.mv(nu1L1, Rnu1L1); + + DimVector &outerNormaln1L1 = interactionVolume.getNormal(idx1, 1); + + Scalar omega111L1 = lambda[idx1][1] * (outerNormaln1L1 * K1nu1L1) * interactionVolume.getFaceArea(idx1, 1) / T1L1; + Scalar omega112L1 = lambda[idx1][1] * (outerNormaln1L1 * K1nu2L1) * interactionVolume.getFaceArea(idx1, 1) / T1L1; + Scalar omega211L1 = lambda[idx1][0] * (outerNormaln2 * K1nu1L1) * interactionVolume.getFaceArea(idx1, 0) / T1L1; + Scalar omega212L1 = lambda[idx1][0] * (outerNormaln2 * K1nu2L1) * interactionVolume.getFaceArea(idx1, 0) / T1L1; + Scalar omega123L1 = lambda[idx4][0] * (outerNormaln1L1 * K3nu3L1) * interactionVolume.getFaceArea(idx4, 0) / T2L1; + Scalar omega124L1 = lambda[idx4][0] * (outerNormaln1L1 * K3nu4L1) * interactionVolume.getFaceArea(idx4, 0) / T2L1; + Scalar omega235L1 = lambda[idx2][1] * (outerNormaln2 * K2nu5L1) * interactionVolume.getFaceArea(idx2, 1) / T3L1; + Scalar omega236L1 = lambda[idx2][1] * (outerNormaln2 * K2nu6L1) * interactionVolume.getFaceArea(idx2, 1) / T3L1; + Scalar chi711L1 = (nu7L1 * Rnu1L1) / T1L1; + Scalar chi712L1 = (nu7L1 * Rnu2L1) / T1L1; + + // compute transmissibility matrix TL1 = CA^{-1}B+D + C = 0; + A = 0; + D = 0; + B = 0; + + // evaluate matrix C, D, A, B + C[0][0] = -omega111L1; + C[0][1] = -omega112L1; + C[1][0] = -omega211L1; + C[1][1] = -omega212L1; + + D[0][0] = omega111L1 + omega112L1; + D[1][0] = omega211L1 + omega212L1; + + A[0][0] = omega111L1 - omega124L1 - omega123L1 * chi711L1; + A[0][1] = omega112L1 - omega123L1 * chi712L1; + A[1][0] = omega211L1 - omega236L1 * chi711L1; + A[1][1] = omega212L1 - omega235L1 - omega236L1 * chi712L1; + + B[0][0] = omega111L1 + omega112L1 + omega123L1 * (1.0 - chi711L1 - chi712L1); + B[0][1] = -omega123L1 - omega124L1; + B[1][0] = omega211L1 + omega212L1 + omega236L1 * (1.0 - chi711L1 - chi712L1); + B[1][2] = -omega235L1 - omega236L1; + + // compute TL1 + A.invert(); + D += B.leftmultiply(C.rightmultiply(A)); + Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> TL1(D); + + //selection criterion + Scalar sR = std::abs(TR1[1][2] - TR1[1][0]); + Scalar sL = std::abs(TL1[1][0] - TL1[1][2]); + + // 3.decide which triangle (which transmissibility coefficients) to use + if (sR <= sL) + { + transmissibility = TR1; + return rightTriangle; + } + else + { + transmissibility = TL1; + return leftTriangle; + } +} + +/*! \brief Calculates tranmissibility matrix + * + * Calculates tranmissibility matrix of an L-shape for a certain flux face. + * Calculates only the transmissibility of the left L-shape (needed at hanging nodes HN). + * + * \param transmissibilityLeft Matrix for the resulting transmissibility + * \param interactionVolume The interaction volume object (includes geometric information) + * \param lambda Mobilities of cells 1-3 + * \param idx1 Index of cell 1 of the L-stencil + * \param idx2 Index of cell 2 of the L-stencil + * \param idx3 Index of cell 3 of the L-stencil + */ +template<class TypeTag> +int FvMpfaL2dTransmissibilityCalculator<TypeTag>::calculateLeftHNTransmissibility( + TransmissibilityType& transmissibilityLeft, + InteractionVolume& interactionVolume, + std::vector<DimVector >& lambda, + int idx1, int idx2, int idx3) +{ + ElementPointer& elementPointer1 = interactionVolume.getSubVolumeElement(idx1); + ElementPointer& elementPointer2 = interactionVolume.getSubVolumeElement(idx2); + ElementPointer& elementPointer3 = interactionVolume.getSubVolumeElement(idx3); + + if (elementPointer1->level() != elementPointer3->level()) + { + return noTransmissibility; + } + + // get global coordinate of cell centers + const GlobalPosition& globalPos1 = elementPointer1->geometry().center(); + const GlobalPosition& globalPos2 = elementPointer2->geometry().center(); + const GlobalPosition& globalPos3 = elementPointer3->geometry().center(); + + const GlobalPosition& globalPosCenter = interactionVolume.getCenterPosition(); + + const DimMatrix& K1 = problem_.spatialParams().intrinsicPermeability(*elementPointer1); + const DimMatrix& K2 = problem_.spatialParams().intrinsicPermeability(*elementPointer2); + const DimMatrix& K3 = problem_.spatialParams().intrinsicPermeability(*elementPointer3); + + const GlobalPosition& globalPosFace12 = interactionVolume.getFacePosition(idx1, 0); + DimVector &outerNormaln2 = interactionVolume.getNormal(idx1, 0); + + // compute transmissibility matrix TR1 = CA^{-1}B+D + DimMatrix C(0), A(0); + TransmissibilityType D(0), B(0); + + // 2.use triangle L to compute the transmissibility of half edge + const GlobalPosition& globalPosFace14 = interactionVolume.getFacePosition(idx1, 1); + + // compute normal vectors nu1-nu7 in triangle L for first half edge + DimVector nu1L1(0); + R_.mv(globalPosFace12 - globalPos1, nu1L1); + + DimVector nu2L1(0); + R_.mv(globalPos1 - globalPosFace14, nu2L1); + + DimVector nu3L1(0); + R_.mv(globalPosFace14 - globalPos3, nu3L1); + + DimVector nu4L1(0); + R_.mv(globalPos3 - globalPosCenter, nu4L1); + + DimVector nu5L1(0); + R_.mv(globalPosCenter - globalPos2, nu5L1); + + DimVector nu6L1(0); + R_.mv(globalPos2 - globalPosFace12, nu6L1); + + DimVector nu7L1(0); + R_.mv(globalPosCenter - globalPos1, nu7L1); + + // compute T, i.e., the area of quadrilateral made by normal vectors 'nu' + DimVector Rnu2L1(0); + R_.mv(nu2L1, Rnu2L1); + Scalar T1L1 = nu1L1 * Rnu2L1; + + DimVector Rnu4L1(0); + R_.mv(nu4L1, Rnu4L1); + Scalar T2L1 = nu3L1 * Rnu4L1; + + DimVector Rnu6L1(0); + R_.mv(nu6L1, Rnu6L1); + Scalar T3L1 = nu5L1 * Rnu6L1; + + // compute components needed for flux calculation, denoted as 'omega' and 'chi' + DimVector K1nu1L1(0); + K1.mv(nu1L1, K1nu1L1); + DimVector K1nu2L1(0); + K1.mv(nu2L1, K1nu2L1); + DimVector K3nu3L1(0); + K3.mv(nu3L1, K3nu3L1); + DimVector K3nu4L1(0); + K3.mv(nu4L1, K3nu4L1); + DimVector K2nu5L1(0); + K2.mv(nu5L1, K2nu5L1); + DimVector K2nu6L1(0); + K2.mv(nu6L1, K2nu6L1); + + DimVector Rnu1L1(0); + R_.mv(nu1L1, Rnu1L1); + + DimVector &outerNormaln1L1 = interactionVolume.getNormal(idx1, 1); + + Scalar omega111L1 = lambda[idx1][1] * (outerNormaln1L1 * K1nu1L1) * interactionVolume.getFaceArea(idx1, 1) / T1L1; + Scalar omega112L1 = lambda[idx1][1] * (outerNormaln1L1 * K1nu2L1) * interactionVolume.getFaceArea(idx1, 1) / T1L1; + Scalar omega211L1 = lambda[idx1][0] * (outerNormaln2 * K1nu1L1) * interactionVolume.getFaceArea(idx1, 0) / T1L1; + Scalar omega212L1 = lambda[idx1][0] * (outerNormaln2 * K1nu2L1) * interactionVolume.getFaceArea(idx1, 0) / T1L1; + Scalar omega123L1 = lambda[idx3][0] * (outerNormaln1L1 * K3nu3L1) * interactionVolume.getFaceArea(idx3, 0) / T2L1; + Scalar omega124L1 = lambda[idx3][0] * (outerNormaln1L1 * K3nu4L1) * interactionVolume.getFaceArea(idx3, 0) / T2L1; + Scalar omega235L1 = lambda[idx2][1] * (outerNormaln2 * K2nu5L1) * interactionVolume.getFaceArea(idx2, 1) / T3L1; + Scalar omega236L1 = lambda[idx2][1] * (outerNormaln2 * K2nu6L1) * interactionVolume.getFaceArea(idx2, 1) / T3L1; + Scalar chi711L1 = (nu7L1 * Rnu1L1) / T1L1; + Scalar chi712L1 = (nu7L1 * Rnu2L1) / T1L1; + + // compute transmissibility matrix TL1 = CA^{-1}B+D + // evaluate matrix C, D, A, B + C[0][0] = -omega111L1; + C[0][1] = -omega112L1; + C[1][0] = -omega211L1; + C[1][1] = -omega212L1; + + D[0][0] = omega111L1 + omega112L1; + D[1][0] = omega211L1 + omega212L1; + + A[0][0] = omega111L1 - omega124L1 - omega123L1 * chi711L1; + A[0][1] = omega112L1 - omega123L1 * chi712L1; + A[1][0] = omega211L1 - omega236L1 * chi711L1; + A[1][1] = omega212L1 - omega235L1 - omega236L1 * chi712L1; + + B[0][0] = omega111L1 + omega112L1 + omega123L1 * (1.0 - chi711L1 - chi712L1); + B[0][1] = -omega123L1 - omega124L1; + B[1][0] = omega211L1 + omega212L1 + omega236L1 * (1.0 - chi711L1 - chi712L1); + B[1][2] = -omega235L1 - omega236L1; + + // compute TL1 + A.invert(); + D += B.leftmultiply(C.rightmultiply(A)); + + // 3.decide which triangle (which transmissibility coefficients) to use + transmissibilityLeft = D; + return leftTriangle; +} + +/*! \brief Calculates tranmissibility matrix + * + * Calculates tranmissibility matrix of an L-shape for a certain flux face. + * Calculates only the transmissibility of the right L-shape (needed at hanging nodes HN). + * + * \param transmissibilityRight Matrix for the resulting transmissibility + * \param interactionVolume The interaction volume object (includes geometric information) + * \param lambda Mobilities of cells 1-3 + * \param idx1 Index of cell 1 of the L-stencil + * \param idx2 Index of cell 2 of the L-stencil + * \param idx3 Index of cell 3 of the L-stencil + */ +template<class TypeTag> +int FvMpfaL2dTransmissibilityCalculator<TypeTag>::calculateRightHNTransmissibility( + TransmissibilityType& transmissibilityRight, + InteractionVolume& interactionVolume, + std::vector<DimVector >& lambda, + int idx1, int idx2, int idx3) +{ + ElementPointer& elementPointer1 = interactionVolume.getSubVolumeElement(idx1); + ElementPointer& elementPointer2 = interactionVolume.getSubVolumeElement(idx2); + ElementPointer& elementPointer3 = interactionVolume.getSubVolumeElement(idx3); + + if (elementPointer2->level() != elementPointer3->level()) + { + return noTransmissibility; + } + + // get global coordinate of cell centers + const GlobalPosition& globalPos1 = elementPointer1->geometry().center(); + const GlobalPosition& globalPos2 = elementPointer2->geometry().center(); + const GlobalPosition& globalPos3 = elementPointer3->geometry().center(); + + const GlobalPosition& globalPosCenter = interactionVolume.getCenterPosition(); + + const DimMatrix& K1 = problem_.spatialParams().intrinsicPermeability(*elementPointer1); + const DimMatrix& K2 = problem_.spatialParams().intrinsicPermeability(*elementPointer2); + const DimMatrix& K3 = problem_.spatialParams().intrinsicPermeability(*elementPointer3); + + const GlobalPosition& globalPosFace12 = interactionVolume.getFacePosition(idx1, 0); + const GlobalPosition& globalPosFace23 = interactionVolume.getFacePosition(idx2, 0); + + // compute normal vectors nu1-nu7 in triangle R for first half edge + DimVector nu1R1(0); + R_.mv(globalPosFace12 - globalPos2, nu1R1); + + DimVector nu2R1(0); + R_.mv(globalPos2 - globalPosFace23, nu2R1); + + DimVector nu3R1(0); + R_.mv(globalPosFace23 - globalPos3, nu3R1); + + DimVector nu4R1(0); + R_.mv(globalPos3 - globalPosCenter, nu4R1); + + DimVector nu5R1(0); + R_.mv(globalPosCenter - globalPos1, nu5R1); + + DimVector nu6R1(0); + R_.mv(globalPos1 - globalPosFace12, nu6R1); + + DimVector nu7R1(0); + R_.mv(globalPosCenter - globalPos2, nu7R1); + + // compute T, i.e., the area of quadrilateral made by normal vectors 'nu' + DimVector Rnu2R1(0); + R_.mv(nu2R1, Rnu2R1); + Scalar T1R1 = nu1R1 * Rnu2R1; + + DimVector Rnu4R1(0); + R_.mv(nu4R1, Rnu4R1); + Scalar T2R1 = nu3R1 * Rnu4R1; + + DimVector Rnu6R1(0); + R_.mv(nu6R1, Rnu6R1); + Scalar T3R1 = nu5R1 * Rnu6R1; + + // compute components needed for flux calculation, denoted as 'omega' and 'chi' + DimVector K2nu1R1(0); + K2.mv(nu1R1, K2nu1R1); + DimVector K2nu2R1(0); + K2.mv(nu2R1, K2nu2R1); + DimVector K3nu3R1(0); + K3.mv(nu3R1, K3nu3R1); + DimVector K3nu4R1(0); + K3.mv(nu4R1, K3nu4R1); + DimVector K1nu5R1(0); + K1.mv(nu5R1, K1nu5R1); + DimVector K1nu6R1(0); + K1.mv(nu6R1, K1nu6R1); + + DimVector Rnu1R1(0); + R_.mv(nu1R1, Rnu1R1); + + DimVector &outerNormaln1R1 = interactionVolume.getNormal(idx2, 0); + DimVector &outerNormaln2 = interactionVolume.getNormal(idx1, 0); + + Scalar omega111R1 = lambda[idx2][0] * (outerNormaln1R1 * K2nu1R1) * interactionVolume.getFaceArea(idx2, 0) / T1R1; + Scalar omega112R1 = lambda[idx2][0] * (outerNormaln1R1 * K2nu2R1) * interactionVolume.getFaceArea(idx2, 0) / T1R1; + Scalar omega211R1 = lambda[idx2][1] * (outerNormaln2 * K2nu1R1) * interactionVolume.getFaceArea(idx2, 1) / T1R1; + Scalar omega212R1 = lambda[idx2][1] * (outerNormaln2 * K2nu2R1) * interactionVolume.getFaceArea(idx2, 1) / T1R1; + Scalar omega123R1 = lambda[idx3][1] * (outerNormaln1R1 * K3nu3R1) * interactionVolume.getFaceArea(idx3, 1) / T2R1; + Scalar omega124R1 = lambda[idx3][1] * (outerNormaln1R1 * K3nu4R1) * interactionVolume.getFaceArea(idx3, 1) / T2R1; + Scalar omega235R1 = lambda[idx1][0] * (outerNormaln2 * K1nu5R1) * interactionVolume.getFaceArea(idx1, 0) / T3R1; + Scalar omega236R1 = lambda[idx1][0] * (outerNormaln2 * K1nu6R1) * interactionVolume.getFaceArea(idx1, 0) / T3R1; + Scalar chi711R1 = (nu7R1 * Rnu1R1) / T1R1; + Scalar chi712R1 = (nu7R1 * Rnu2R1) / T1R1; + + // compute transmissibility matrix TR1 = CA^{-1}B+D + DimMatrix C(0), A(0); + TransmissibilityType D(0), B(0); + + // evaluate matrix C, D, A, B + C[0][0] = -omega111R1; + C[0][1] = -omega112R1; + C[1][0] = -omega211R1; + C[1][1] = -omega212R1; + + D[0][0] = omega111R1 + omega112R1; + D[1][0] = omega211R1 + omega212R1; + + A[0][0] = omega111R1 - omega124R1 - omega123R1 * chi711R1; + A[0][1] = omega112R1 - omega123R1 * chi712R1; + A[1][0] = omega211R1 - omega236R1 * chi711R1; + A[1][1] = omega212R1 - omega235R1 - omega236R1 * chi712R1; + + B[0][0] = omega111R1 + omega112R1 + omega123R1 * (1.0 - chi711R1 - chi712R1); + B[0][1] = -omega123R1 - omega124R1; + B[1][0] = omega211R1 + omega212R1 + omega236R1 * (1.0 - chi711R1 - chi712R1); + B[1][2] = -omega235R1 - omega236R1; + + // compute TR1 + A.invert(); + D += B.leftmultiply(C.rightmultiply(A)); + + transmissibilityRight = D; + return rightTriangle; +} +}// end of Dune namespace +#endif diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dvelocity2p.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dvelocity2p.hh new file mode 100644 index 0000000000000000000000000000000000000000..d6241a583c0c900f98cdc83b57cf0e41e49fc75e --- /dev/null +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dvelocity2p.hh @@ -0,0 +1,862 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +#ifndef DUMUX_FVMPFAL2DVELOCITY2P_HH +#define DUMUX_FVMPFAL2DVELOCITY2P_HH + + +#include <dune/grid/common/gridenums.hh> +#include <dumux/decoupled/2p/diffusion/diffusionproperties2p.hh> +#include <dumux/decoupled/common/fv/mpfa/fvmpfaproperties.hh> +#include <dumux/decoupled/common/fv/mpfa/mpfalinteractionvolume.hh> +#include "fvmpfal2dtransmissibilitycalculator.hh" + +/** + * @file + * @brief Velocity calculation using a 2-d MPFA L-method + */ + +namespace Dumux +{ +template<class TypeTag> class FvMpfaL2dVelocity2p +{ + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + enum + { + dim = GridView::dimension, dimWorld = GridView::dimensionworld + }; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + +#if DUNE_VERSION_NEWER(DUNE_GRID, 2, 3) + typedef typename Dune::ReferenceElements<Scalar, dim> ReferenceElements; + typedef typename Dune::ReferenceElement<Scalar, dim> ReferenceElement; +#else + typedef typename Dune::GenericReferenceElements<Scalar, dim> ReferenceElements; + typedef typename Dune::GenericReferenceElement<Scalar, dim> ReferenceElement; +#endif + + typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; + typedef typename SpatialParams::MaterialLaw MaterialLaw; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; + + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP(TypeTag, SolutionTypes) SolutionTypes; + typedef typename SolutionTypes::PrimaryVariables PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, CellData) CellData; + + typedef typename GridView::Traits::template Codim<0>::Entity Element; + typedef typename GridView::Grid Grid; + typedef typename GridView::IndexSet IndexSet; + typedef typename GridView::template Codim<0>::Iterator ElementIterator; + typedef typename GridView::template Codim<dim>::Iterator VertexIterator; + typedef typename GridView::IntersectionIterator IntersectionIterator; + typedef typename Grid::template Codim<0>::EntityPointer ElementPointer; + + typedef typename Element::Geometry Geometry; + #if DUNE_VERSION_NEWER(DUNE_GRID, 2, 3) + typedef typename Geometry::JacobianTransposed JacobianTransposed; + #else + typedef typename Geometry::Jacobian JacobianTransposed; + #endif + + typedef typename GET_PROP_TYPE(TypeTag, GridTypeIndices) GridTypeIndices; + + typedef typename Dumux::FVMPFALInteractionVolume<TypeTag> InteractionVolume; + typedef Dumux::FvMpfaL2dTransmissibilityCalculator<TypeTag> TransmissibilityCalculator; + typedef std::vector<Dune::FieldVector<bool, 2 * dim> > InnerBoundaryVolumeFaces; + + enum + { + pw = Indices::pressureW, + pn = Indices::pressureNw, + pglobal = Indices::pressureGlobal, + sw = Indices::saturationW, + sn = Indices::saturationNw, + vw = Indices::velocityW, + vn = Indices::velocityNw, + vt = Indices::velocityTotal + }; + enum + { + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + pressureIdx = Indices::pressureIdx, + saturationIdx = Indices::saturationIdx, + pressureEqIdx = Indices::pressureEqIdx, + satEqIdx = Indices::satEqIdx, + numPhases = GET_PROP_VALUE(TypeTag, NumPhases) + }; + + typedef Dune::FieldVector<Scalar, dim> LocalPosition; + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; + typedef Dune::FieldVector<Scalar, dim> DimVector; + +public: + FvMpfaL2dVelocity2p(Problem& problem) : + problem_(problem), transmissibilityCalculator_(problem), gravity_(problem.gravity()) + { + density_[wPhaseIdx] = 0.; + density_[nPhaseIdx] = 0.; + viscosity_[wPhaseIdx] = 0.; + viscosity_[nPhaseIdx] = 0.; + + vtkOutputLevel_ = GET_PARAM_FROM_GROUP(TypeTag, int, Vtk, OutputLevel); + } + + void calculateInnerInteractionVolumeVelocity(InteractionVolume& interactionVolume, CellData& cellData1, CellData& cellData2, CellData& cellData3, CellData& cellData4, InnerBoundaryVolumeFaces& innerBoundaryVolumeFaces); + void calculateBoundaryInteractionVolumeVelocity(InteractionVolume& interactionVolume, CellData& cellData, int elemIdx); + + void initialize() + { + ElementIterator element = problem_.gridView().template begin<0>(); + FluidState fluidState; + fluidState.setPressure(wPhaseIdx, problem_.referencePressure(*element)); + fluidState.setPressure(nPhaseIdx, problem_.referencePressure(*element)); + fluidState.setTemperature(problem_.temperature(*element)); + fluidState.setSaturation(wPhaseIdx, 1.); + fluidState.setSaturation(nPhaseIdx, 0.); + density_[wPhaseIdx] = FluidSystem::density(fluidState, wPhaseIdx); + density_[nPhaseIdx] = FluidSystem::density(fluidState, nPhaseIdx); + viscosity_[wPhaseIdx] = FluidSystem::viscosity(fluidState, wPhaseIdx); + viscosity_[nPhaseIdx] = FluidSystem::viscosity(fluidState, nPhaseIdx); + + return; + } + + //! \brief Write data files + /* \param name file name */ + template<class MultiWriter> + void addOutputVtkFields(MultiWriter &writer) + { + if (vtkOutputLevel_ > 0) + { + Dune::BlockVector < DimVector > &velocityWetting = *(writer.template allocateManagedBuffer<Scalar, dim>( + problem_.gridView().size(0))); + Dune::BlockVector < DimVector > &velocityNonwetting = *(writer.template allocateManagedBuffer<Scalar, dim>( + problem_.gridView().size(0))); + + // compute update vector + ElementIterator eEndIt = problem_.gridView().template end<0>(); + for (ElementIterator eIt = problem_.gridView().template begin<0>(); eIt != eEndIt; ++eIt) + { + // cell index + int globalIdx = problem_.variables().index(*eIt); + + CellData & cellData = problem_.variables().cellData(globalIdx); + + Dune::FieldVector < Scalar, 2 * dim > fluxW(0); + Dune::FieldVector < Scalar, 2 * dim > fluxNw(0); + + // run through all intersections with neighbors and boundary + IntersectionIterator isEndIt = problem_.gridView().iend(*eIt); + for (IntersectionIterator isIt = problem_.gridView().ibegin(*eIt); isIt != isEndIt; ++isIt) + { + int isIndex = isIt->indexInInside(); + + fluxW[isIndex] += isIt->geometry().volume() + * (isIt->centerUnitOuterNormal() * cellData.fluxData().velocity(wPhaseIdx, isIndex)); + fluxNw[isIndex] += isIt->geometry().volume() + * (isIt->centerUnitOuterNormal() * cellData.fluxData().velocity(nPhaseIdx, isIndex)); + } + + DimVector refVelocity(0); + refVelocity[0] = 0.5 * (fluxW[1] - fluxW[0]); + refVelocity[1] = 0.5 * (fluxW[3] - fluxW[2]); + + const DimVector& localPos = ReferenceElements::general(eIt->geometry().type()).position(0, 0); + + // get the transposed Jacobian of the element mapping + const JacobianTransposed jacobianT = eIt->geometry().jacobianTransposed(localPos); + + // calculate the element velocity by the Piola transformation + DimVector elementVelocity(0); + jacobianT.umtv(refVelocity, elementVelocity); + elementVelocity /= eIt->geometry().integrationElement(localPos); + + velocityWetting[globalIdx] = elementVelocity; + + refVelocity = 0; + refVelocity[0] = 0.5 * (fluxNw[1] - fluxNw[0]); + refVelocity[1] = 0.5 * (fluxNw[3] - fluxNw[2]); + + // calculate the element velocity by the Piola transformation + elementVelocity = 0; + jacobianT.umtv(refVelocity, elementVelocity); + elementVelocity /= eIt->geometry().integrationElement(localPos); + + velocityNonwetting[globalIdx] = elementVelocity; + } + + writer.attachCellData(velocityWetting, "wetting-velocity", dim); + writer.attachCellData(velocityNonwetting, "non-wetting-velocity", dim); + } + + return; + } + +private: + Problem& problem_; +protected: + TransmissibilityCalculator transmissibilityCalculator_; + + const GlobalPosition& gravity_; //!< vector including the gravity constant + + Scalar density_[numPhases]; + Scalar viscosity_[numPhases]; + + int vtkOutputLevel_; + + static constexpr Scalar threshold_ = 1e-15; + static const int velocityType_ = GET_PROP_VALUE(TypeTag, VelocityFormulation);//!< gives kind of velocity used (\f$ 0 = v_w\f$, \f$ 1 = v_n\f$, \f$ 2 = v_t\f$) + static const int pressureType_ = GET_PROP_VALUE(TypeTag, PressureFormulation);//!< gives kind of pressure used (\f$ 0 = p_w\f$, \f$ 1 = p_n\f$, \f$ 2 = p_{global}\f$) + static const int saturationType_ = GET_PROP_VALUE(TypeTag, SaturationFormulation);//!< gives kind of saturation used (\f$ 0 = S_w\f$, \f$ 1 = S_n\f$) +}; +// end of template + +template<class TypeTag> +void FvMpfaL2dVelocity2p<TypeTag>::calculateInnerInteractionVolumeVelocity(InteractionVolume& interactionVolume, CellData& cellData1, CellData& cellData2, CellData& cellData3, CellData& cellData4, InnerBoundaryVolumeFaces& innerBoundaryVolumeFaces) +{ + ElementPointer & elementPointer1 = interactionVolume.getSubVolumeElement(0); + ElementPointer & elementPointer2 = interactionVolume.getSubVolumeElement(1); + ElementPointer & elementPointer3 = interactionVolume.getSubVolumeElement(2); + ElementPointer & elementPointer4 = interactionVolume.getSubVolumeElement(3); + + int level1 = elementPointer1->level(); + int level2 = elementPointer2->level(); + int level3 = elementPointer3->level(); + int level4 = elementPointer4->level(); + + // cell index + int globalIdx1 = problem_.variables().index(*elementPointer1); + int globalIdx2 = problem_.variables().index(*elementPointer2); + int globalIdx3 = problem_.variables().index(*elementPointer3); + int globalIdx4 = problem_.variables().index(*elementPointer4); + + // get pressure values + Dune::FieldVector < Scalar, 2 * dim > potW(0); + Dune::FieldVector < Scalar, 2 * dim > potNw(0); + + potW[0] = cellData1.potential(wPhaseIdx); + potW[1] = cellData2.potential(wPhaseIdx); + potW[2] = cellData3.potential(wPhaseIdx); + potW[3] = cellData4.potential(wPhaseIdx); + + potNw[0] = cellData1.potential(nPhaseIdx); + potNw[1] = cellData2.potential(nPhaseIdx); + potNw[2] = cellData3.potential(nPhaseIdx); + potNw[3] = cellData4.potential(nPhaseIdx); + + //get mobilities of the phases + Dune::FieldVector < Scalar, numPhases > lambda1(cellData1.mobility(wPhaseIdx)); + lambda1[nPhaseIdx] = cellData1.mobility(nPhaseIdx); + + //compute total mobility of cell 1 + Scalar lambdaTotal1 = lambda1[wPhaseIdx] + lambda1[nPhaseIdx]; + + //get mobilities of the phases + Dune::FieldVector < Scalar, numPhases > lambda2(cellData2.mobility(wPhaseIdx)); + lambda2[nPhaseIdx] = cellData2.mobility(nPhaseIdx); + + //compute total mobility of cell 1 + Scalar lambdaTotal2 = lambda2[wPhaseIdx] + lambda2[nPhaseIdx]; + + //get mobilities of the phases + Dune::FieldVector < Scalar, numPhases > lambda3(cellData3.mobility(wPhaseIdx)); + lambda3[nPhaseIdx] = cellData3.mobility(nPhaseIdx); + + //compute total mobility of cell 1 + Scalar lambdaTotal3 = lambda3[wPhaseIdx] + lambda3[nPhaseIdx]; + + //get mobilities of the phases + Dune::FieldVector < Scalar, numPhases > lambda4(cellData4.mobility(wPhaseIdx)); + lambda4[nPhaseIdx] = cellData4.mobility(nPhaseIdx); + + //compute total mobility of cell 1 + Scalar lambdaTotal4 = lambda4[wPhaseIdx] + lambda4[nPhaseIdx]; + + + std::vector < DimVector > lambda(2 * dim); + + lambda[0][0] = lambdaTotal1; + lambda[0][1] = lambdaTotal1; + lambda[1][0] = lambdaTotal2; + lambda[1][1] = lambdaTotal2; + lambda[2][0] = lambdaTotal3; + lambda[2][1] = lambdaTotal3; + lambda[3][0] = lambdaTotal4; + lambda[3][1] = lambdaTotal4; + + Scalar potentialDiffW12 = 0; + Scalar potentialDiffW14 = 0; + Scalar potentialDiffW32 = 0; + Scalar potentialDiffW34 = 0; + + Scalar potentialDiffNw12 = 0; + Scalar potentialDiffNw14 = 0; + Scalar potentialDiffNw32 = 0; + Scalar potentialDiffNw34 = 0; + + //flux vector + Dune::FieldVector < Scalar, 2 * dim > fluxW(0); + Dune::FieldVector < Scalar, 2 * dim > fluxNw(0); + + Dune::FieldMatrix < Scalar, dim, 2 * dim - dim + 1 > T(0); + DimVector Tu(0); + Dune::FieldVector<Scalar, 2 * dim - dim + 1> u(0); + + int lType = transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 0, 1, 2, 3); + + if (lType == TransmissibilityCalculator::rightTriangle) + { + u[0] = potW[1]; + u[1] = potW[2]; + u[2] = potW[0]; + + T.mv(u, Tu); + + fluxW[0] = Tu[1]; + potentialDiffW12 = Tu[1]; + + u[0] = potNw[1]; + u[1] = potNw[2]; + u[2] = potNw[0]; + + T.mv(u, Tu); + + fluxNw[0] = Tu[1]; + potentialDiffNw12 = Tu[1]; + } + else + { + u[0] = potW[0]; + u[1] = potW[3]; + u[2] = potW[1]; + + T.mv(u, Tu); + + fluxW[0] = Tu[1]; + potentialDiffW12 = Tu[1]; + + u[0] = potNw[0]; + u[1] = potNw[3]; + u[2] = potNw[1]; + + T.mv(u, Tu); + + fluxNw[0] = Tu[1]; + potentialDiffNw12 = Tu[1]; + } + + lType = transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 1, 2, 3, 0); + + if (lType == TransmissibilityCalculator::rightTriangle) + { + u[0] = potW[2]; + u[1] = potW[3]; + u[2] = potW[1]; + + T.mv(u, Tu); + + fluxW[1] = Tu[1]; + potentialDiffW32 = -Tu[1]; + + u[0] = potNw[2]; + u[1] = potNw[3]; + u[2] = potNw[1]; + + T.mv(u, Tu); + + fluxNw[1] = Tu[1]; + potentialDiffNw32 = -Tu[1]; + } + else + { + u[0] = potW[1]; + u[1] = potW[0]; + u[2] = potW[2]; + + T.mv(u, Tu); + + fluxW[1] = Tu[1]; + potentialDiffW32 = -Tu[1]; + + u[0] = potNw[1]; + u[1] = potNw[0]; + u[2] = potNw[2]; + + T.mv(u, Tu); + + fluxNw[1] = Tu[1]; + potentialDiffNw32 = -Tu[1]; + } + + lType = transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 2, 3, 0, 1); + + if (lType == TransmissibilityCalculator::rightTriangle) + { + u[0] = potW[3]; + u[1] = potW[0]; + u[2] = potW[2]; + + T.mv(u, Tu); + + fluxW[2] = Tu[1]; + potentialDiffW34 = Tu[1]; + + u[0] = potNw[3]; + u[1] = potNw[0]; + u[2] = potNw[2]; + + T.mv(u, Tu); + + fluxNw[2] = Tu[1]; + potentialDiffNw34 = Tu[1]; + } + else + { + u[0] = potW[2]; + u[1] = potW[1]; + u[2] = potW[3]; + + T.mv(u, Tu); + + fluxW[2] = Tu[1]; + potentialDiffW34 = Tu[1]; + + u[0] = potNw[2]; + u[1] = potNw[1]; + u[2] = potNw[3]; + + T.mv(u, Tu); + + fluxNw[2] = Tu[1]; + potentialDiffNw34 = Tu[1]; + } + + lType = transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 3, 0, 1, 2); + + if (lType == TransmissibilityCalculator::rightTriangle) + { + u[0] = potW[0]; + u[1] = potW[1]; + u[2] = potW[3]; + + T.mv(u, Tu); + + fluxW[3] = Tu[1]; + potentialDiffW14 = -Tu[1]; + + u[0] = potNw[0]; + u[1] = potNw[1]; + u[2] = potNw[3]; + + T.mv(u, Tu); + + fluxNw[3] = Tu[1]; + potentialDiffNw14 = -Tu[1]; + } + else + { + u[0] = potW[3]; + u[1] = potW[2]; + u[2] = potW[0]; + + T.mv(u, Tu); + + fluxW[3] = Tu[1]; + potentialDiffW14 = -Tu[1]; + + u[0] = potNw[3]; + u[1] = potNw[2]; + u[2] = potNw[0]; + + T.mv(u, Tu); + + fluxNw[3] = Tu[1]; + potentialDiffNw14 = -Tu[1]; + } + + //store potentials for further calculations (saturation, ...) + cellData1.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(0, 0), potentialDiffW12); + cellData1.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(0, 0), potentialDiffNw12); + cellData1.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(0, 1), potentialDiffW14); + cellData1.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(0, 1), potentialDiffNw14); + cellData2.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(1, 0), -potentialDiffW32); + cellData2.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(1, 0), -potentialDiffNw32); + cellData2.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(1, 1), -potentialDiffW12); + cellData2.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(1, 1), -potentialDiffNw12); + cellData3.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(2, 0), potentialDiffW34); + cellData3.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(2, 0), potentialDiffNw34); + cellData3.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(2, 1), potentialDiffW32); + cellData3.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(2, 1), potentialDiffNw32); + cellData4.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(3, 0), -potentialDiffW14); + cellData4.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(3, 0), -potentialDiffNw14); + cellData4.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(3, 1), -potentialDiffW34); + cellData4.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(3, 1), -potentialDiffNw34); + + //compute mobilities of face 1 + Dune::FieldVector < Scalar, numPhases > lambda12Upw(0.0); + lambda12Upw[wPhaseIdx] = (potentialDiffW12 >= 0) ? lambda1[wPhaseIdx] : lambda2[wPhaseIdx]; + lambda12Upw[nPhaseIdx] = (potentialDiffNw12 >= 0) ? lambda1[nPhaseIdx] : lambda2[nPhaseIdx]; + + //compute mobilities of face 4 + Dune::FieldVector < Scalar, numPhases > lambda14Upw(0.0); + lambda14Upw[wPhaseIdx] = (potentialDiffW14 >= 0) ? lambda1[wPhaseIdx] : lambda4[wPhaseIdx]; + lambda14Upw[nPhaseIdx] = (potentialDiffNw14 >= 0) ? lambda1[nPhaseIdx] : lambda4[nPhaseIdx]; + + //compute mobilities of face 2 + Dune::FieldVector < Scalar, numPhases > lambda32Upw(0.0); + lambda32Upw[wPhaseIdx] = (potentialDiffW32 >= 0) ? lambda3[wPhaseIdx] : lambda2[wPhaseIdx]; + lambda32Upw[nPhaseIdx] = (potentialDiffNw32 >= 0) ? lambda3[nPhaseIdx] : lambda2[nPhaseIdx]; + + //compute mobilities of face 3 + Dune::FieldVector < Scalar, numPhases > lambda34Upw(0.0); + lambda34Upw[wPhaseIdx] = (potentialDiffW34 >= 0) ? lambda3[wPhaseIdx] : lambda4[wPhaseIdx]; + lambda34Upw[nPhaseIdx] = (potentialDiffNw34 >= 0) ? lambda3[nPhaseIdx] : lambda4[nPhaseIdx]; + + for (int i = 0; i < numPhases; i++) + { + // evaluate parts of velocity + DimVector vel12 = interactionVolume.getNormal(0, 0); + DimVector vel14 = interactionVolume.getNormal(3, 0); + DimVector vel23 = interactionVolume.getNormal(1, 0); + DimVector vel21 = interactionVolume.getNormal(0, 0); + DimVector vel34 = interactionVolume.getNormal(2, 0); + DimVector vel32 = interactionVolume.getNormal(1, 0); + DimVector vel41 = interactionVolume.getNormal(3, 0); + DimVector vel43 = interactionVolume.getNormal(2, 0); + + Dune::FieldVector < Scalar, 2 * dim > flux(0); + switch (i) + { + case wPhaseIdx: + { + flux = fluxW; + break; + } + case nPhaseIdx: + { + flux = fluxNw; + break; + } + } + + vel12 *= flux[0] / (2 * interactionVolume.getFaceArea(0, 0)); //divide by 2 because the flux is related to the half face! + vel14 *= flux[3] / (2 * interactionVolume.getFaceArea(0, 1)); + vel23 *= flux[1] / (2 * interactionVolume.getFaceArea(1, 0)); + vel21 *= flux[0] / (2 * interactionVolume.getFaceArea(1, 1)); + vel34 *= flux[2] / (2 * interactionVolume.getFaceArea(2, 0)); + vel32 *= flux[1] / (2 * interactionVolume.getFaceArea(2, 1)); + vel41 *= flux[3] / (2 * interactionVolume.getFaceArea(3, 0)); + vel43 *= flux[2] / (2 * interactionVolume.getFaceArea(3, 1)); + + if (level1 < level2) + { + vel12 *= 0.5; + } + else if (level2 < level1) + { + vel21 *= 0.5; + } + if (level2 < level3) + { + vel23 *= 0.5; + } + else if (level3 < level2) + { + vel32 *= 0.5; + } + if (level3 < level4) + { + vel34 *= 0.5; + } + else if (level4 < level3) + { + vel43 *= 0.5; + } + if (level4 < level1) + { + vel41 *= 0.5; + } + else if (level1 < level4) + { + vel14 *= 0.5; + } + + Scalar lambdaT12 = lambda12Upw[wPhaseIdx] + lambda12Upw[nPhaseIdx]; + Scalar lambdaT14 = lambda14Upw[wPhaseIdx] + lambda14Upw[nPhaseIdx]; + Scalar lambdaT32 = lambda32Upw[wPhaseIdx] + lambda32Upw[nPhaseIdx]; + Scalar lambdaT34 = lambda34Upw[wPhaseIdx] + lambda34Upw[nPhaseIdx]; + Scalar fracFlow12 = (lambdaT12 > threshold_) ? lambda12Upw[i] / (lambdaT12) : 0.0; + Scalar fracFlow14 = (lambdaT14 > threshold_) ? lambda14Upw[i] / (lambdaT14) : 0.0; + Scalar fracFlow32 = (lambdaT32 > threshold_) ? lambda32Upw[i] / (lambdaT32) : 0.0; + Scalar fracFlow34 = (lambdaT34 > threshold_) ? lambda34Upw[i] / (lambdaT34) : 0.0; + + vel12 *= fracFlow12; + vel14 *= fracFlow14; + vel23 *= fracFlow32; + vel21 *= fracFlow12; + vel34 *= fracFlow34; + vel32 *= fracFlow32; + vel41 *= fracFlow14; + vel43 *= fracFlow34; + + if (innerBoundaryVolumeFaces[globalIdx1][interactionVolume.getIndexOnElement(0, 0)]) + { + vel12 *= 2; + } + if (innerBoundaryVolumeFaces[globalIdx1][interactionVolume.getIndexOnElement(0, 1)]) + { + vel14 *= 2; + } + if (innerBoundaryVolumeFaces[globalIdx2][interactionVolume.getIndexOnElement(1, 0)]) + { + vel23 *= 2; + } + if (innerBoundaryVolumeFaces[globalIdx2][interactionVolume.getIndexOnElement(1, 1)]) + { + vel21 *= 2; + } + if (innerBoundaryVolumeFaces[globalIdx3][interactionVolume.getIndexOnElement(2, 0)]) + { + vel34 *= 2; + } + if (innerBoundaryVolumeFaces[globalIdx3][interactionVolume.getIndexOnElement(2, 1)]) + { + vel32 *= 2; + } + if (innerBoundaryVolumeFaces[globalIdx4][interactionVolume.getIndexOnElement(3, 0)]) + { + vel41 *= 2; + } + if (innerBoundaryVolumeFaces[globalIdx4][interactionVolume.getIndexOnElement(3, 1)]) + { + vel43 *= 2; + } + + //store velocities + cellData1.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(0, 0), vel12); + cellData1.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(0, 1), vel14); + cellData2.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(1, 0), vel23); + cellData2.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(1, 1), vel21); + cellData3.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(2, 0), vel34); + cellData3.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(2, 1), vel32); + cellData4.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(3, 0), vel41); + cellData4.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(3, 1), vel43); + } + //set velocity marker + cellData1.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(0, 0)); + cellData1.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(0, 1)); + cellData2.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(1, 0)); + cellData2.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(1, 1)); + cellData3.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(2, 0)); + cellData3.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(2, 1)); + cellData4.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(3, 0)); + cellData4.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(3, 1)); +} + +template<class TypeTag> +void FvMpfaL2dVelocity2p<TypeTag>::calculateBoundaryInteractionVolumeVelocity(InteractionVolume& interactionVolume, CellData& cellData, int elemIdx) +{ + ElementPointer & elementPointer = interactionVolume.getSubVolumeElement(elemIdx); + + // get global coordinate of cell centers + const GlobalPosition& globalPos = elementPointer->geometry().center(); + + //permeability vector at boundary + DimMatrix permeability(problem_.spatialParams().intrinsicPermeability(*elementPointer)); + + //get mobilities of the phases + Dune::FieldVector < Scalar, numPhases > lambda(cellData.mobility(wPhaseIdx)); + lambda[nPhaseIdx] = cellData.mobility(nPhaseIdx); + + for (int faceIdx = 0; faceIdx < dim; faceIdx++) + { + int intVolFaceIdx = interactionVolume.getFaceIndexFromSubVolume(elemIdx, faceIdx); + + if (interactionVolume.isBoundaryFace(intVolFaceIdx)) + { + if (interactionVolume.getBoundaryType(intVolFaceIdx).isDirichlet(pressureEqIdx)) + { + int boundaryFaceIdx = interactionVolume.getIndexOnElement(elemIdx, faceIdx); + + const ReferenceElement& referenceElement = ReferenceElements::general( + elementPointer->geometry().type()); + + const LocalPosition& localPos = referenceElement.position(boundaryFaceIdx, 1); + + const GlobalPosition& globalPosFace = elementPointer->geometry().global(localPos); + + DimVector distVec(globalPosFace - globalPos); + Scalar dist = distVec.two_norm(); + DimVector unitDistVec(distVec); + unitDistVec /= dist; + + // get pc and lambda at the boundary + Scalar satWBound = cellData.saturation(wPhaseIdx); + //check boundary sat at face 1 + if (interactionVolume.getBoundaryType(intVolFaceIdx).isDirichlet(satEqIdx)) + { + Scalar satBound = interactionVolume.getDirichletValues(intVolFaceIdx)[saturationIdx]; + switch (saturationType_) + { + case sw: + { + satWBound = satBound; + break; + } + case sn: + { + satWBound = 1 - satBound; + break; + } + } + + } + + Scalar pcBound = MaterialLaw::pc( + problem_.spatialParams().materialLawParams(*elementPointer), satWBound); + + Scalar gravityDiffBound = (problem_.bBoxMax() - globalPosFace) * gravity_ + * (density_[nPhaseIdx] - density_[wPhaseIdx]); + + pcBound += gravityDiffBound; + + Dune::FieldVector < Scalar, numPhases + > lambdaBound( + MaterialLaw::krw( + problem_.spatialParams().materialLawParams(*elementPointer), + satWBound)); + lambdaBound[nPhaseIdx] = MaterialLaw::krn( + problem_.spatialParams().materialLawParams(*elementPointer), satWBound); + lambdaBound[wPhaseIdx] /= viscosity_[wPhaseIdx]; + lambdaBound[nPhaseIdx] /= viscosity_[nPhaseIdx]; + + Scalar gdeltaZ = (problem_.bBoxMax()-globalPosFace) * gravity_; + Scalar potentialBoundW = interactionVolume.getDirichletValues(intVolFaceIdx)[pressureIdx] + density_[wPhaseIdx]*gdeltaZ; + Scalar potentialBoundNw = potentialBoundW; + + //calculate potential gradients + switch (pressureType_) + { + case pw: + { + potentialBoundNw += pcBound; + break; + } + case pn: + { + //calculate potential gradients + potentialBoundW -= pcBound; + break; + } + } + + Scalar potentialDiffW = (cellData.potential(wPhaseIdx) - potentialBoundW) / dist; + Scalar potentialDiffNw = (cellData.potential(nPhaseIdx) - potentialBoundNw) / dist; + + //store potentials for further calculations (saturation, ...) + cellData.fluxData().addUpwindPotential(wPhaseIdx, boundaryFaceIdx, potentialDiffW); + cellData.fluxData().addUpwindPotential(nPhaseIdx, boundaryFaceIdx, potentialDiffNw); + + //calculated phase velocities from advective velocities -> capillary pressure velocity already added in pressure part! + DimVector velocityW(0); + DimVector velocityNw(0); + + // calculate capillary pressure gradient + DimVector pressGradient = unitDistVec; + pressGradient *= (cellData.potential(wPhaseIdx) - potentialBoundW) / dist; + permeability.mv(pressGradient, velocityW); + + pressGradient = unitDistVec; + pressGradient *= (cellData.potential(nPhaseIdx) - potentialBoundNw) / dist; + permeability.mv(pressGradient, velocityNw); + + velocityW *= (potentialDiffW >= 0.) ? lambda[wPhaseIdx] : lambdaBound[wPhaseIdx]; + velocityNw *= (potentialDiffNw >= 0.) ? lambda[nPhaseIdx] : lambdaBound[nPhaseIdx]; + + //velocity is calculated from two vertices of one intersection! + velocityW *= 0.5; + velocityNw *= 0.5; + + //store velocities + velocityW += cellData.fluxData().velocity(wPhaseIdx, boundaryFaceIdx); + velocityNw += cellData.fluxData().velocity(nPhaseIdx, boundaryFaceIdx); + cellData.fluxData().setVelocity(wPhaseIdx, boundaryFaceIdx, velocityW); + cellData.fluxData().setVelocity(nPhaseIdx, boundaryFaceIdx, velocityNw); + cellData.fluxData().setVelocityMarker(boundaryFaceIdx); + } + else if (interactionVolume.getBoundaryType(intVolFaceIdx).isNeumann(pressureEqIdx)) + { + int boundaryFaceIdx = interactionVolume.getIndexOnElement(elemIdx, faceIdx); + + const ReferenceElement& referenceElement = ReferenceElements::general( + elementPointer->geometry().type()); + + const LocalPosition& localPos = referenceElement.position(boundaryFaceIdx, 1); + + const GlobalPosition& globalPosFace = elementPointer->geometry().global(localPos); + + DimVector distVec(globalPosFace - globalPos); + Scalar dist = distVec.two_norm(); + DimVector unitDistVec(distVec); + unitDistVec /= dist; + + // get neumann boundary value + PrimaryVariables boundValues(interactionVolume.getNeumannValues(intVolFaceIdx)); + + boundValues[wPhaseIdx] /= density_[wPhaseIdx]; + boundValues[nPhaseIdx] /= density_[nPhaseIdx]; + + DimVector velocityW(unitDistVec); + DimVector velocityNw(unitDistVec); + + velocityW *= boundValues[wPhaseIdx] / (2 * interactionVolume.getFaceArea(elemIdx, faceIdx)); + velocityNw *= boundValues[nPhaseIdx] + / (2 * interactionVolume.getFaceArea(elemIdx, faceIdx)); + + //store potentials for further calculations (saturation, ...) + cellData.fluxData().addUpwindPotential(wPhaseIdx, boundaryFaceIdx, boundValues[wPhaseIdx]); + cellData.fluxData().addUpwindPotential(nPhaseIdx, boundaryFaceIdx, boundValues[nPhaseIdx]); + + //store velocities + velocityW += cellData.fluxData().velocity(wPhaseIdx, boundaryFaceIdx); + velocityNw += cellData.fluxData().velocity(nPhaseIdx, boundaryFaceIdx); + cellData.fluxData().setVelocity(wPhaseIdx, boundaryFaceIdx, velocityW); + cellData.fluxData().setVelocity(nPhaseIdx, boundaryFaceIdx, velocityNw); + cellData.fluxData().setVelocityMarker(boundaryFaceIdx); + } + else + { + DUNE_THROW(Dune::NotImplemented, + "No valid boundary condition type defined for pressure equation!"); + } + } + } +} + +} +// end of Dune namespace +#endif diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dvelocity2padaptive.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dvelocity2padaptive.hh new file mode 100644 index 0000000000000000000000000000000000000000..eb6059d73a5cd837df88bf4992c549b307afb0d0 --- /dev/null +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dvelocity2padaptive.hh @@ -0,0 +1,395 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +#ifndef DUMUX_FVMPFAL2DVELOCITY2P_ADAPTIVE_HH +#define DUMUX_FVMPFAL2DVELOCITY2P_ADAPTIVE_HH + + +#include "fvmpfal2dvelocity2p.hh" + +/** + * @file + * @brief Velocity calculation using a 2-d MPFA L-method + */ + +namespace Dumux +{ +template<class TypeTag> class FvMpfaL2dVelocity2pAdaptive : public FvMpfaL2dVelocity2p<TypeTag> +{ + typedef FvMpfaL2dVelocity2p<TypeTag> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + enum + { + dim = GridView::dimension, dimWorld = GridView::dimensionworld + }; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + +#if DUNE_VERSION_NEWER(DUNE_GRID, 2, 3) + typedef typename Dune::ReferenceElements<Scalar, dim> ReferenceElements; + typedef typename Dune::ReferenceElement<Scalar, dim> ReferenceElement; +#else + typedef typename Dune::GenericReferenceElements<Scalar, dim> ReferenceElements; + typedef typename Dune::GenericReferenceElement<Scalar, dim> ReferenceElement; +#endif + + typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; + typedef typename SpatialParams::MaterialLaw MaterialLaw; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; + + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP(TypeTag, SolutionTypes) SolutionTypes; + typedef typename SolutionTypes::PrimaryVariables PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, CellData) CellData; + + typedef typename GridView::Traits::template Codim<0>::Entity Element; + typedef typename GridView::Grid Grid; + typedef typename GridView::IndexSet IndexSet; + typedef typename GridView::template Codim<0>::Iterator ElementIterator; + typedef typename GridView::template Codim<dim>::Iterator VertexIterator; + typedef typename GridView::IntersectionIterator IntersectionIterator; + typedef typename Grid::template Codim<0>::EntityPointer ElementPointer; + + typedef typename Element::Geometry Geometry; + #if DUNE_VERSION_NEWER(DUNE_GRID, 2, 3) + typedef typename Geometry::JacobianTransposed JacobianTransposed; + #else + typedef typename Geometry::Jacobian JacobianTransposed; + #endif + + typedef typename GET_PROP_TYPE(TypeTag, GridTypeIndices) GridTypeIndices; + + typedef typename Dumux::FVMPFALInteractionVolume<TypeTag> InteractionVolume; + typedef std::vector<Dune::FieldVector<bool, 2 * dim> > InnerBoundaryVolumeFaces; + typedef Dumux::FvMpfaL2dTransmissibilityCalculator<TypeTag> TransmissibilityCalculator; + + enum + { + pw = Indices::pressureW, + pn = Indices::pressureNw, + pglobal = Indices::pressureGlobal, + sw = Indices::saturationW, + sn = Indices::saturationNw, + vw = Indices::velocityW, + vn = Indices::velocityNw, + vt = Indices::velocityTotal + }; + enum + { + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + pressureIdx = Indices::pressureIdx, + saturationIdx = Indices::saturationIdx, + pressureEqIdx = Indices::pressureEqIdx, + satEqIdx = Indices::satEqIdx, + numPhases = GET_PROP_VALUE(TypeTag, NumPhases) + }; + + typedef Dune::FieldVector<Scalar, dim> LocalPosition; + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; + typedef Dune::FieldVector<Scalar, dim> DimVector; + +public: + FvMpfaL2dVelocity2pAdaptive(Problem& problem) : + ParentType(problem), problem_(problem) + {} + + void calculateHangingNodeInteractionVolumeVelocity(InteractionVolume& interactionVolume, CellData& cellData1, CellData& cellData2, CellData& cellData4, InnerBoundaryVolumeFaces& innerBoundaryVolumeFaces); + +private: + Problem& problem_; +}; +// end of template + +template<class TypeTag> +void FvMpfaL2dVelocity2pAdaptive<TypeTag>::calculateHangingNodeInteractionVolumeVelocity(InteractionVolume& interactionVolume, CellData& cellData1, CellData& cellData2, CellData& cellData4, InnerBoundaryVolumeFaces& innerBoundaryVolumeFaces) +{ + ElementPointer & elementPointer1 = interactionVolume.getSubVolumeElement(0); + ElementPointer & elementPointer2 = interactionVolume.getSubVolumeElement(1); + ElementPointer & elementPointer4 = interactionVolume.getSubVolumeElement(3); + + // cell index + int globalIdx1 = problem_.variables().index(*elementPointer1); + int globalIdx2 = problem_.variables().index(*elementPointer2); + int globalIdx4 = problem_.variables().index(*elementPointer4); + + // get pressure values + Dune::FieldVector < Scalar, 2 * dim > potW(0); + Dune::FieldVector < Scalar, 2 * dim > potNw(0); + + potW[0] = cellData1.potential(wPhaseIdx); + potW[1] = cellData2.potential(wPhaseIdx); + potW[2] = cellData4.potential(wPhaseIdx); + + potNw[0] = cellData1.potential(nPhaseIdx); + potNw[1] = cellData2.potential(nPhaseIdx); + potNw[2] = cellData4.potential(nPhaseIdx); + + //get mobilities of the phases + Dune::FieldVector<Scalar, numPhases> lambda1(cellData1.mobility(wPhaseIdx)); + lambda1[nPhaseIdx] = cellData1.mobility(nPhaseIdx); + + //compute total mobility of cell 1 + Scalar lambdaTotal1 = lambda1[wPhaseIdx] + lambda1[nPhaseIdx]; + + //get mobilities of the phases + Dune::FieldVector<Scalar, numPhases> lambda2(cellData2.mobility(wPhaseIdx)); + lambda2[nPhaseIdx] = cellData2.mobility(nPhaseIdx); + + //compute total mobility of cell 1 + Scalar lambdaTotal2 = lambda2[wPhaseIdx] + lambda2[nPhaseIdx]; + + //get mobilities of the phases + Dune::FieldVector<Scalar, numPhases> lambda4(cellData4.mobility(wPhaseIdx)); + lambda4[nPhaseIdx] = cellData4.mobility(nPhaseIdx); + + //compute total mobility of cell 1 + Scalar lambdaTotal4 = lambda4[wPhaseIdx] + lambda4[nPhaseIdx]; + + std::vector < DimVector > lambda(4); + + lambda[0][0] = lambdaTotal1; + lambda[0][1] = lambdaTotal1; + lambda[1][0] = lambdaTotal2; + lambda[1][1] = lambdaTotal2; + lambda[3][0] = lambdaTotal4; + lambda[3][1] = lambdaTotal4; + + Scalar potentialDiffW12 = 0; + Scalar potentialDiffW14 = 0; + Scalar potentialDiffW24 = 0; + + Scalar potentialDiffNw12 = 0; + Scalar potentialDiffNw14 = 0; + Scalar potentialDiffNw24 = 0; + + //flux vector + Dune::FieldVector<Scalar, 3> fluxW(0); + Dune::FieldVector<Scalar, 3> fluxNw(0); + + Dune::FieldMatrix<Scalar, dim, 2 * dim - dim + 1> T(0); + DimVector Tu(0); + Dune::FieldVector<Scalar, 2 * dim - dim + 1> u(0); + + int transmissibilityType = this->transmissibilityCalculator_.calculateTransmissibility(T, interactionVolume, lambda, 0, 1, 3, 3); + + if (transmissibilityType == TransmissibilityCalculator::rightTriangle) + { + u[0] = potW[1]; + u[1] = potW[2]; + u[2] = potW[0]; + + T.mv(u, Tu); + + fluxW[0] = Tu[1]; + potentialDiffW12 = Tu[1]; + + u[0] = potNw[1]; + u[1] = potNw[2]; + u[2] = potNw[0]; + + T.mv(u, Tu); + + fluxNw[0] = Tu[1]; + potentialDiffNw12 = Tu[1]; + } + else if (transmissibilityType == TransmissibilityCalculator::leftTriangle) + { + u[0] = potW[0]; + u[1] = potW[2]; + u[2] = potW[1]; + + T.mv(u, Tu); + + fluxW[0] = Tu[1]; + potentialDiffW12 = Tu[1]; + + u[0] = potNw[0]; + u[1] = potNw[2]; + u[2] = potNw[1]; + + T.mv(u, Tu); + + fluxNw[0] = Tu[1]; + potentialDiffNw12 = Tu[1]; + } + + transmissibilityType = this->transmissibilityCalculator_.calculateLeftHNTransmissibility(T, interactionVolume, lambda, 1, 3, 0); + + if (transmissibilityType == TransmissibilityCalculator::leftTriangle) + { + u[0] = potW[1]; + u[1] = potW[0]; + u[2] = potW[2]; + + T.mv(u, Tu); + + fluxW[1] = Tu[1]; + potentialDiffW24 = Tu[1]; + + u[0] = potNw[1]; + u[1] = potNw[0]; + u[2] = potNw[2]; + + T.mv(u, Tu); + + fluxNw[1] = Tu[1]; + potentialDiffNw24 = Tu[1]; + } + + transmissibilityType = this->transmissibilityCalculator_.calculateRightHNTransmissibility(T, interactionVolume, lambda, 3, 0, 1); + + if (transmissibilityType == TransmissibilityCalculator::rightTriangle) + { + u[0] = potW[0]; + u[1] = potW[1]; + u[2] = potW[2]; + + T.mv(u, Tu); + + fluxW[2] = Tu[1]; + potentialDiffW14 = -Tu[1]; + + u[0] = potNw[0]; + u[1] = potNw[1]; + u[2] = potNw[2]; + + T.mv(u, Tu); + + fluxNw[2] = Tu[1]; + potentialDiffNw14 = -Tu[1]; + } + + //store potentials for further calculations (saturation, ...) -> maybe add new potential to old one!! + cellData1.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(0, 0), potentialDiffW12); + cellData1.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(0, 0), potentialDiffNw12); + cellData1.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(0, 1), potentialDiffW14); + cellData1.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(0, 1), potentialDiffNw14); + cellData2.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(1, 0), potentialDiffW24); + cellData2.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(1, 0), potentialDiffNw24); + cellData2.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(1, 1), -potentialDiffW12); + cellData2.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(1, 1), -potentialDiffNw12); + cellData4.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(3, 0), -potentialDiffW14); + cellData4.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(3, 0), -potentialDiffNw14); + cellData4.fluxData().addUpwindPotential(wPhaseIdx, interactionVolume.getIndexOnElement(3, 1), -potentialDiffW24); + cellData4.fluxData().addUpwindPotential(nPhaseIdx, interactionVolume.getIndexOnElement(3, 1), -potentialDiffNw24); + + //compute mobilities of face 1 + Dune::FieldVector<Scalar, numPhases> lambda12Upw(0.0); + lambda12Upw[wPhaseIdx] = (potentialDiffW12 >= 0) ? lambda1[wPhaseIdx] : lambda2[wPhaseIdx]; + lambda12Upw[nPhaseIdx] = (potentialDiffNw12 >= 0) ? lambda1[nPhaseIdx] : lambda2[nPhaseIdx]; + + //compute mobilities of face 4 + Dune::FieldVector<Scalar, numPhases> lambda14Upw(0.0); + lambda14Upw[wPhaseIdx] = (potentialDiffW14 >= 0) ? lambda1[wPhaseIdx] : lambda4[wPhaseIdx]; + lambda14Upw[nPhaseIdx] = (potentialDiffNw14 >= 0) ? lambda1[nPhaseIdx] : lambda4[nPhaseIdx]; + + //compute mobilities of face 2 + Dune::FieldVector<Scalar, numPhases> lambda24Upw(0.0); + lambda24Upw[wPhaseIdx] = (potentialDiffW24 >= 0) ? lambda2[wPhaseIdx] : lambda4[wPhaseIdx]; + lambda24Upw[nPhaseIdx] = (potentialDiffNw24 >= 0) ? lambda2[nPhaseIdx] : lambda4[nPhaseIdx]; + + for (int i = 0; i < numPhases; i++) + { + // evaluate parts of velocity --> always take the normal for which the flux is calculated! + DimVector vel12 = interactionVolume.getNormal(0, 0); + DimVector vel14 = interactionVolume.getNormal(3, 0); + DimVector vel24 = interactionVolume.getNormal(1, 0); + DimVector vel21 = interactionVolume.getNormal(0, 0); + DimVector vel41 = interactionVolume.getNormal(3, 0); + DimVector vel42 = interactionVolume.getNormal(1, 0); + + Dune::FieldVector<Scalar, 3> flux(0); + switch (i) + { + case wPhaseIdx: + { + flux = fluxW; + break; + } + case nPhaseIdx: + { + flux = fluxNw; + break; + } + } + + vel12 *= flux[0] / (2 * interactionVolume.getFaceArea(0, 0)); //divide by 2 because the flux is related to the half face! + vel14 *= flux[2] / (2 * interactionVolume.getFaceArea(3, 0)); + vel24 *= flux[1] / (2 * interactionVolume.getFaceArea(1, 0)); + vel21 *= flux[0] / (2 * interactionVolume.getFaceArea(0, 0)); + vel41 *= flux[2] / (4 * interactionVolume.getFaceArea(3, 0)); + vel42 *= flux[1] / (4 * interactionVolume.getFaceArea(1, 0)); + + Scalar lambdaT12 = lambda12Upw[wPhaseIdx] + lambda12Upw[nPhaseIdx]; + Scalar lambdaT14 = lambda14Upw[wPhaseIdx] + lambda14Upw[nPhaseIdx]; + Scalar lambdaT24 = lambda24Upw[wPhaseIdx] + lambda24Upw[nPhaseIdx]; + Scalar fracFlow12 = (lambdaT12 > this->threshold_) ? lambda12Upw[i] / (lambdaT12) : 0.0; + Scalar fracFlow14 = (lambdaT14 > this->threshold_) ? lambda14Upw[i] / (lambdaT14) : 0.0; + Scalar fracFlow24 = (lambdaT24 > this->threshold_) ? lambda24Upw[i] / (lambdaT24) : 0.0; + + vel12 *= fracFlow12; + vel14 *= fracFlow14; + vel24 *= fracFlow24; + vel21 *= fracFlow12; + vel41 *= fracFlow14; + vel42 *= fracFlow24; + + if (innerBoundaryVolumeFaces[globalIdx1][interactionVolume.getIndexOnElement(0, 0)]) + { + vel12 *= 2; + vel21 *= 2; + } + if (innerBoundaryVolumeFaces[globalIdx1][interactionVolume.getIndexOnElement(0, 1)]) + { + vel14 *= 2; + vel41 *= 2; + } + if (innerBoundaryVolumeFaces[globalIdx2][interactionVolume.getIndexOnElement(1, 0)]) + { + vel24 *= 2; + vel42 *= 2; + } + + //store velocities + //set velocity + cellData1.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(0, 0), vel12); + cellData1.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(0, 1), vel14); + cellData2.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(1, 0), vel24); + cellData2.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(1, 1), vel21); + cellData4.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(3, 0), vel41); + cellData4.fluxData().addVelocity(i, interactionVolume.getIndexOnElement(3, 1), vel42); + } + //set velocity marker + cellData1.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(0, 0)); + cellData1.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(0, 1)); + cellData2.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(1, 0)); + cellData2.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(1, 1)); + cellData4.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(3, 0)); + cellData4.fluxData().setVelocityMarker(interactionVolume.getIndexOnElement(3, 1)); +} + +} +// end of Dune namespace +#endif diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dinteractionvolumecontaineradaptive.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dinteractionvolumecontaineradaptive.hh index 2be63d5d34b685163c74363d773334f0843027f2..3ae9911121a40c9f857a946ce1004225082ec0e3 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dinteractionvolumecontaineradaptive.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dinteractionvolumecontaineradaptive.hh @@ -76,7 +76,7 @@ class FvMpfaL3dInteractionVolumeContainerAdaptive: public FvMpfaL3dInteractionVo enum { - pressEqIdx = Indices::pressEqIdx, + pressEqIdx = Indices::pressureEqIdx, }; typedef IndexTranslatorAdaptive IndexTranslator; diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressure2padaptive.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressure2padaptive.hh index f173e080a7bb2175d057815e4c9114df684c517d..73917e647f809e26c27a6715da46ea1d602822d3 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressure2padaptive.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressure2padaptive.hh @@ -103,7 +103,7 @@ class FvMpfaL3dPressure2pAdaptive: public FvMpfaL3dPressure2p<TypeTag> nPhaseIdx = Indices::nPhaseIdx, pressureIdx = Indices::pressureIdx, saturationIdx = Indices::saturationIdx, - pressEqIdx = Indices::pressEqIdx, + pressEqIdx = Indices::pressureEqIdx, satEqIdx = Indices::satEqIdx, numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressureproperties2p.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressureproperties2p.hh index 4c6a7b49885a89c888569fda6bdb215c34e251f9..576ff9fcbf041859f445591e8972847a71fa2fac 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressureproperties2p.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressureproperties2p.hh @@ -39,6 +39,7 @@ NEW_TYPE_TAG(FvMpfaL3dPressureTwoP, INHERITS_FROM(PressureTwoP, MPFAProperties)) } #include <dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressurevelocity2p.hh> +#include <dumux/decoupled/common/fv/mpfa/fvmpfavelocityintransport.hh> namespace Dumux { @@ -47,6 +48,7 @@ namespace Properties SET_TYPE_PROP(FvMpfaL3dPressureTwoP, MPFAInteractionVolume, Dumux::FvMpfaL3dInteractionVolume<TypeTag>); SET_TYPE_PROP(FvMpfaL3dPressureTwoP, MPFAInteractionVolumeContainer, Dumux::FvMpfaL3dInteractionVolumeContainer<TypeTag>); SET_TYPE_PROP(FvMpfaL3dPressureTwoP, PressureModel, Dumux::FvMpfaL3dPressureVelocity2p<TypeTag>); +SET_TYPE_PROP( FvMpfaL3dPressureTwoP, Velocity, Dumux::FvMpfaVelocityInTransport<TypeTag> ); } }// end of Dune namespace #endif diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressureproperties2padaptive.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressureproperties2padaptive.hh index b376cacd3beb9d30c325f17ae454c24fbfbef8f7..967cf7295b5960ff05193dbd755ebba1beeeeb1a 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressureproperties2padaptive.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressureproperties2padaptive.hh @@ -40,6 +40,7 @@ NEW_TYPE_TAG(FvMpfaL3dPressureTwoPAdaptive, INHERITS_FROM(PressureTwoP, MPFAProp } #include <dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressurevelocity2padaptive.hh> +#include <dumux/decoupled/common/fv/mpfa/fvmpfavelocityintransport.hh> namespace Dumux { @@ -48,6 +49,7 @@ namespace Properties SET_TYPE_PROP(FvMpfaL3dPressureTwoPAdaptive, MPFAInteractionVolume, Dumux::FvMpfaL3dInteractionVolumeAdaptive<TypeTag>); SET_TYPE_PROP(FvMpfaL3dPressureTwoPAdaptive, MPFAInteractionVolumeContainer, Dumux::FvMpfaL3dInteractionVolumeContainerAdaptive<TypeTag>); SET_TYPE_PROP(FvMpfaL3dPressureTwoPAdaptive, PressureModel, Dumux::FvMpfaL3dPressureVelocity2pAdaptive<TypeTag>); +SET_TYPE_PROP( FvMpfaL3dPressureTwoPAdaptive, Velocity, Dumux::FvMpfaVelocityInTransport<TypeTag> ); } }// end of Dune namespace #endif diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressurevelocity2p.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressurevelocity2p.hh index fcf548d45d05188626a3f922cdf0af33dc78a3f5..fb71e1f8b30575bbfafe349d4c41726152188af3 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressurevelocity2p.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressurevelocity2p.hh @@ -34,46 +34,106 @@ template<class TypeTag> class FvMpfaL3dPressureVelocity2p: public FvMpfaL3dPress typedef FvMpfaL3dPressure2p<TypeTag> ParentType; typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; enum { dim = GridView::dimension, dimWorld = GridView::dimensionworld }; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + enum + { + pw = Indices::pressureW, + pn = Indices::pressureNw, + sw = Indices::saturationW, + sn = Indices::saturationNw, + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + pressureIdx = Indices::pressureIdx, + saturationIdx = Indices::saturationIdx, + pressEqIdx = Indices::pressureEqIdx, + satEqIdx = Indices::satEqIdx, + numPhases = GET_PROP_VALUE(TypeTag, NumPhases) + }; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; typedef typename GET_PROP_TYPE(TypeTag, CellData) CellData; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP(TypeTag, SolutionTypes) SolutionTypes; + typedef typename SolutionTypes::PrimaryVariables PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; + typedef typename SpatialParams::MaterialLaw MaterialLaw; +#if DUNE_VERSION_NEWER(DUNE_GRID, 2, 3) + typedef typename Dune::ReferenceElements<Scalar, dim> ReferenceElements; + typedef typename Dune::ReferenceElement<Scalar, dim> ReferenceElement; +#else + typedef typename Dune::GenericReferenceElements<Scalar, dim> ReferenceElements; + typedef typename Dune::GenericReferenceElement<Scalar, dim> ReferenceElement; +#endif + + typedef typename GridView::template Codim<0>::Iterator ElementIterator; typedef typename GridView::template Codim<dim>::Iterator VertexIterator; typedef typename GET_PROP_TYPE(TypeTag, MPFAInteractionVolume) InteractionVolume; + typedef typename GridView::IntersectionIterator IntersectionIterator; + typedef typename GridView::template Codim<0>::EntityPointer ElementPointer; + typedef typename GridView::Intersection Intersection; + + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; public: FvMpfaL3dPressureVelocity2p(Problem& problem) : ParentType(problem), problem_(problem), velocity_(problem) - {} + { + density_[wPhaseIdx] = 0.; + density_[nPhaseIdx] = 0.; + viscosity_[wPhaseIdx] = 0.; + viscosity_[nPhaseIdx] = 0.; + + calcVelocityInTransport_ = GET_PARAM_FROM_GROUP(TypeTag, bool, MPFA, CalcVelocityInTransport); + } void calculateVelocity(); public: + // Calculates the velocity at a cell-cell interface. + void calculateVelocity(const Intersection&, CellData&); + void calculateVelocityOnBoundary(const Intersection& intersection, CellData& cellData); + void updateVelocity() { this->updateMaterialLaws(); - //reset velocities - int size = problem_.gridView().size(0); - for (int i = 0; i < size; i++) - { - CellData& cellData = problem_.variables().cellData(i); - cellData.fluxData().resetVelocity(); - } + this->storePressureSolution(); + if (!calculateVelocityInTransport()) calculateVelocity(); } void initialize(bool solveTwice = true) { + ElementIterator element = problem_.gridView().template begin<0>(); + FluidState fluidState; + fluidState.setPressure(wPhaseIdx, problem_.referencePressure(*element)); + fluidState.setPressure(nPhaseIdx, problem_.referencePressure(*element)); + fluidState.setTemperature(problem_.temperature(*element)); + fluidState.setSaturation(wPhaseIdx, 1.); + fluidState.setSaturation(nPhaseIdx, 0.); + density_[wPhaseIdx] = FluidSystem::density(fluidState, wPhaseIdx); + density_[nPhaseIdx] = FluidSystem::density(fluidState, nPhaseIdx); + viscosity_[wPhaseIdx] = FluidSystem::viscosity(fluidState, wPhaseIdx); + viscosity_[nPhaseIdx] = FluidSystem::viscosity(fluidState, nPhaseIdx); + ParentType::initialize(); velocity_.initialize(); + + if (!calculateVelocityInTransport()) calculateVelocity(); return; @@ -82,9 +142,20 @@ public: void update() { ParentType::update(); + + if (!calculateVelocityInTransport()) calculateVelocity(); } + /*! \brief Indicates if velocity is reconstructed in the pressure step or in the transport step + * + * Returns true (In the standard finite volume discretization the velocity is calculated during the saturation transport.) + */ + bool calculateVelocityInTransport() + { + return calcVelocityInTransport_; + } + //! \brief Write data files /* \param name file name */ template<class MultiWriter> @@ -97,6 +168,13 @@ public: private: Problem& problem_; FvMpfaL3dVelocity2p<TypeTag> velocity_; + + Scalar density_[numPhases]; + Scalar viscosity_[numPhases]; + bool calcVelocityInTransport_; + + static const int pressureType_ = GET_PROP_VALUE(TypeTag, PressureFormulation); //!< gives kind of pressure used (\f$ 0 = p_w\f$, \f$ 1 = p_n\f$, \f$ 2 = p_{global}\f$) + static const int saturationType_ = GET_PROP_VALUE(TypeTag, SaturationFormulation); //!< gives kind of saturation used (\f$ 0 = S_w\f$, \f$ 1 = S_n\f$) }; // end of template @@ -115,12 +193,61 @@ void FvMpfaL3dPressureVelocity2p<TypeTag>::calculateVelocity() // inner interactionvolume if (interactionVolume.isInnerVolume()) { - velocity_.calculateInnerInteractionVolumeVelocity(interactionVolume, this->interactionVolumes_, this->transmissibilityCalculator_); + // cell index + int globalIdx[8]; + for (int i = 0; i < 8; i++) + { + globalIdx[i] = problem_.variables().index(*(interactionVolume.getSubVolumeElement(i))); + } + + //get the cell Data + CellData & cellData1 = problem_.variables().cellData(globalIdx[0]); + CellData & cellData2 = problem_.variables().cellData(globalIdx[1]); + CellData & cellData3 = problem_.variables().cellData(globalIdx[2]); + CellData & cellData4 = problem_.variables().cellData(globalIdx[3]); + CellData & cellData5 = problem_.variables().cellData(globalIdx[4]); + CellData & cellData6 = problem_.variables().cellData(globalIdx[5]); + CellData & cellData7 = problem_.variables().cellData(globalIdx[6]); + CellData & cellData8 = problem_.variables().cellData(globalIdx[7]); + + velocity_.calculateInnerInteractionVolumeVelocity(interactionVolume, + cellData1, cellData2, cellData3, cellData4, + cellData5, cellData6, cellData7, cellData8, + this->interactionVolumes_, this->transmissibilityCalculator_); } // at least one face on boundary! (boundary interactionvolume) else { - velocity_.calculateBoundaryInteractionVolumeVelocity(interactionVolume, this->interactionVolumes_, this->transmissibilityCalculator_); + for (int elemIdx = 0; elemIdx < 8; elemIdx++) + { + if (!interactionVolume.hasSubVolumeElement(elemIdx)) + { + continue; + } + bool isOutside = false; + for (int faceIdx = 0; faceIdx < dim; faceIdx++) + { + int intVolFaceIdx = interactionVolume.getFaceIndexFromSubVolume(elemIdx, faceIdx); + if (interactionVolume.isOutsideFace(intVolFaceIdx)) + { + isOutside = true; + break; + } + } + if (isOutside) + { + continue; + } + + ElementPointer & elementPointer = interactionVolume.getSubVolumeElement(elemIdx); + + // cell index + int globalIdx = problem_.variables().index(*elementPointer); + //get the cell Data + CellData& cellData = problem_.variables().cellData(globalIdx); + + velocity_.calculateBoundaryInteractionVolumeVelocity(interactionVolume, cellData, elemIdx); + } } // end boundaries } // end vertex iterator @@ -128,6 +255,257 @@ void FvMpfaL3dPressureVelocity2p<TypeTag>::calculateVelocity() return; } +template<class TypeTag> +void FvMpfaL3dPressureVelocity2p<TypeTag>::calculateVelocity(const Intersection& intersection, CellData& cellData) +{ + int numVertices = intersection.geometry().corners(); + + ElementPointer elementPtrI = intersection.inside(); + ElementPointer elementPtrJ = intersection.outside(); + + int globalIdxI = problem_.variables().index(*elementPtrI); + int globalIdxJ = problem_.variables().index(*elementPtrJ); + + CellData& cellDataJ = problem_.variables().cellData(globalIdxJ); + + const ReferenceElement& referenceElement = ReferenceElements::general(elementPtrI->geometry().type()); + + int indexInInside = intersection.indexInInside(); + int indexInOutside = intersection.indexInOutside(); + + Dune::FieldVector<CellData, 8> cellDataTemp; + + for (int vIdx = 0; vIdx < numVertices; vIdx++) + { + int localVertIdx = referenceElement.subEntity(indexInInside, 1, vIdx, dim); + + int globalVertIdx = problem_.variables().index( + *((*elementPtrI).template subEntity < dim > (localVertIdx))); + + InteractionVolume& interactionVolume = this->interactionVolumes_.interactionVolume(globalVertIdx); + + if (interactionVolume.isInnerVolume()) + { + // cell index + int globalIdx[8]; + for (int i = 0; i < 8; i++) + { + globalIdx[i] = problem_.variables().index(*(interactionVolume.getSubVolumeElement(i))); + cellDataTemp[i] = problem_.variables().cellData(globalIdx[i]); + } + + velocity_.calculateInnerInteractionVolumeVelocity(interactionVolume, + cellDataTemp[0], cellDataTemp[1], cellDataTemp[2], cellDataTemp[3], + cellDataTemp[4], cellDataTemp[5], cellDataTemp[6], cellDataTemp[7], + this->interactionVolumes_, this->transmissibilityCalculator_); + + for (int i = 0; i < 8; i++) + { + if (globalIdx[i] == globalIdxI) + { + cellData.fluxData().setVelocity(wPhaseIdx, indexInInside, cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInInside)); + cellData.fluxData().setVelocity(nPhaseIdx, indexInInside, cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInInside)); + cellData.fluxData().setUpwindPotential(wPhaseIdx, indexInInside, cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInInside)); + cellData.fluxData().setUpwindPotential(nPhaseIdx, indexInInside, cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInInside)); + } + else if (globalIdx[i] == globalIdxJ) + { + cellDataJ.fluxData().setVelocity(wPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInOutside)); + cellDataJ.fluxData().setVelocity(nPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInOutside)); + cellDataJ.fluxData().setUpwindPotential(wPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInOutside)); + cellDataJ.fluxData().setUpwindPotential(nPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInOutside)); + } + } + } + } + cellData.fluxData().setVelocityMarker(indexInInside); + cellDataJ.fluxData().setVelocityMarker(indexInOutside); +} + +template<class TypeTag> +void FvMpfaL3dPressureVelocity2p<TypeTag>::calculateVelocityOnBoundary(const Intersection& intersection, CellData& cellData) +{ + ElementPointer element = intersection.inside(); + + //get face index + int isIndex = intersection.indexInInside(); + + //get face normal + const Dune::FieldVector<Scalar, dim>& unitOuterNormal = intersection.centerUnitOuterNormal(); + + BoundaryTypes bcType; + //get boundary type + problem_.boundaryTypes(bcType, intersection); + PrimaryVariables boundValues(0.0); + + if (bcType.isDirichlet(pressEqIdx)) + { + problem_.dirichlet(boundValues, intersection); + + // get global coordinates of cell centers + const GlobalPosition& globalPosI = element->geometry().center(); + + // center of face in global coordinates + const GlobalPosition& globalPosJ = intersection.geometry().center(); + + // get mobilities and fractional flow factors + Scalar lambdaWI = cellData.mobility(wPhaseIdx); + Scalar lambdaNwI = cellData.mobility(nPhaseIdx); + + // get capillary pressure + Scalar pcI = cellData.capillaryPressure(); + + // distance vector between barycenters + GlobalPosition distVec = globalPosJ - globalPosI; + + // compute distance between cell centers + Scalar dist = distVec.two_norm(); + + //permeability vector at boundary + // compute vectorized permeabilities + DimMatrix meanPermeability(0); + + problem_.spatialParams().meanK(meanPermeability, problem_.spatialParams().intrinsicPermeability(*element)); + + Dune::FieldVector<Scalar, dim> permeability(0); + meanPermeability.mv(unitOuterNormal, permeability); + + //determine saturation at the boundary -> if no saturation is known directly at the boundary use the cell saturation + Scalar satW = 0; + Scalar satNw = 0; + if (bcType.isDirichlet(satEqIdx)) + { + switch (saturationType_) + { + case sw: + { + satW = boundValues[saturationIdx]; + satNw = 1 - boundValues[saturationIdx]; + break; + } + case sn: + { + satW = 1 - boundValues[saturationIdx]; + satNw = boundValues[saturationIdx]; + break; + } + } + } + else + { + satW = cellData.saturation(wPhaseIdx); + satNw = cellData.saturation(nPhaseIdx); + } + + Scalar pressBound = boundValues[pressureIdx]; + Scalar pcBound = MaterialLaw::pc(problem_.spatialParams().materialLawParams(*element), satW); + + //determine phase pressures from primary pressure variable + Scalar pressWBound = 0; + Scalar pressNwBound = 0; + if (pressureType_ == pw) + { + pressWBound = pressBound; + pressNwBound = pressBound + pcBound; + } + else if (pressureType_ == pn) + { + pressWBound = pressBound - pcBound; + pressNwBound = pressBound; + } + + Scalar lambdaWBound = MaterialLaw::krw(problem_.spatialParams().materialLawParams(*element), satW) + / viscosity_[wPhaseIdx]; + Scalar lambdaNwBound = MaterialLaw::krn(problem_.spatialParams().materialLawParams(*element), satW) + / viscosity_[nPhaseIdx]; + + Scalar potentialDiffW = cellData.fluxData().upwindPotential(wPhaseIdx, isIndex); + Scalar potentialDiffNw = cellData.fluxData().upwindPotential(nPhaseIdx, isIndex); + + //calculate potential gradient + potentialDiffW = (cellData.pressure(wPhaseIdx) - pressWBound); + potentialDiffNw = (cellData.pressure(nPhaseIdx) - pressNwBound); + + potentialDiffW += density_[wPhaseIdx] * (distVec * problem_.gravity()); + potentialDiffNw += density_[nPhaseIdx] * (distVec * problem_.gravity()); + + //store potential gradients for further calculations + cellData.fluxData().setUpwindPotential(wPhaseIdx, isIndex, potentialDiffW); + cellData.fluxData().setUpwindPotential(nPhaseIdx, isIndex, potentialDiffNw); + + //do the upwinding of the mobility depending on the phase potentials + Scalar lambdaW = (potentialDiffW > 0.) ? lambdaWI : lambdaWBound; + lambdaW = (potentialDiffW == 0) ? 0.5 * (lambdaWI + lambdaWBound) : lambdaW; + Scalar lambdaNw = (potentialDiffNw > 0.) ? lambdaNwI : lambdaNwBound; + lambdaNw = (potentialDiffNw == 0) ? 0.5 * (lambdaNwI + lambdaNwBound) : lambdaNw; + + + Scalar scalarPerm = permeability.two_norm(); + + //calculate the gravity term + Dune::FieldVector<Scalar, dimWorld> velocityW(unitOuterNormal); + Dune::FieldVector<Scalar, dimWorld> velocityNw(unitOuterNormal); + + //calculate unit distVec + distVec /= dist; + Scalar areaScaling = (unitOuterNormal * distVec); + //this treatment of g allows to account for gravity flux through faces where the face normal has no z component (e.g. parallelepiped grids) + Scalar gravityTermW = (problem_.gravity() * distVec) * density_[wPhaseIdx] * areaScaling; + Scalar gravityTermNw = (problem_.gravity() * distVec) * density_[nPhaseIdx] * areaScaling; + + //calculate velocity depending on the pressure used -> use pc = pn - pw + switch (pressureType_) + { + case pw: + { + velocityW *= lambdaW * scalarPerm * ((cellData.pressure(wPhaseIdx) - pressBound) / dist + gravityTermW); + velocityNw *= lambdaNw * scalarPerm * ((cellData.pressure(wPhaseIdx) - pressBound) / dist + gravityTermNw) + + 0.5 * (lambdaNwI + lambdaNwBound) * scalarPerm * (pcI - pcBound) / dist; + break; + } + case pn: + { + velocityW *= lambdaW * scalarPerm * ((cellData.pressure(nPhaseIdx) - pressBound) / dist + gravityTermW) + - 0.5 * (lambdaWI + lambdaWBound) * scalarPerm * (pcI - pcBound) / dist; + velocityNw *= lambdaNw * scalarPerm * ((cellData.pressure(nPhaseIdx) - pressBound) / dist + gravityTermNw); + break; + } + } + + //store velocities + cellData.fluxData().setVelocity(wPhaseIdx, isIndex, velocityW); + cellData.fluxData().setVelocity(nPhaseIdx, isIndex, velocityNw); + cellData.fluxData().setVelocityMarker(isIndex); + + } //end dirichlet boundary + + else if (bcType.isNeumann(pressEqIdx)) + { + problem_.neumann(boundValues, intersection); + + Dune::FieldVector<Scalar, dimWorld> velocityW(unitOuterNormal); + Dune::FieldVector<Scalar, dimWorld> velocityNw(unitOuterNormal); + + velocityW *= boundValues[wPhaseIdx]; + velocityNw *= boundValues[nPhaseIdx]; + + velocityW /= density_[wPhaseIdx]; + velocityNw /= density_[nPhaseIdx]; + + //store potential gradients for further calculations + cellData.fluxData().setUpwindPotential(wPhaseIdx, isIndex, boundValues[wPhaseIdx]); + cellData.fluxData().setUpwindPotential(nPhaseIdx, isIndex, boundValues[nPhaseIdx]); + + cellData.fluxData().setVelocity(wPhaseIdx, isIndex, velocityW); + cellData.fluxData().setVelocity(nPhaseIdx, isIndex, velocityNw); + cellData.fluxData().setVelocityMarker(isIndex); + } //end neumann boundary + else + { + DUNE_THROW(Dune::NotImplemented, "No valid boundary condition type defined for pressure equation!"); + } +} + } // end of Dune namespace #endif diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressurevelocity2padaptive.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressurevelocity2padaptive.hh index 31a8f8a6fca6ca4cf94346920fd1dc538bcfb04c..04a11ce5fbf957967118b8b1db61496ae2ca3d99 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressurevelocity2padaptive.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dpressurevelocity2padaptive.hh @@ -31,6 +31,7 @@ namespace Dumux template<class TypeTag> class FvMpfaL3dPressureVelocity2pAdaptive: public FvMpfaL3dPressure2pAdaptive<TypeTag> { typedef FvMpfaL3dPressure2pAdaptive<TypeTag> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; @@ -39,40 +40,101 @@ template<class TypeTag> class FvMpfaL3dPressureVelocity2pAdaptive: public FvMpfa dim = GridView::dimension, dimWorld = GridView::dimensionworld }; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + enum + { + pw = Indices::pressureW, + pn = Indices::pressureNw, + sw = Indices::saturationW, + sn = Indices::saturationNw, + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + pressureIdx = Indices::pressureIdx, + saturationIdx = Indices::saturationIdx, + pressEqIdx = Indices::pressureEqIdx, + satEqIdx = Indices::satEqIdx, + numPhases = GET_PROP_VALUE(TypeTag, NumPhases) + }; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; typedef typename GET_PROP_TYPE(TypeTag, CellData) CellData; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP(TypeTag, SolutionTypes) SolutionTypes; + typedef typename SolutionTypes::PrimaryVariables PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; + typedef typename SpatialParams::MaterialLaw MaterialLaw; +#if DUNE_VERSION_NEWER(DUNE_GRID, 2, 3) + typedef typename Dune::ReferenceElements<Scalar, dim> ReferenceElements; + typedef typename Dune::ReferenceElement<Scalar, dim> ReferenceElement; +#else + typedef typename Dune::GenericReferenceElements<Scalar, dim> ReferenceElements; + typedef typename Dune::GenericReferenceElement<Scalar, dim> ReferenceElement; +#endif + + typedef typename GridView::template Codim<0>::Iterator ElementIterator; typedef typename GridView::template Codim<dim>::Iterator VertexIterator; typedef typename GET_PROP_TYPE(TypeTag, MPFAInteractionVolume) InteractionVolume; + typedef typename GridView::IntersectionIterator IntersectionIterator; + typedef typename GridView::template Codim<0>::EntityPointer ElementPointer; + typedef typename GridView::Intersection Intersection; + + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; + typedef Dune::FieldVector<Scalar, dim> DimVector; public: FvMpfaL3dPressureVelocity2pAdaptive(Problem& problem) : ParentType(problem), problem_(problem), velocity_(problem) - {} + { + density_[wPhaseIdx] = 0.; + density_[nPhaseIdx] = 0.; + viscosity_[wPhaseIdx] = 0.; + viscosity_[nPhaseIdx] = 0.; + + calcVelocityInTransport_ = GET_PARAM_FROM_GROUP(TypeTag, bool, MPFA, CalcVelocityInTransport); + } void calculateVelocity(); public: + // Calculates the velocity at a cell-cell interface. + void calculateVelocity(const Intersection&, CellData&); + void calculateVelocityOnBoundary(const Intersection& intersection, CellData& cellData); + + void updateVelocity() { this->updateMaterialLaws(); - //reset velocities - int size = problem_.gridView().size(0); - for (int i = 0; i < size; i++) - { - CellData& cellData = problem_.variables().cellData(i); - cellData.fluxData().resetVelocity(); - } + this->storePressureSolution(); + if (!calculateVelocityInTransport()) calculateVelocity(); } void initialize(bool solveTwice = true) { + ElementIterator element = problem_.gridView().template begin<0>(); + FluidState fluidState; + fluidState.setPressure(wPhaseIdx, problem_.referencePressure(*element)); + fluidState.setPressure(nPhaseIdx, problem_.referencePressure(*element)); + fluidState.setTemperature(problem_.temperature(*element)); + fluidState.setSaturation(wPhaseIdx, 1.); + fluidState.setSaturation(nPhaseIdx, 0.); + density_[wPhaseIdx] = FluidSystem::density(fluidState, wPhaseIdx); + density_[nPhaseIdx] = FluidSystem::density(fluidState, nPhaseIdx); + viscosity_[wPhaseIdx] = FluidSystem::viscosity(fluidState, wPhaseIdx); + viscosity_[nPhaseIdx] = FluidSystem::viscosity(fluidState, nPhaseIdx); + ParentType::initialize(); velocity_.initialize(); + + if (!calculateVelocityInTransport()) calculateVelocity(); return; @@ -81,9 +143,20 @@ public: void update() { ParentType::update(); + + if (!calculateVelocityInTransport()) calculateVelocity(); } + /*! \brief Indicates if velocity is reconstructed in the pressure step or in the transport step + * + * Returns true (In the standard finite volume discretization the velocity is calculated during the saturation transport.) + */ + bool calculateVelocityInTransport() + { + return calcVelocityInTransport_; + } + //! \brief Write data files /* \param name file name */ template<class MultiWriter> @@ -96,6 +169,13 @@ public: private: Problem& problem_; FvMpfaL3dVelocity2pAdaptive<TypeTag> velocity_; + + Scalar density_[numPhases]; + Scalar viscosity_[numPhases]; + bool calcVelocityInTransport_; + + static const int pressureType_ = GET_PROP_VALUE(TypeTag, PressureFormulation); //!< gives kind of pressure used (\f$ 0 = p_w\f$, \f$ 1 = p_n\f$, \f$ 2 = p_{global}\f$) + static const int saturationType_ = GET_PROP_VALUE(TypeTag, SaturationFormulation); //!< gives kind of saturation used (\f$ 0 = S_w\f$, \f$ 1 = S_n\f$) }; // end of template @@ -114,19 +194,70 @@ void FvMpfaL3dPressureVelocity2pAdaptive<TypeTag>::calculateVelocity() // inner interactionvolume if (interactionVolume.isInnerVolume()) { + // cell index + int globalIdx[8]; + for (int i = 0; i < 8; i++) + { + globalIdx[i] = problem_.variables().index(*(interactionVolume.getSubVolumeElement(i))); + } + + //get the cell Data + CellData & cellData1 = problem_.variables().cellData(globalIdx[0]); + CellData & cellData2 = problem_.variables().cellData(globalIdx[1]); + CellData & cellData3 = problem_.variables().cellData(globalIdx[2]); + CellData & cellData4 = problem_.variables().cellData(globalIdx[3]); + CellData & cellData5 = problem_.variables().cellData(globalIdx[4]); + CellData & cellData6 = problem_.variables().cellData(globalIdx[5]); + CellData & cellData7 = problem_.variables().cellData(globalIdx[6]); + CellData & cellData8 = problem_.variables().cellData(globalIdx[7]); + if (!interactionVolume.isHangingNodeVolume()) { - velocity_.calculateInnerInteractionVolumeVelocity(interactionVolume, this->interactionVolumes_, this->transmissibilityCalculator_); + velocity_.calculateInnerInteractionVolumeVelocity(interactionVolume, + cellData1, cellData2, cellData3, cellData4, + cellData5, cellData6, cellData7, cellData8, + this->interactionVolumes_, this->transmissibilityCalculator_); } else { - velocity_.calculateHangingNodeInteractionVolumeVelocity(interactionVolume); + velocity_.calculateHangingNodeInteractionVolumeVelocity(interactionVolume, + cellData1, cellData2, cellData3, cellData4, + cellData5, cellData6, cellData7, cellData8); } } // at least one face on boundary! (boundary interactionvolume) else { - velocity_.calculateBoundaryInteractionVolumeVelocity(interactionVolume, this->interactionVolumes_, this->transmissibilityCalculator_); + for (int elemIdx = 0; elemIdx < 8; elemIdx++) + { + if (!interactionVolume.hasSubVolumeElement(elemIdx)) + { + continue; + } + bool isOutside = false; + for (int faceIdx = 0; faceIdx < dim; faceIdx++) + { + int intVolFaceIdx = interactionVolume.getFaceIndexFromSubVolume(elemIdx, faceIdx); + if (interactionVolume.isOutsideFace(intVolFaceIdx)) + { + isOutside = true; + break; + } + } + if (isOutside) + { + continue; + } + + ElementPointer & elementPointer = interactionVolume.getSubVolumeElement(elemIdx); + + // cell index + int globalIdx = problem_.variables().index(*elementPointer); + //get the cell Data + CellData& cellData = problem_.variables().cellData(globalIdx); + + velocity_.calculateBoundaryInteractionVolumeVelocity(interactionVolume, cellData, elemIdx); + } } // end boundaries } // end vertex iterator @@ -134,6 +265,325 @@ void FvMpfaL3dPressureVelocity2pAdaptive<TypeTag>::calculateVelocity() return; } +template<class TypeTag> +void FvMpfaL3dPressureVelocity2pAdaptive<TypeTag>::calculateVelocity(const Intersection& intersection, CellData& cellData) +{ + int numVertices = intersection.geometry().corners(); + + ElementPointer elementPtrI = intersection.inside(); + ElementPointer elementPtrJ = intersection.outside(); + + int levelI = elementPtrI->level(); + int levelJ = elementPtrJ->level(); + + int globalIdxI = problem_.variables().index(*elementPtrI); + int globalIdxJ = problem_.variables().index(*elementPtrJ); + + CellData& cellDataJ = problem_.variables().cellData(globalIdxJ); + + const ReferenceElement& referenceElement = ReferenceElements::general(elementPtrI->geometry().type()); + + int indexInInside = intersection.indexInInside(); + int indexInOutside = intersection.indexInOutside(); + + int faceIdx = indexInInside; + + if (levelI < levelJ) + faceIdx = indexInOutside; + + Dune::FieldVector<CellData, 8> cellDataTemp; + + if (levelI != levelJ) + { + DimVector vel(0); + cellData.fluxData().setVelocity(wPhaseIdx, indexInInside, vel); + cellData.fluxData().setVelocity(nPhaseIdx, indexInInside, vel); + cellData.fluxData().setUpwindPotential(wPhaseIdx, indexInInside, 0); + cellData.fluxData().setUpwindPotential(nPhaseIdx, indexInInside, 0); + + cellDataJ.fluxData().setVelocity(wPhaseIdx, indexInOutside, vel); + cellDataJ.fluxData().setVelocity(nPhaseIdx, indexInOutside, vel); + cellDataJ.fluxData().setUpwindPotential(wPhaseIdx, indexInOutside, 0); + cellDataJ.fluxData().setUpwindPotential(nPhaseIdx, indexInOutside, 0); + } + + for (int vIdx = 0; vIdx < numVertices; vIdx++) + { + int localVertIdx = referenceElement.subEntity(faceIdx, 1, vIdx, dim); + + int globalVertIdx = 0; + if (levelI >= levelJ) + { + globalVertIdx = problem_.variables().index( + *((*elementPtrI).template subEntity < dim > (localVertIdx))); + } + else + { + globalVertIdx = problem_.variables().index( + *((*elementPtrJ).template subEntity < dim > (localVertIdx))); + } + + InteractionVolume& interactionVolume = this->interactionVolumes_.interactionVolume(globalVertIdx); + + if (interactionVolume.isInnerVolume()) + { + // cell index + int globalIdx[8]; + for (int i = 0; i < 8; i++) + { + globalIdx[i] = problem_.variables().index(*(interactionVolume.getSubVolumeElement(i))); + cellDataTemp[i] = problem_.variables().cellData(globalIdx[i]); + } + + if (!interactionVolume.isHangingNodeVolume()) + { + velocity_.calculateInnerInteractionVolumeVelocity(interactionVolume, + cellDataTemp[0], cellDataTemp[1], cellDataTemp[2], cellDataTemp[3], + cellDataTemp[4], cellDataTemp[5], cellDataTemp[6], cellDataTemp[7], + this->interactionVolumes_, this->transmissibilityCalculator_); + } + else + { + velocity_.calculateHangingNodeInteractionVolumeVelocity(interactionVolume, + cellDataTemp[0], cellDataTemp[1], cellDataTemp[2], cellDataTemp[3], + cellDataTemp[4], cellDataTemp[5], cellDataTemp[6], cellDataTemp[7]); + } + + + for (int i = 0; i < 8; i++) + { + if (globalIdx[i] == globalIdxI) + { + if (levelI >= levelJ) + { + cellData.fluxData().setVelocity(wPhaseIdx, indexInInside, cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInInside)); + cellData.fluxData().setVelocity(nPhaseIdx, indexInInside, cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInInside)); + cellData.fluxData().setUpwindPotential(wPhaseIdx, indexInInside, cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInInside)); + cellData.fluxData().setUpwindPotential(nPhaseIdx, indexInInside, cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInInside)); + + if (levelI > levelJ) + { + cellDataJ.fluxData().setVelocity(wPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInInside)); + cellDataJ.fluxData().setVelocity(nPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInInside)); + cellDataJ.fluxData().setUpwindPotential(wPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInInside)); + cellDataJ.fluxData().setUpwindPotential(nPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInInside)); + + } + } + } + else if (globalIdx[i] == globalIdxJ) + { + if (levelJ >= levelI) + { + cellDataJ.fluxData().setVelocity(wPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInOutside)); + cellDataJ.fluxData().setVelocity(nPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInOutside)); + cellDataJ.fluxData().setUpwindPotential(wPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInOutside)); + cellDataJ.fluxData().setUpwindPotential(nPhaseIdx, indexInOutside, cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInOutside)); + + if (levelJ > levelI) + { + cellData.fluxData().setVelocity(wPhaseIdx, indexInInside, cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInOutside)); + cellData.fluxData().setVelocity(nPhaseIdx, indexInInside, cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInOutside)); + cellData.fluxData().setUpwindPotential(wPhaseIdx, indexInInside, cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInOutside)); + cellData.fluxData().setUpwindPotential(nPhaseIdx, indexInInside, cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInOutside)); + + } + } + } + } + } + } + if (levelI == levelJ) + { + cellData.fluxData().setVelocityMarker(indexInInside); + cellDataJ.fluxData().setVelocityMarker(indexInOutside); + } +} + +template<class TypeTag> +void FvMpfaL3dPressureVelocity2pAdaptive<TypeTag>::calculateVelocityOnBoundary(const Intersection& intersection, CellData& cellData) +{ + ElementPointer element = intersection.inside(); + + //get face index + int isIndex = intersection.indexInInside(); + + //get face normal + const Dune::FieldVector<Scalar, dim>& unitOuterNormal = intersection.centerUnitOuterNormal(); + + BoundaryTypes bcType; + //get boundary type + problem_.boundaryTypes(bcType, intersection); + PrimaryVariables boundValues(0.0); + + if (bcType.isDirichlet(pressEqIdx)) + { + problem_.dirichlet(boundValues, intersection); + + // get global coordinates of cell centers + const GlobalPosition& globalPosI = element->geometry().center(); + + // center of face in global coordinates + const GlobalPosition& globalPosJ = intersection.geometry().center(); + + // get mobilities and fractional flow factors + Scalar lambdaWI = cellData.mobility(wPhaseIdx); + Scalar lambdaNwI = cellData.mobility(nPhaseIdx); + + // get capillary pressure + Scalar pcI = cellData.capillaryPressure(); + + // distance vector between barycenters + GlobalPosition distVec = globalPosJ - globalPosI; + + // compute distance between cell centers + Scalar dist = distVec.two_norm(); + + //permeability vector at boundary + // compute vectorized permeabilities + DimMatrix meanPermeability(0); + + problem_.spatialParams().meanK(meanPermeability, problem_.spatialParams().intrinsicPermeability(*element)); + + Dune::FieldVector<Scalar, dim> permeability(0); + meanPermeability.mv(unitOuterNormal, permeability); + + //determine saturation at the boundary -> if no saturation is known directly at the boundary use the cell saturation + Scalar satW = 0; + Scalar satNw = 0; + if (bcType.isDirichlet(satEqIdx)) + { + switch (saturationType_) + { + case sw: + { + satW = boundValues[saturationIdx]; + satNw = 1 - boundValues[saturationIdx]; + break; + } + case sn: + { + satW = 1 - boundValues[saturationIdx]; + satNw = boundValues[saturationIdx]; + break; + } + } + } + else + { + satW = cellData.saturation(wPhaseIdx); + satNw = cellData.saturation(nPhaseIdx); + } + + Scalar pressBound = boundValues[pressureIdx]; + Scalar pcBound = MaterialLaw::pc(problem_.spatialParams().materialLawParams(*element), satW); + + //determine phase pressures from primary pressure variable + Scalar pressWBound = 0; + Scalar pressNwBound = 0; + if (pressureType_ == pw) + { + pressWBound = pressBound; + pressNwBound = pressBound + pcBound; + } + else if (pressureType_ == pn) + { + pressWBound = pressBound - pcBound; + pressNwBound = pressBound; + } + + Scalar lambdaWBound = MaterialLaw::krw(problem_.spatialParams().materialLawParams(*element), satW) + / viscosity_[wPhaseIdx]; + Scalar lambdaNwBound = MaterialLaw::krn(problem_.spatialParams().materialLawParams(*element), satW) + / viscosity_[nPhaseIdx]; + + Scalar potentialDiffW = cellData.fluxData().upwindPotential(wPhaseIdx, isIndex); + Scalar potentialDiffNw = cellData.fluxData().upwindPotential(nPhaseIdx, isIndex); + + //calculate potential gradient + potentialDiffW = (cellData.pressure(wPhaseIdx) - pressWBound); + potentialDiffNw = (cellData.pressure(nPhaseIdx) - pressNwBound); + + potentialDiffW += density_[wPhaseIdx] * (distVec * problem_.gravity()); + potentialDiffNw += density_[nPhaseIdx] * (distVec * problem_.gravity()); + + //store potential gradients for further calculations + cellData.fluxData().setUpwindPotential(wPhaseIdx, isIndex, potentialDiffW); + cellData.fluxData().setUpwindPotential(nPhaseIdx, isIndex, potentialDiffNw); + + //do the upwinding of the mobility depending on the phase potentials + Scalar lambdaW = (potentialDiffW > 0.) ? lambdaWI : lambdaWBound; + lambdaW = (potentialDiffW == 0) ? 0.5 * (lambdaWI + lambdaWBound) : lambdaW; + Scalar lambdaNw = (potentialDiffNw > 0.) ? lambdaNwI : lambdaNwBound; + lambdaNw = (potentialDiffNw == 0) ? 0.5 * (lambdaNwI + lambdaNwBound) : lambdaNw; + + + Scalar scalarPerm = permeability.two_norm(); + + //calculate the gravity term + Dune::FieldVector<Scalar, dimWorld> velocityW(unitOuterNormal); + Dune::FieldVector<Scalar, dimWorld> velocityNw(unitOuterNormal); + + //calculate unit distVec + distVec /= dist; + Scalar areaScaling = (unitOuterNormal * distVec); + //this treatment of g allows to account for gravity flux through faces where the face normal has no z component (e.g. parallelepiped grids) + Scalar gravityTermW = (problem_.gravity() * distVec) * density_[wPhaseIdx] * areaScaling; + Scalar gravityTermNw = (problem_.gravity() * distVec) * density_[nPhaseIdx] * areaScaling; + + //calculate velocity depending on the pressure used -> use pc = pn - pw + switch (pressureType_) + { + case pw: + { + velocityW *= lambdaW * scalarPerm * ((cellData.pressure(wPhaseIdx) - pressBound) / dist + gravityTermW); + velocityNw *= lambdaNw * scalarPerm * ((cellData.pressure(wPhaseIdx) - pressBound) / dist + gravityTermNw) + + 0.5 * (lambdaNwI + lambdaNwBound) * scalarPerm * (pcI - pcBound) / dist; + break; + } + case pn: + { + velocityW *= lambdaW * scalarPerm * ((cellData.pressure(nPhaseIdx) - pressBound) / dist + gravityTermW) + - 0.5 * (lambdaWI + lambdaWBound) * scalarPerm * (pcI - pcBound) / dist; + velocityNw *= lambdaNw * scalarPerm * ((cellData.pressure(nPhaseIdx) - pressBound) / dist + gravityTermNw); + break; + } + } + + //store velocities + cellData.fluxData().setVelocity(wPhaseIdx, isIndex, velocityW); + cellData.fluxData().setVelocity(nPhaseIdx, isIndex, velocityNw); + cellData.fluxData().setVelocityMarker(isIndex); + + } //end dirichlet boundary + + else if (bcType.isNeumann(pressEqIdx)) + { + problem_.neumann(boundValues, intersection); + + Dune::FieldVector<Scalar, dimWorld> velocityW(unitOuterNormal); + Dune::FieldVector<Scalar, dimWorld> velocityNw(unitOuterNormal); + + velocityW *= boundValues[wPhaseIdx]; + velocityNw *= boundValues[nPhaseIdx]; + + velocityW /= density_[wPhaseIdx]; + velocityNw /= density_[nPhaseIdx]; + + //store potential gradients for further calculations + cellData.fluxData().setUpwindPotential(wPhaseIdx, isIndex, boundValues[wPhaseIdx]); + cellData.fluxData().setUpwindPotential(nPhaseIdx, isIndex, boundValues[nPhaseIdx]); + + cellData.fluxData().setVelocity(wPhaseIdx, isIndex, velocityW); + cellData.fluxData().setVelocity(nPhaseIdx, isIndex, velocityNw); + cellData.fluxData().setVelocityMarker(isIndex); + } //end neumann boundary + else + { + DUNE_THROW(Dune::NotImplemented, "No valid boundary condition type defined for pressure equation!"); + } +} + } // end of Dune namespace #endif diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dvelocity2p.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dvelocity2p.hh index c6344b5efb9e2b4c672248fb898c06ea23e946b6..c2740d4dc5947eccde91dd02037059777772d30c 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dvelocity2p.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dvelocity2p.hh @@ -140,8 +140,11 @@ public: vtkOutputLevel_ = GET_PARAM_FROM_GROUP(TypeTag, int, Vtk, OutputLevel); } - void calculateInnerInteractionVolumeVelocity(InteractionVolume& interactionVolume, InteractionVolumeContainer& interactionVolumes, TransmissibilityCalculator& transmissibilityCalculator); - void calculateBoundaryInteractionVolumeVelocity(InteractionVolume& interactionVolume, InteractionVolumeContainer& interactionVolumes, TransmissibilityCalculator& transmissibilityCalculator); + void calculateInnerInteractionVolumeVelocity(InteractionVolume& interactionVolume, + CellData & cellData1, CellData & cellData2, CellData & cellData3, CellData & cellData4, + CellData & cellData5, CellData & cellData6, CellData & cellData7, CellData & cellData8, + InteractionVolumeContainer& interactionVolumes, TransmissibilityCalculator& transmissibilityCalculator); + void calculateBoundaryInteractionVolumeVelocity(InteractionVolume& interactionVolume, CellData& cellData, int elemIdx); void initialize(bool solveTwice = true) { @@ -250,7 +253,10 @@ private: // end of template template<class TypeTag> -void FvMpfaL3dVelocity2p<TypeTag>::calculateInnerInteractionVolumeVelocity(InteractionVolume& interactionVolume, InteractionVolumeContainer& interactionVolumes, TransmissibilityCalculator& transmissibilityCalculator) +void FvMpfaL3dVelocity2p<TypeTag>::calculateInnerInteractionVolumeVelocity(InteractionVolume& interactionVolume, + CellData & cellData1, CellData & cellData2, CellData & cellData3, CellData & cellData4, + CellData & cellData5, CellData & cellData6, CellData & cellData7, CellData & cellData8, + InteractionVolumeContainer& interactionVolumes, TransmissibilityCalculator& transmissibilityCalculator) { ElementPointer& elementPointer1 = interactionVolume.getSubVolumeElement(0); ElementPointer& elementPointer2 = interactionVolume.getSubVolumeElement(1); @@ -271,16 +277,6 @@ void FvMpfaL3dVelocity2p<TypeTag>::calculateInnerInteractionVolumeVelocity(Inter int globalIdx7 = problem_.variables().index(*elementPointer7); int globalIdx8 = problem_.variables().index(*elementPointer8); - //get the cell Data - CellData & cellData1 = problem_.variables().cellData(globalIdx1); - CellData & cellData2 = problem_.variables().cellData(globalIdx2); - CellData & cellData3 = problem_.variables().cellData(globalIdx3); - CellData & cellData4 = problem_.variables().cellData(globalIdx4); - CellData & cellData5 = problem_.variables().cellData(globalIdx5); - CellData & cellData6 = problem_.variables().cellData(globalIdx6); - CellData & cellData7 = problem_.variables().cellData(globalIdx7); - CellData & cellData8 = problem_.variables().cellData(globalIdx8); - // pressures flux calculation Dune::FieldVector<Scalar, 8> potW(0); Dune::FieldVector<Scalar, 8> potNw(0); @@ -1837,40 +1833,13 @@ void FvMpfaL3dVelocity2p<TypeTag>::calculateInnerInteractionVolumeVelocity(Inter } template<class TypeTag> -void FvMpfaL3dVelocity2p<TypeTag>::calculateBoundaryInteractionVolumeVelocity(InteractionVolume& interactionVolume, InteractionVolumeContainer& interactionVolumes, TransmissibilityCalculator& transmissibilityCalculator) +void FvMpfaL3dVelocity2p<TypeTag>::calculateBoundaryInteractionVolumeVelocity(InteractionVolume& interactionVolume, CellData& cellData, int elemIdx) { - for (int elemIdx = 0; elemIdx < 8; elemIdx++) - { - if (!interactionVolume.hasSubVolumeElement(elemIdx)) - { - continue; - } - bool isOutside = false; - for (int faceIdx = 0; faceIdx < dim; faceIdx++) - { - int intVolFaceIdx = interactionVolume.getFaceIndexFromSubVolume(elemIdx, faceIdx); - if (interactionVolume.isOutsideFace(intVolFaceIdx)) - { - isOutside = true; - break; - } - } - if (isOutside) - { - continue; - } - ElementPointer& elementPointer = interactionVolume.getSubVolumeElement(elemIdx); // get global coordinate of cell centers const GlobalPosition& globalPos = elementPointer->geometry().center(); - // cell index - int globalIdx = problem_.variables().index(*elementPointer); - - //get the cell Data - CellData & cellData = problem_.variables().cellData(globalIdx); - // permeability vector at boundary DimMatrix permeability(problem_.spatialParams().intrinsicPermeability(*elementPointer)); @@ -2023,7 +1992,6 @@ void FvMpfaL3dVelocity2p<TypeTag>::calculateBoundaryInteractionVolumeVelocity(In "No valid boundary condition type defined for pressure equation!"); } } - } } } diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dvelocity2padaptive.hh b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dvelocity2padaptive.hh index 15674fa2f3b7ec257f75d6f2c166b55e4cd4fdce..dfea523223ba721246f30357293c19f5c024ffe9 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dvelocity2padaptive.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal3dvelocity2padaptive.hh @@ -100,7 +100,7 @@ template<class TypeTag> class FvMpfaL3dVelocity2pAdaptive: public FvMpfaL3dVeloc nPhaseIdx = Indices::nPhaseIdx, pressureIdx = Indices::pressureIdx, saturationIdx = Indices::saturationIdx, - pressEqIdx = Indices::pressEqIdx, + pressEqIdx = Indices::pressureEqIdx, satEqIdx = Indices::satEqIdx, numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; @@ -143,7 +143,9 @@ public: viscosity_[nPhaseIdx] = 0.; } - void calculateHangingNodeInteractionVolumeVelocity(InteractionVolume& interactionVolume); + void calculateHangingNodeInteractionVolumeVelocity(InteractionVolume& interactionVolume, + CellData & cellData1, CellData & cellData2, CellData & cellData3, CellData & cellData4, + CellData & cellData5, CellData & cellData6, CellData & cellData7, CellData & cellData8); void initialize() @@ -181,7 +183,9 @@ private: // only for 3-D general hexahedron template<class TypeTag> -void FvMpfaL3dVelocity2pAdaptive<TypeTag>::calculateHangingNodeInteractionVolumeVelocity(InteractionVolume& interactionVolume) +void FvMpfaL3dVelocity2pAdaptive<TypeTag>::calculateHangingNodeInteractionVolumeVelocity(InteractionVolume& interactionVolume, + CellData & cellData1, CellData & cellData2, CellData & cellData3, CellData & cellData4, + CellData & cellData5, CellData & cellData6, CellData & cellData7, CellData & cellData8) { ElementPointer& elementPointer1 = interactionVolume.getSubVolumeElement(0); ElementPointer& elementPointer2 = interactionVolume.getSubVolumeElement(1); @@ -202,16 +206,6 @@ void FvMpfaL3dVelocity2pAdaptive<TypeTag>::calculateHangingNodeInteractionVolume int globalIdx7 = problem_.variables().index(*elementPointer7); int globalIdx8 = problem_.variables().index(*elementPointer8); - //get the cell Data - CellData & cellData1 = problem_.variables().cellData(globalIdx1); - CellData & cellData2 = problem_.variables().cellData(globalIdx2); - CellData & cellData3 = problem_.variables().cellData(globalIdx3); - CellData & cellData4 = problem_.variables().cellData(globalIdx4); - CellData & cellData5 = problem_.variables().cellData(globalIdx5); - CellData & cellData6 = problem_.variables().cellData(globalIdx6); - CellData & cellData7 = problem_.variables().cellData(globalIdx7); - CellData & cellData8 = problem_.variables().cellData(globalIdx8); - // pressures flux calculation Dune::FieldVector<Scalar, 8> potW(0); Dune::FieldVector<Scalar, 8> potNw(0); diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/omethod/fvmpfao2dpressurevelocity2p.hh b/dumux/decoupled/2p/diffusion/fvmpfa/omethod/fvmpfao2dpressurevelocity2p.hh index 505be6f4c53ee9b1743b6f41bcf62086e94d9c39..27156a2b8b3ca5e97426e45061fa77f96254039e 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/omethod/fvmpfao2dpressurevelocity2p.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/omethod/fvmpfao2dpressurevelocity2p.hh @@ -103,8 +103,8 @@ template<class TypeTag> class FvMpfaO2dPressureVelocity2p: public FvMpfaO2dPress sn = Indices::saturationNw, pressureIdx = Indices::pressureIdx, saturationIdx = Indices::saturationIdx, - eqIdxPress = Indices::pressureEqIdx, - eqIdxSat = Indices::satEqIdx, + pressEqIdx = Indices::pressureEqIdx, + satEqIdx = Indices::satEqIdx, numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; @@ -138,13 +138,7 @@ public: { this->updateMaterialLaws(); - //reset velocities - int size = problem_.gridView().size(0); - for (int i = 0; i < size; i++) - { - CellData& cellData = problem_.variables().cellData(i); - cellData.fluxData().resetVelocity(); - } + this->storePressureSolution(); if (!calculateVelocityInTransport()) calculateVelocity(); @@ -388,7 +382,7 @@ void FvMpfaO2dPressureVelocity2p<TypeTag>::calculateVelocityOnBoundary(const Int problem_.boundaryTypes(bcType, intersection); PrimaryVariables boundValues(0.0); - if (bcType.isDirichlet(eqIdxPress)) + if (bcType.isDirichlet(pressEqIdx)) { problem_.dirichlet(boundValues, intersection); @@ -423,7 +417,7 @@ void FvMpfaO2dPressureVelocity2p<TypeTag>::calculateVelocityOnBoundary(const Int //determine saturation at the boundary -> if no saturation is known directly at the boundary use the cell saturation Scalar satW = 0; Scalar satNw = 0; - if (bcType.isDirichlet(eqIdxSat)) + if (bcType.isDirichlet(satEqIdx)) { switch (saturationType_) { @@ -529,7 +523,7 @@ void FvMpfaO2dPressureVelocity2p<TypeTag>::calculateVelocityOnBoundary(const Int } //end dirichlet boundary - else if (bcType.isNeumann(eqIdxPress)) + else if (bcType.isNeumann(pressEqIdx)) { problem_.neumann(boundValues, intersection); diff --git a/dumux/decoupled/2p/diffusion/fvmpfa/omethod/fvmpfao2dvelocity2p.hh b/dumux/decoupled/2p/diffusion/fvmpfa/omethod/fvmpfao2dvelocity2p.hh index c532e653cb34cde9edf3142300f7906261033dbc..914fff2d425eed268c56cdc9fe8ad9c63268e9bd 100644 --- a/dumux/decoupled/2p/diffusion/fvmpfa/omethod/fvmpfao2dvelocity2p.hh +++ b/dumux/decoupled/2p/diffusion/fvmpfa/omethod/fvmpfao2dvelocity2p.hh @@ -126,7 +126,7 @@ public: void calculateInnerInteractionVolumeVelocity(InteractionVolume& interactionVolume, CellData& cellData1, CellData& cellData2, CellData& cellData3, CellData& cellData4, InnerBoundaryVolumeFaces& innerBoundaryVolumeFaces); void calculateBoundaryInteractionVolumeVelocity(InteractionVolume& interactionVolume, CellData& cellData, int elemIdx); - void initialize(bool solveTwice = true) + void initialize() { ElementIterator element = problem_.gridView().template begin<0>(); FluidState fluidState; diff --git a/dumux/decoupled/2p2c/fvpressure2p2cadaptive.hh b/dumux/decoupled/2p2c/fvpressure2p2cadaptive.hh index a810aef384345e1af81edb76317c1d6526c0cfc7..2b571156b33c8258533d2f9329381e45e44ba1a1 100644 --- a/dumux/decoupled/2p2c/fvpressure2p2cadaptive.hh +++ b/dumux/decoupled/2p2c/fvpressure2p2cadaptive.hh @@ -27,8 +27,7 @@ // dumux environment // include 2p mpfa pressure model -#include <dumux/decoupled/common/fv/mpfa/fvmpfaproperties.hh> -#include <dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dpressure2padaptive.hh> +#include <dumux/decoupled/2p/diffusion/fvmpfa/lmethod/fvmpfal2dtransmissibilitycalculator.hh> #include <dumux/decoupled/2p2c/fvpressure2p2c.hh> #include <dumux/common/math.hh> @@ -122,6 +121,7 @@ template<class TypeTag> class FVPressure2P2CAdaptive // the typenames used for the stiffness matrix and solution vector typedef typename GET_PROP_TYPE(TypeTag, PressureCoefficientMatrix) Matrix; + typedef Dumux::FvMpfaL2dTransmissibilityCalculator<TypeTag> TransmissibilityCalculator; protected: Problem& problem() { @@ -166,7 +166,7 @@ public: * \param problem a problem class object */ FVPressure2P2CAdaptive(Problem& problem) : FVPressure2P2C<TypeTag>(problem), - problem_(problem) + problem_(problem), transmissibilityCalculator_(problem) { enableVolumeIntegral = GET_PARAM_FROM_GROUP(TypeTag,bool, Impet, EnableVolumeIntegral); enableMPFA= GET_PARAM_FROM_GROUP(TypeTag,bool, GridAdapt, EnableMultiPointFluxApproximation); @@ -206,7 +206,7 @@ protected: bool enableMPFA; //!< Enables mpfa method to calculate the fluxes near hanging nodes bool enableSecondHalfEdge; //!< If possible, 2 interaction volumes are used for the mpfa method near hanging nodes //! The 2p Mpfa pressure module, that is only used for the calulation of transmissibility of the second interaction volumes - Dune::shared_ptr<FvMpfaL2dPressure2pAdaptive<TypeTag> > pressureModelAdaptive2p_; + TransmissibilityCalculator transmissibilityCalculator_; }; @@ -1181,9 +1181,6 @@ int FVPressure2P2CAdaptive<TypeTag>::transmissibilityAdapter_(const Intersection } /**** end find 4 faces **/ - - if(!pressureModelAdaptive2p_) - pressureModelAdaptive2p_= Dune::make_shared<FvMpfaL2dPressure2pAdaptive<TypeTag> >(problem()) ; // create Interaction Volume object Dumux::FVMPFALInteractionVolume<TypeTag> interactionVolume; @@ -1275,12 +1272,12 @@ int FVPressure2P2CAdaptive<TypeTag>::transmissibilityAdapter_(const Intersection std::vector<Dune::FieldVector<Scalar, dim> > lambda(4, unity); Dune::FieldMatrix<Scalar,dim,2*dim-dim+1> T; - int triangleType = pressureModelAdaptive2p_->calculateTransmissibility( + int triangleType = transmissibilityCalculator_.calculateTransmissibility( T, interactionVolume, lambda, 0, 1, 2, 3); // 3.decide which triangle (which transmissibility coefficients) to use - if (triangleType == pressureModelAdaptive2p_->rightTriangle) + if (triangleType == TransmissibilityCalculator::rightTriangle) { additionalIntersectionIt = isIt23; // Translate flux from 2p mpfa-l local indexing to @@ -1290,7 +1287,7 @@ int FVPressure2P2CAdaptive<TypeTag>::transmissibilityAdapter_(const Intersection additionalT[1] = -T[1][1]; additionalT[2] = -T[1][0]; } - else if (triangleType == pressureModelAdaptive2p_->leftTriangle) + else if (triangleType == TransmissibilityCalculator::leftTriangle) { additionalIntersectionIt = isIt14; // Translate flux from 2p mpfa-l local indexing to