#include "Includes.h" module EllipticIP use SMConstants use Headers use MeshTypes use ElementClass use HexMeshClass use Physics use PhysicsStorage use VariableConversion use MPI_Process_Info use MPI_Face_Class use EllipticDiscretizationClass use DGSEMClass use FluidData use BoundaryConditions , only: BCs use Utilities , only: toLower, dot_product implicit none ! ! private public InteriorPenalty_t, SIPG, IIPG, NIPG public IP_GradientInterfaceSolution, IP_GradientInterfaceSolutionBoundary public IP_GradientInterfaceSolutionMPI integer, parameter :: SIPG = -1 integer, parameter :: IIPG = 0 integer, parameter :: NIPG = 1 type, extends(EllipticDiscretization_t) :: InteriorPenalty_t procedure(PenaltyParameter_f), pointer :: PenaltyParameter integer :: IPmethod = SIPG contains procedure :: Construct => IP_Construct procedure :: ComputeGradient => IP_ComputeGradient procedure :: ComputeInnerFluxes => IP_ComputeInnerFluxes procedure :: RiemannSolver => IP_RiemannSolver #if (defined(NAVIERSTOKES) && (!(SPALARTALMARAS))) || defined(SCALAR) procedure :: RiemannSolver_Jacobians => IP_RiemannSolver_Jacobians #endif procedure :: Describe => IP_Describe end type InteriorPenalty_t abstract interface function PenaltyParameter_f(self, f) use SMConstants use FaceClass import InteriorPenalty_t implicit none class(InteriorPenalty_t) :: self class(Face), intent(in) :: f real(kind=RP) :: PenaltyParameter_f end function PenaltyParameter_f end interface ! ! ======== contains ! ======== ! subroutine IP_Construct(self, controlVariables, eqname) use FTValueDictionaryClass use mainKeywordsModule use MPI_Process_Info use PhysicsStorage implicit none class(InteriorPenalty_t) :: self class(FTValueDictionary), intent(in) :: controlVariables integer, intent(in) :: eqname ! ! --------------- ! Local variables ! --------------- ! character(len=LINE_LENGTH) :: eqnameaux character(len=LINE_LENGTH) :: IPvariant ! ! ---------------------------------------------------------- ! Set the particular procedures to compute the elliptic flux ! ---------------------------------------------------------- ! select case (eqName) case(ELLIPTIC_NS) self % eqName = ELLIPTIC_NS self % PenaltyParameter => PenaltyParameterNS case(ELLIPTIC_NSSA) self % eqName = ELLIPTIC_NSSA self % PenaltyParameter => PenaltyParameterNS case(ELLIPTIC_iNS) self % eqName = ELLIPTIC_iNS self % PenaltyParameter => PenaltyParameterNS case(ELLIPTIC_CH) self % eqName = ELLIPTIC_CH self % PenaltyParameter => PenaltyParameterCH case(ELLIPTIC_MU) self % eqName = ELLIPTIC_MU self % PenaltyParameter => PenaltyParameterNS case(ELLIPTIC_SLR) self % eqName = ELLIPTIC_SLR self % PenaltyParameter => PenaltyParameterNS case default print*, "Unrecognized equation" errorMessage(STD_OUT) error stop end select ! ! Request the penalty parameter ! ----------------------------- if ( controlVariables % containsKey("penalty parameter") ) then self % sigma = controlVariables % doublePrecisionValueForKey("penalty parameter") else ! ! Set 1.0 by default ! ------------------ self % sigma = 1.0_RP end if ! ! Request the interior penalty variant ! ------------------------------------ if ( controlVariables % containsKey("interior penalty variant") ) then IPvariant = controlVariables % stringValueForKey("interior penalty variant", LINE_LENGTH) call toLower(IPVariant) else ! ! Select SIPG by default ! ---------------------- IPvariant = "sipg" end if select case (trim(IPvariant)) case("sipg") self % IPmethod = SIPG case("iipg") self % IPmethod = IIPG case("nipg") self % IPmethod = NIPG case default if ( MPI_Process % isRoot ) then print*, "Unknown selected IP variant", trim(IPvariant), "." print*, "Available options are:" print*, " * SIPG" print*, " * IIPG" print*, " * NIPG" errorMessage(STD_OUT) error stop end if end select end subroutine IP_Construct subroutine IP_Describe(self) implicit none class(InteriorPenalty_t), intent(in) :: self ! ! Display the configuration ! ------------------------- if (MPI_Process % isRoot) write(STD_OUT,'(/)') call Subsection_Header("Viscous discretization") if (.not. MPI_Process % isRoot ) return write(STD_OUT,'(30X,A,A30,A)') "->","Numerical scheme: ","IP" select case(self % IPmethod) case(SIPG) write(STD_OUT,'(30X,A,A30,A)') "->","Interior penalty variant: ","SIPG" case(NIPG) write(STD_OUT,'(30X,A,A30,A)') "->","Interior penalty variant: ","NIPG" case(IIPG) write(STD_OUT,'(30X,A,A30,A)') "->","Interior penalty variant: ","IIPG" end select write(STD_OUT,'(30X,A,A30,F10.3)') "->","Penalty parameter: ", self % sigma end subroutine IP_Describe subroutine IP_ComputeGradient(self, nEqn, nGradEqn, mesh, time, GetGradients, HO_Elements) use HexMeshClass use PhysicsStorage use Physics use MPI_Process_Info implicit none class(InteriorPenalty_t), intent(in) :: self integer, intent(in) :: nEqn, nGradEqn class(HexMesh) :: mesh real(kind=RP), intent(in) :: time procedure(GetGradientValues_f) :: GetGradients logical, intent(in), optional :: HO_Elements ! ! --------------- ! Local variables ! --------------- ! integer :: Nx, Ny, Nz integer :: i, j, k integer :: eID , fID , dimID , eqID, fIDs(6), iFace, iEl logical :: HOElements if (present(HO_Elements)) then HOElements = HO_Elements else HOElements = .false. end if ! ! ********************************* ! Volume loops and prolong to faces ! ********************************* ! if (HOElements) then !$omp do schedule(runtime) do eID = 1, size(mesh % HO_Elements) associate( e => mesh % elements(mesh % HO_Elements(eID)) ) call e % ComputeLocalGradient(nEqn, nGradEqn, GetGradients, .false.) ! ! Prolong to faces ! ---------------- fIDs = e % faceIDs call e % ProlongGradientsToFaces(nGradEqn, & mesh % faces(fIDs(1)),& mesh % faces(fIDs(2)),& mesh % faces(fIDs(3)),& mesh % faces(fIDs(4)),& mesh % faces(fIDs(5)),& mesh % faces(fIDs(6)) ) end associate end do !$omp end do else !$omp do schedule(runtime) do eID = 1, size(mesh % elements) associate( e => mesh % elements(eID) ) call e % ComputeLocalGradient(nEqn, nGradEqn, GetGradients, .false.) ! ! Prolong to faces ! ---------------- fIDs = e % faceIDs call e % ProlongGradientsToFaces(nGradEqn, & mesh % faces(fIDs(1)),& mesh % faces(fIDs(2)),& mesh % faces(fIDs(3)),& mesh % faces(fIDs(4)),& mesh % faces(fIDs(5)),& mesh % faces(fIDs(6)) ) end associate end do !$omp end do end if ! ! ********************************************** ! Compute interface solution of non-shared faces ! ********************************************** ! if (HOElements) then !$omp do schedule(runtime) private(fID) do iFace = 1, size(mesh % HO_FacesInterior) fID = mesh % HO_FacesInterior(iFace) call IP_GradientInterfaceSolution(mesh % faces(fID), nEqn, nGradEqn, GetGradients) end do !$omp end do else !$omp do schedule(runtime) private(fID) do iFace = 1, size(mesh % faces_interior) fID = mesh % faces_interior(iFace) call IP_GradientInterfaceSolution(mesh % faces(fID), nEqn, nGradEqn, GetGradients) end do !$omp end do end if if (HOElements) then !$omp do schedule(runtime) private(fID) do iFace = 1, size(mesh % HO_FacesBoundary) fID = mesh % HO_FacesBoundary(iFace) call IP_GradientInterfaceSolutionBoundary(mesh % faces(fID), nEqn, nGradEqn, time, GetGradients) end do !$omp end do else !$omp do schedule(runtime) private(fID) do iFace = 1, size(mesh % faces_boundary) fID = mesh % faces_boundary(iFace) call IP_GradientInterfaceSolutionBoundary(mesh % faces(fID), nEqn, nGradEqn, time, GetGradients) end do !$omp end do end if ! ! ********************** ! Compute face integrals ! ********************** ! if (HOElements) then !$omp do schedule(runtime) private(eID) do iEl = 1, size(mesh % HO_ElementsSequential) eID = mesh % HO_ElementsSequential(iEl) call IP_ComputeGradientFaceIntegrals(self,nGradEqn, mesh % elements(eID), mesh) end do !$omp end do else !$omp do schedule(runtime) private(eID) do iEl = 1, size(mesh % elements_sequential) eID = mesh % elements_sequential(iEl) call IP_ComputeGradientFaceIntegrals(self,nGradEqn, mesh % elements(eID), mesh) end do !$omp end do end if ! ! ****************** ! Wait for MPI faces ! ****************** ! #ifdef _HAS_MPI_ !$omp single if ( MPI_Process % doMPIAction ) then call mesh % GatherMPIFacesSolution(nEqn) end if !$omp end single ! ! ******************************* ! Compute MPI interface solutions ! ******************************* ! !$omp do schedule(runtime) private(fID) do iFace = 1, size(mesh % faces_mpi) fID = mesh % faces_mpi(iFace) call IP_GradientInterfaceSolutionMPI(mesh % faces(fID), nEqn, nGradEqn, GetGradients) end do !$omp end do ! ! ************************************************** ! Compute face integrals for elements with MPI faces ! ************************************************** ! if (HOElements) then !$omp do schedule(runtime) private(eID) do iEl = 1, size(mesh % HO_ElementsMPI) eID = mesh % HO_ElementsMPI(iEl) call IP_ComputeGradientFaceIntegrals(self,nGradEqn, mesh % elements(eID), mesh) end do !$omp end do else !$omp do schedule(runtime) private(eID) do iEl = 1, size(mesh % elements_mpi) eID = mesh % elements_mpi(iEl) call IP_ComputeGradientFaceIntegrals(self,nGradEqn, mesh % elements(eID), mesh) end do !$omp end do end if #endif end subroutine IP_ComputeGradient ! !/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ! subroutine IP_ComputeGradientFaceIntegrals(self,nGradEqn, e, mesh) use ElementClass use HexMeshClass use PhysicsStorage use Physics use DGIntegrals implicit none type(InteriorPenalty_t), intent(in) :: self integer, intent(in) :: nGradEqn class(Element) :: e class(HexMesh) :: mesh ! ! --------------- ! Local variables ! --------------- ! integer :: i, j, k real(kind=RP) :: invjac real(kind=RP) :: faceInt_x(nGradEqn, 0:e%Nxyz(1) , 0:e%Nxyz(2) , 0:e%Nxyz(3) ) real(kind=RP) :: faceInt_y(nGradEqn, 0:e%Nxyz(1) , 0:e%Nxyz(2) , 0:e%Nxyz(3) ) real(kind=RP) :: faceInt_z(nGradEqn, 0:e%Nxyz(1) , 0:e%Nxyz(2) , 0:e%Nxyz(3) ) call VectorWeakIntegrals % StdFace(e, nGradEqn, & mesh % faces(e % faceIDs(EFRONT)) % storage(e % faceSide(EFRONT)) % unStar, & mesh % faces(e % faceIDs(EBACK)) % storage(e % faceSide(EBACK)) % unStar, & mesh % faces(e % faceIDs(EBOTTOM)) % storage(e % faceSide(EBOTTOM)) % unStar, & mesh % faces(e % faceIDs(ERIGHT)) % storage(e % faceSide(ERIGHT)) % unStar, & mesh % faces(e % faceIDs(ETOP)) % storage(e % faceSide(ETOP)) % unStar, & mesh % faces(e % faceIDs(ELEFT)) % storage(e % faceSide(ELEFT)) % unStar, & faceInt_x, faceInt_y, faceInt_z ) ! ! Add the integrals weighted with the Jacobian ! -------------------------------------------- do k = 0, e % Nxyz(3) ; do j = 0, e % Nxyz(2) ; do i = 0, e % Nxyz(1) invjac = self % IPmethod * e % geom % invJacobian(i,j,k) e % storage % U_x(:,i,j,k) = e % storage % U_x(:,i,j,k) + faceInt_x(:,i,j,k) * invjac e % storage % U_y(:,i,j,k) = e % storage % U_y(:,i,j,k) + faceInt_y(:,i,j,k) * invjac e % storage % U_z(:,i,j,k) = e % storage % U_z(:,i,j,k) + faceInt_z(:,i,j,k) * invjac end do ; end do ; end do ! end subroutine IP_ComputeGradientFaceIntegrals ! !/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ! subroutine IP_GradientInterfaceSolution(f, nEqn, nGradEqn, GetGradients) use Physics use ElementClass use FaceClass implicit none ! ! --------- ! Arguments ! --------- ! type(Face) :: f integer, intent(in) :: nEqn, nGradEqn procedure(GetGradientValues_f) :: GetGradients ! ! --------------- ! Local variables ! --------------- ! real(kind=RP) :: UL(nGradEqn), UR(nGradEqn) real(kind=RP) :: Uhat(nGradEqn) real(kind=RP) :: Hflux(nGradEqn,NDIM,0:f % Nf(1), 0:f % Nf(2)) integer :: i,j do j = 0, f % Nf(2) ; do i = 0, f % Nf(1) #ifdef MULTIPHASE call GetGradients(nEqn, nGradEqn, Q = f % storage(1) % Q(:,i,j), U = UL, rho_ = f % storage(1) % rho(i,j)) call GetGradients(nEqn, nGradEqn, Q = f % storage(2) % Q(:,i,j), U = UR, rho_ = f % storage(2) % rho(i,j)) #else call GetGradients(nEqn, nGradEqn, Q = f % storage(1) % Q(:,i,j), U = UL) call GetGradients(nEqn, nGradEqn, Q = f % storage(2) % Q(:,i,j), U = UR) #endif #ifdef MULTIPHASE ! The multiphase solver needs the Chemical potential as first entropy variable ! ---------------------------------------------------------------------------- UL(IGMU) = f % storage(1) % mu(1,i,j) UR(IGMU) = f % storage(2) % mu(1,i,j) #endif Uhat = 0.5_RP * (UL - UR) * f % geom % jacobian(i,j) Hflux(:,IX,i,j) = Uhat * f % geom % normal(IX,i,j) Hflux(:,IY,i,j) = Uhat * f % geom % normal(IY,i,j) Hflux(:,IZ,i,j) = Uhat * f % geom % normal(IZ,i,j) end do ; end do call f % ProjectGradientFluxToElements(nGradEqn, HFlux,(/1,2/),1) end subroutine IP_GradientInterfaceSolution subroutine IP_GradientInterfaceSolutionMPI(f, nEqn, nGradEqn, GetGradients) use Physics use ElementClass use FaceClass implicit none ! ! --------- ! Arguments ! --------- ! type(Face) :: f integer, intent(in) :: nEqn, nGradEqn procedure(GetGradientValues_f) :: GetGradients ! ! --------------- ! Local variables ! --------------- ! real(kind=RP) :: UL(nGradEqn), UR(nGradEqn) real(kind=RP) :: Uhat(nGradEqn) real(kind=RP) :: Hflux(nGradEqn,NDIM,0:f % Nf(1), 0:f % Nf(2)) integer :: i,j, thisSide do j = 0, f % Nf(2) ; do i = 0, f % Nf(1) #ifdef MULTIPHASE call GetGradients(nEqn, nGradEqn, Q = f % storage(1) % Q(:,i,j), U = UL, rho_ = f % storage(1) % rho(i,j)) call GetGradients(nEqn, nGradEqn, Q = f % storage(2) % Q(:,i,j), U = UR, rho_ = f % storage(2) % rho(i,j)) #else call GetGradients(nEqn, nGradEqn, Q = f % storage(1) % Q(:,i,j), U = UL) call GetGradients(nEqn, nGradEqn, Q = f % storage(2) % Q(:,i,j), U = UR) #endif #ifdef MULTIPHASE ! The multiphase solver needs the Chemical potential as first entropy variable ! ---------------------------------------------------------------------------- UL(IGMU) = f % storage(1) % mu(1,i,j) UR(IGMU) = f % storage(2) % mu(1,i,j) #endif Uhat = 0.5_RP * (UL - UR) * f % geom % jacobian(i,j) Hflux(:,IX,i,j) = Uhat * f % geom % normal(IX,i,j) Hflux(:,IY,i,j) = Uhat * f % geom % normal(IY,i,j) Hflux(:,IZ,i,j) = Uhat * f % geom % normal(IZ,i,j) end do ; end do thisSide = maxloc(f % elementIDs, dim = 1) call f % ProjectGradientFluxToElements(nGradEqn, HFlux,(/thisSide, HMESH_NONE/),1) end subroutine IP_GradientInterfaceSolutionMPI subroutine IP_GradientInterfaceSolutionBoundary(f, nEqn, nGradEqn, time, GetGradients) use Physics use FaceClass implicit none type(Face) :: f integer, intent(in) :: nEqn integer, intent(in) :: nGradEqn real(kind=RP) :: time procedure(GetGradientValues_f) :: GetGradients ! ! --------------- ! Local variables ! --------------- ! integer :: i, j real(kind=RP) :: Uhat(nGradEqn), UL(nGradEqn), UR(nGradEqn) real(kind=RP) :: bvExt(nEqn) #if defined(INCNS) || defined(MULTIPHASE) if ( trim(BCs(f % zone) % bc % BCType) /= "freeslipwall" ) then #endif do j = 0, f % Nf(2) ; do i = 0, f % Nf(1) bvExt = f % storage(1) % Q(:,i,j) call BCs(f % zone) % bc % StateForEqn( nEqn, f % geom % x(:,i,j), & time , & f % geom % normal(:,i,j) , & bvExt ) ! ! ------------------- ! u, v, w, T averages ! ------------------- ! #ifdef MULTIPHASE call GetGradients(nEqn, nGradEqn, f % storage(1) % Q(:,i,j), UL, f % storage(1) % rho(i,j)) call GetGradients(nEqn, nGradEqn, bvExt, UR, f % storage(1) % rho(i,j)) #else call GetGradients(nEqn, nGradEqn, f % storage(1) % Q(:,i,j), UL) call GetGradients(nEqn, nGradEqn, bvExt, UR) #endif #ifdef MULTIPHASE ! The multiphase solver needs the Chemical potential as first entropy variable ! ---------------------------------------------------------------------------- UL(IGMU) = f % storage(1) % mu(1,i,j) UR(IGMU) = f % storage(1) % mu(1,i,j) #endif Uhat = 0.5_RP * (UL - UR) * f % geom % jacobian(i,j) f % storage(1) % unStar(:,1,i,j) = Uhat * f % geom % normal(1,i,j) f % storage(1) % unStar(:,2,i,j) = Uhat * f % geom % normal(2,i,j) f % storage(1) % unStar(:,3,i,j) = Uhat * f % geom % normal(3,i,j) end do ; end do #if defined(INCNS) || defined(MULTIPHASE) else ! ! ***************************** ! Set W* = W in free slip walls: [[W]] = 0! ! ***************************** f % storage(1) % unStar = 0.0_RP end if #endif end subroutine IP_GradientInterfaceSolutionBoundary ! !/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ! subroutine IP_ComputeInnerFluxes( self , nEqn, nGradEqn, EllipticFlux, GetViscosity, e , contravariantFlux ) use ElementClass use PhysicsStorage use Physics implicit none class(InteriorPenalty_t) , intent(in) :: self integer, intent(in) :: nEqn, nGradEqn procedure(EllipticFlux_f) :: EllipticFlux procedure(GetViscosity_f) :: GetViscosity type(Element) :: e real(kind=RP) , intent (out) :: contravariantFlux(1:nEqn, 0:e%Nxyz(1), 0:e%Nxyz(2), 0:e%Nxyz(3), 1:NDIM) ! ! --------------- ! Local variables ! --------------- ! real(kind=RP) :: delta real(kind=RP) :: cartesianFlux(1:nEqn, 1:NDIM) real(kind=RP) :: mu(0:e % Nxyz(1), 0:e % Nxyz(2), 0:e % Nxyz(3)) real(kind=RP) :: beta(0:e % Nxyz(1), 0:e % Nxyz(2), 0:e % Nxyz(3)) real(kind=RP) :: kappa(0:e % Nxyz(1), 0:e % Nxyz(2), 0:e % Nxyz(3)) integer :: i, j, k #if (!defined(CAHNHILLIARD)) #if defined(NAVIERSTOKES) && (!(SPALARTALMARAS)) mu = e % storage % mu_ns(1,:,:,:) kappa = e % storage % mu_ns(2,:,:,:) beta = 0.0_RP #elif defined(NAVIERSTOKES) && (SPALARTALMARAS) mu = e % storage % mu_ns(1,:,:,:) kappa = e % storage % mu_ns(2,:,:,:) beta = e % storage % mu_ns(3,:,:,:) #elif defined(INCNS) do k = 0, e % Nxyz(3) ; do j = 0, e % Nxyz(2) ; do i = 0, e % Nxyz(1) call GetViscosity(e % storage % Q(INSRHO,i,j,k), mu(i,j,k)) end do ; end do ; end do kappa = 0.0_RP beta = 0.0_RP #endif #else /* !(defined(CAHNHILLIARD) */ #if defined(NAVIERSTOKES) do k = 0, e % Nxyz(3) ; do j = 0, e % Nxyz(2) ; do i = 0, e % Nxyz(1) call GetViscosity(e % storage % c(1,i,j,k), mu(i,j,k)) end do ; end do ; end do kappa = 1.0_RP / ( thermodynamics % gammaMinus1 * & POW2( dimensionless % Mach) * dimensionless % Pr ) * mu beta = 0.0_RP #elif defined(INCNS) do k = 0, e % Nxyz(3) ; do j = 0, e % Nxyz(2) ; do i = 0, e % Nxyz(1) call GetViscosity(e % storage % c(1,i,j,k), mu(i,j,k)) end do ; end do ; end do kappa = 0.0_RP beta = 0.0_RP #endif #endif #if defined(SCALAR) mu = 1.0_RP kappa = 0.0_RP beta = 0.0_RP #endif do k = 0, e%Nxyz(3) ; do j = 0, e%Nxyz(2) ; do i = 0, e%Nxyz(1) call EllipticFlux( nEqn, nGradEqn, e % storage % Q(:,i,j,k), e % storage % U_x(:,i,j,k), & e % storage % U_y(:,i,j,k) , e % storage % U_z(:,i,j,k), mu(i,j,k), beta(i,j,k), kappa(i,j,k), cartesianFlux ) contravariantFlux(:,i,j,k,IX) = cartesianFlux(:,IX) * e % geom % jGradXi(IX,i,j,k) & + cartesianFlux(:,IY) * e % geom % jGradXi(IY,i,j,k) & + cartesianFlux(:,IZ) * e % geom % jGradXi(IZ,i,j,k) contravariantFlux(:,i,j,k,IY) = cartesianFlux(:,IX) * e % geom % jGradEta(IX,i,j,k) & + cartesianFlux(:,IY) * e % geom % jGradEta(IY,i,j,k) & + cartesianFlux(:,IZ) * e % geom % jGradEta(IZ,i,j,k) contravariantFlux(:,i,j,k,IZ) = cartesianFlux(:,IX) * e % geom % jGradZeta(IX,i,j,k) & + cartesianFlux(:,IY) * e % geom % jGradZeta(IY,i,j,k) & + cartesianFlux(:,IZ) * e % geom % jGradZeta(IZ,i,j,k) end do ; end do ; end do end subroutine IP_ComputeInnerFluxes ! !/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ! ! ---------------------------------------- ! Function to get the IP penalty parameter ! ---------------------------------------- function PenaltyParameterNS(self, f) use FaceClass implicit none class(InteriorPenalty_t) :: self class(Face), intent(in) :: f real(kind=RP) :: PenaltyParameterNS PenaltyParameterNS = 0.5_RP*self % sigma * (maxval(f % Nf)+1)*(maxval(f % Nf)+2) / f % geom % h end function PenaltyParameterNS function PenaltyParameterCH(self, f) use FaceClass implicit none class(InteriorPenalty_t) :: self class(Face), intent(in) :: f real(kind=RP) :: PenaltyParameterCH PenaltyParameterCH = 0.5_RP*self % sigma * (maxval(f % Nf)+1)*(maxval(f % Nf)+2) / f % geom % h !PenaltyParameterCH = 0.25_RP * self % sigma * (maxval(f % Nf)) *(maxval(f % Nf)+1) / f % geom % h end function PenaltyParameterCH ! !/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ! subroutine IP_RiemannSolver ( self , nEqn, nGradEqn, EllipticFlux, f, QLeft , QRight , U_xLeft , U_yLeft , U_zLeft , U_xRight , U_yRight , U_zRight , & mu_left, mu_right, nHat , dWall, & #ifdef MULTIPHASE sigma, & #endif flux ) use SMConstants use PhysicsStorage use Physics use FaceClass implicit none class(InteriorPenalty_t) :: self integer, intent(in) :: nEqn integer, intent(in) :: nGradEqn procedure(EllipticFlux_f) :: EllipticFlux class(Face), intent(in) :: f real(kind=RP), intent(in) :: QLeft(nEqn) real(kind=RP), intent(in) :: QRight(nEqn) real(kind=RP), intent(in) :: U_xLeft(nGradEqn) real(kind=RP), intent(in) :: U_yLeft(nGradEqn) real(kind=RP), intent(in) :: U_zLeft(nGradEqn) real(kind=RP), intent(in) :: U_xRight(nGradEqn) real(kind=RP), intent(in) :: U_yRight(nGradEqn) real(kind=RP), intent(in) :: U_zRight(nGradEqn) real(kind=RP), intent(in) :: mu_left(3), mu_right(3) real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(in) :: dWall #ifdef MULTIPHASE real(kind=RP), intent(in) :: sigma(nEqn) #endif real(kind=RP), intent(out) :: flux(nEqn) ! ! --------------- ! Local variables ! --------------- ! real(kind=RP) :: Q(nEqn) , U_x(nGradEqn) , U_y(nGradEqn) , U_z(nGradEqn) real(kind=RP) :: flux_vec(nEqn,NDIM) real(kind=RP) :: flux_vecL(nEqn,NDIM) real(kind=RP) :: flux_vecR(nEqn,NDIM) real(kind=RP) :: delta, mu call EllipticFlux(nEqn, nGradEqn, QLeft , U_xLeft , U_yLeft , U_zLeft, mu_left(1), mu_left(2), mu_left(3), flux_vecL ) call EllipticFlux(nEqn, nGradEqn, QRight , U_xRight , U_yRight , U_zRight, mu_right(1), mu_right(2), mu_right(3), flux_vecR ) flux_vec = 0.5_RP * (flux_vecL + flux_vecR) #ifdef NAVIERSTOKES flux = flux_vec(:,IX) * nHat(IX) + flux_vec(:,IY) * nHat(IY) + flux_vec(:,IZ) * nHat(IZ) - self % PenaltyParameter(f) * dimensionless % mu * (QLeft - QRight) #else mu = 0.5_RP*(mu_left(1) + mu_right(1)) flux = flux_vec(:,IX) * nHat(IX) + flux_vec(:,IY) * nHat(IY) + flux_vec(:,IZ) * nHat(IZ) - self % PenaltyParameter(f) * mu * (QLeft - QRight) #endif end subroutine IP_RiemannSolver ! !/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ! ! ----------------------------------------------------------------------------- ! Subroutine to get the Jacobian (with respect to ∇q⁺ and ∇q⁻) of the numerical ! contravariant fluxes on a face. Stored in: ! -> f % storage(side) % dFv_dGradQF(:,:,:,:,i,j) ! | |_| | | |_| ! | | | | | ! | | | | |__Coordinate indexes in face ! | | | |_____1 for inner term, 2 for outer term ! | | |_______∇q component: 1, 2, 3 ! | |__________Jacobian for this component ! |_______________________________1 for ∇q⁺ and 2 for ∇q⁻ ! ----------------------------------------------------------------------------- #if (defined(NAVIERSTOKES) && (!(SPALARTALMARAS))) || defined(SCALAR) subroutine IP_RiemannSolver_Jacobians( self, f) use FaceClass use Physics use PhysicsStorage implicit none !-------------------------------------------- class(InteriorPenalty_t), intent(in) :: self type(Face) , intent(inout) :: f !-------------------------------------------- real(kind=RP), DIMENSION(NCONS,NCONS,NDIM,NDIM) :: df_dgradq ! Cartesian Jacobian tensor real(kind=RP), DIMENSION(NCONS,NCONS,NDIM) :: dfdq_ real(kind=RP), parameter :: SideSign(2) = (/ 1._RP, -1._RP /) real(kind=RP) :: mu, sigma integer :: i,j ! Face coordinate counters integer :: n, m ! Index of G_xx integer :: side !-------------------------------------------- ! ! Initializations ! --------------- #if defined(SCALAR) mu = 1.0_RP #else mu = dimensionless % mu ! TODO: change for Cahn-Hilliard #endif sigma = self % PenaltyParameter(f) sigma = sigma * mu do side = 1, 2 do j = 0, f % Nf(2) ; do i = 0, f % Nf(1) ! ! ************************************************ ! Jacobian with respect to ∇q: dF/d∇q⁺ and dF/d∇q⁻ ! ************************************************ ! ! ! Definitions ! ----------- associate( Q => f % storage(side) % Q (:,i,j) , & U_x => f % storage(side) % U_x(:,i,j) , & U_y => f % storage(side) % U_y(:,i,j) , & U_z => f % storage(side) % U_z(:,i,j) , & nHat => f % geom % normal(:,i,j) , & dFStar_dq => f % storage(side) % dFStar_dqF(:,:,i,j) , & dF_dGradQ_out => f % storage(side) % dFv_dGradQF(:,:,:,i,j) ) call ViscousJacobian(Q, U_x, U_y, U_z, df_dgradq, dfdq_) ! ! For the outer surface integral ! ****************************** ! ! Construct face point Jacobians ! ------------------------------ dF_dGradQ_out = 0._RP do m = 1, NDIM ; do n = 1, NDIM dF_dGradQ_out(:,:,1) = dF_dGradQ_out(:,:,1) + df_dgradq(:,:,n,m) * f % geom % GradXi (n,i,j) * nHat(m) dF_dGradQ_out(:,:,2) = dF_dGradQ_out(:,:,2) + df_dgradq(:,:,n,m) * f % geom % GradEta (n,i,j) * nHat(m) dF_dGradQ_out(:,:,3) = dF_dGradQ_out(:,:,3) + df_dgradq(:,:,n,m) * f % geom % GradZeta(n,i,j) * nHat(m) end do ; end do ! Multiply by 1/2 (IP scheme) and the jacobian (surface integral) ! --------------------------------------------------------------- dF_dGradQ_out = dF_dGradQ_out * 0.5_RP * f % geom % jacobian(i,j) dFStar_dq = dFStar_dq - 0.5_RP * f % geom % jacobian(i,j) * dot_product( dfdq_, nHat ) ! ! ********************************************* ! Jacobian with respect to q: dF/dq⁺ and dF/dq⁻ ! ********************************************* ! ! ! Penalty contribution (shifts dFStar_dq matrix) ! ---------------------------------------------- do n = 1, NCONS dFStar_dq(n,n) = dFStar_dq(n,n) + SideSign(side) * sigma * f % geom % jacobian(i,j) end do end associate end do ; end do end do end subroutine IP_RiemannSolver_Jacobians #endif ! !/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ! end module EllipticIP