LESModels.f90 Source File


Source Code

#include "Includes.h"
module LESModels
   use SMConstants
   use PhysicsStorage_NS
   use FTValueDictionaryClass
   use Physics_NSKeywordsModule
   use MPI_Process_Info
   use Headers
   use Utilities                 , only: toLower
   use FluidData_NS
   use VariableConversion_NS     , only: getVelocityGradients, getTemperatureGradient
   implicit none

   private
   public LESModel, InitializeLESModel, Smagorinsky_t
   
!  Keywords
!  --------
   character(len=*), parameter   :: LESIntensityKey = "les model intensity"
   character(len=*), parameter   :: WallModelKey    = "wall model"
   
!  Model parameters
!  ----------------
   real(kind=RP)   , parameter   :: K_VONKARMAN     = 0.4_RP
   
!  Wall models
!  -----------
   integer         , parameter   :: NO_WALLMODEL       = 0
   integer         , parameter   :: LINEAR_WALLMODEL   = 1
   
   type LESModel_t
      logical  :: active
      logical  :: requiresWallDistances = .FALSE.
      integer  :: WallModel
      contains
         procedure            :: Initialize         => LESModel_Initialize
         procedure, private   :: ComputeWallEffect  => LESModel_ComputeWallEffect
         procedure            :: ComputeViscosity   => LESModel_ComputeViscosity
         procedure            :: Describe           => LESModel_Describe
   end type LESModel_t

   type, extends(LESModel_t)  :: Smagorinsky_t
      real(kind=RP)  :: CS
      contains
         procedure          :: Initialize         => Smagorinsky_Initialize
         procedure          :: Describe           => Smagorinsky_Describe
         procedure          :: ComputeViscosity   => Smagorinsky_ComputeViscosity
   end type Smagorinsky_t

   type, extends(LESModel_t)  :: WALE_t
      real(kind=RP)  :: Cw
      contains
         procedure          :: Initialize         => WALE_Initialize
         procedure          :: Describe           => WALE_Describe
         procedure          :: ComputeViscosity   => WALE_ComputeViscosity
   end type WALE_t

   type, extends(LESModel_t)  :: Vreman_t
      real(kind=RP)  :: C
      contains
         procedure          :: Initialize         => Vreman_Initialize
         procedure          :: Describe           => Vreman_Describe
         procedure          :: ComputeViscosity   => Vreman_ComputeViscosity
   end type Vreman_t


   class(LESModel_t), allocatable   :: LESModel

   contains
      subroutine InitializeLESModel(model, controlVariables)
         implicit none
         class(LESModel_t), allocatable        :: model
         class(FTValueDictionary),  intent(in) :: controlVariables
!
!        ---------------
!        Local variables         
!        ---------------
!
         character(len=LINE_LENGTH)    :: modelName

!
!        Select LES model
!        ----------------
         if ( controlVariables % containsKey(LESMODEL_KEY) ) then
            modelName = controlVariables % stringValueForKey(LESMODEL_KEY, LINE_LENGTH)
            call toLower(modelName)

            select case (trim(modelName))
            case ("none")
               if (.not. allocated(model)) allocate(LESModel_t     :: model)

            case ("smagorinsky")
               if (.not. allocated(model)) allocate(Smagorinsky_t  :: model)

            case ("wale")
               if (.not. allocated(model)) allocate(WALE_t  :: model)

            case ("vreman")
               if (.not. allocated(model)) allocate(Vreman_t  :: model)

            case default
               write(STD_OUT,'(A,A,A)') "LES Model ",trim(modelName), " is not implemented."
               print*, "Available options are:"
               print*, "   * None (default)"
               print*, "   * Smagorinsky"
               print*, "   * Wale"
               print*, "   * Vreman"
               errorMessage(STD_OUT)
               error stop

            end select
   
         else
            if (.not. allocated(model)) allocate(LESModel_t  :: model)

         end if

         call model % Initialize(controlVariables)
         
!        Select wall model
!        -----------------
         if ( controlVariables % containsKey(WallModelKey) ) then
            modelName = controlVariables % stringValueForKey(WallModelKey, LINE_LENGTH)
            call toLower(modelName)

            select case (trim(modelName))
            case ("none")
               model % WallModel = NO_WALLMODEL
               model % requiresWallDistances = .true.

            case ("linear")
               model % WallModel             = LINEAR_WALLMODEL
               model % requiresWallDistances = .true.

            case ("Wale")
               model % WallModel = NO_WALLMODEL
               model % requiresWallDistances = .true.

            case ("Vreman")
               model % WallModel = NO_WALLMODEL
               model % requiresWallDistances = .true.

            case default
               write(STD_OUT,'(A,A,A)') "Wall model ",trim(modelName), " is not implemented."
               print*, "Available options are:"
               print*, "   * Linear"
               print*, "   * Wale"
               print*, "   * Vreman"
               print*, "   * None (default)"
               errorMessage(STD_OUT)
               error stop

            end select
            
         else
            !model % WallModel = LINEAR_WALLMODEL
            model % WallModel = NO_WALLMODEL
         end if
         
!        Describe
!        --------
         call model % Describe
         
      end subroutine InitializeLESModel
!
!/////////////////////////////////////////////////////////////////////////////////////////
!
!           Template procedures
!           -------------------
!
!/////////////////////////////////////////////////////////////////////////////////////////
!
      subroutine LESModel_Initialize(self, controlVariables)
         implicit none
         class(LESModel_t)                     :: self
         class(FTValueDictionary),  intent(in) :: controlVariables

         self % active                = .false.

      end subroutine LESModel_Initialize

      pure real(kind=RP) function LESModel_ComputeWallEffect (self,LS,dWall)
         implicit none
         class(LESModel_t), intent(in) :: self
         real(kind=RP)    , intent(in) :: LS
         real(kind=RP)    , intent(in) :: dWall
         
         select case (self % WallModel)
            case (LINEAR_WALLMODEL)
               LESModel_ComputeWallEffect = min(LS, dWall * K_VONKARMAN)
            case (NO_WALLMODEL)
               LESModel_ComputeWallEffect = LS
               ! LS is left unmodified if no wall model is selected
         end select
         
      end function LESModel_ComputeWallEffect

      pure subroutine LESModel_ComputeViscosity (this, delta, dWall, Q, Q_x, Q_y, Q_z, mu)
         implicit none
         !-arguments---------------------------------------------
         class(LESModel_t), intent(in)    :: this
         real(kind=RP), intent(in)           :: delta
         real(kind=RP), intent(in)           :: dWall
         real(kind=RP), intent(in)           :: Q(NCONS)
         real(kind=RP), intent(in)           :: Q_x(NGRAD)
         real(kind=RP), intent(in)           :: Q_y(NGRAD)
         real(kind=RP), intent(in)           :: Q_z(NGRAD)
         real(kind=RP), intent(out)          :: mu

      end subroutine LESModel_ComputeViscosity
      
      subroutine LESModel_Describe(self)
         implicit none
         class(LESModel_t),   intent(in)  :: self


      end subroutine
!
!//////////////////////////////////////////////////////////////////////////////////////
!
!           Basic Smagorinsky model
!           -----------------------
!
!//////////////////////////////////////////////////////////////////////////////////////
!
      subroutine Smagorinsky_Initialize(self, controlVariables)
         implicit none
         class(Smagorinsky_t)                     :: self
         class(FTValueDictionary),  intent(in) :: controlVariables
!
!        ---------------
!        Local variables
!        ---------------
!
         self % active                = .true.

         if ( controlVariables % containsKey(LESIntensityKey) ) then
            self % CS = controlVariables % doublePrecisionValueForKey(LESIntensityKey)

         else
            self % CS = 0.2_RP      

         end if

      end subroutine Smagorinsky_Initialize
!
!///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
!
      pure subroutine Smagorinsky_ComputeViscosity (this, delta, dWall, Q, Q_x, Q_y, Q_z, mu)
         implicit none
         !-arguments---------------------------------------------
         class(Smagorinsky_t), intent(in)    :: this
         real(kind=RP), intent(in)           :: delta
         real(kind=RP), intent(in)           :: dWall
         real(kind=RP), intent(in)           :: Q(NCONS)
         real(kind=RP), intent(in)           :: Q_x(NGRAD)
         real(kind=RP), intent(in)           :: Q_y(NGRAD)
         real(kind=RP), intent(in)           :: Q_z(NGRAD)
         real(kind=RP), intent(out)          :: mu
         !-local-variables---------------------------------------
         real(kind=RP)  :: S(NDIM, NDIM)
         real(kind=RP)  :: normS, kappa, LS
         real(kind=RP)  :: U_x(NDIM)
         real(kind=RP)  :: U_y(NDIM)
         real(kind=RP)  :: U_z(NDIM)
         !-------------------------------------------------------
         
         call getVelocityGradients(Q,Q_x,Q_y,Q_z,U_x,U_y,U_z)
!
!        Compute symmetric part of the deformation tensor
!        ------------------------------------------------
         S(:,1) = U_x(1:3)
         S(:,2) = U_y(1:3)
         S(:,3) = U_z(1:3)
         
         S(1,:) = S(1,:) + U_x(1:3)
         S(2,:) = S(2,:) + U_y(1:3)
         S(3,:) = S(3,:) + U_z(1:3)
         
         S = 0.5_RP * S
!
!        Compute the norm of S
!        --------------------- 
         normS = sqrt( 2.0_RP * sum(S*S) )
!
!        Compute viscosity and thermal conductivity
!        ------------------------------------------
         LS = this % CS * delta
         LS = this % ComputeWallEffect(LS,dWall)
         mu = Q(IRHO) * POW2(LS) * normS
         
      end subroutine Smagorinsky_ComputeViscosity
!
!///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
!
      subroutine Smagorinsky_Describe(self)
         implicit none
         class(Smagorinsky_t),   intent(in)  :: self

         if ( .not. MPI_Process % isRoot ) return

         write(STD_OUT,*)
         call SubSection_Header("LES Model")
         write(STD_OUT,'(30X,A,A30,A)') "->","LES model: ","Smagorinsky"
         write(STD_OUT,'(30X,A,A30,F10.3)') "->","LES model intensity: ", self % CS
         
         select case (self % WallModel)
            case(LINEAR_WALLMODEL)
               write(STD_OUT,'(30X,A,A30,A)') "->","Wall model: ", "linear"
            case(NO_WALLMODEL)
               write(STD_OUT,'(30X,A,A30,A)') "->","Wall model: ", "none"
         end select
         
      end subroutine Smagorinsky_Describe
!
!//////////////////////////////////////////////////////////////////////////////////////
!
!           WALE turbulence model: Wall-Adapting Local Eddy-Viscosity (WALE) Model
!           -----------------------
!            0.55≤Cw≤0.60
!
!//////////////////////////////////////////////////////////////////////////////////////
!
      subroutine WALE_Initialize(self, controlVariables)
         implicit none
         class(WALE_t)                     :: self
         class(FTValueDictionary),  intent(in) :: controlVariables
!
!        ---------------
!        Local variables
!        ---------------
!
         self % active                = .true.

         if ( controlVariables % containsKey(LESIntensityKey) ) then
            self % Cw = controlVariables % doublePrecisionValueForKey(LESIntensityKey)

         else
            self % Cw = 0.325_RP      

         end if

      end subroutine WALE_Initialize

      pure subroutine WALE_ComputeViscosity (this, delta, dWall, Q, Q_x, Q_y, Q_z, mu)
         implicit none
         !-arguments---------------------------------------------
         class(WALE_t), intent(in)    :: this
         real(kind=RP), intent(in)           :: delta
         real(kind=RP), intent(in)           :: dWall
         real(kind=RP), intent(in)           :: Q(NCONS)
         real(kind=RP), intent(in)           :: Q_x(NGRAD)
         real(kind=RP), intent(in)           :: Q_y(NGRAD)
         real(kind=RP), intent(in)           :: Q_z(NGRAD)
         real(kind=RP), intent(out)          :: mu
         !-local-variables---------------------------------------
         real(kind=RP)  :: S(NDIM, NDIM)
         real(kind=RP)  :: gradV2(NDIM, NDIM), gradV(NDIM,NDIM)
         real(kind=RP)  :: Sd(NDIM, NDIM)
         real(kind=RP)  :: normS, normSd, divV2, kappa, LS
         real(kind=RP)  :: U_x(NDIM)
         real(kind=RP)  :: U_y(NDIM)
         real(kind=RP)  :: U_z(NDIM)
         integer        :: i,j
         !-------------------------------------------------------
         
         call getVelocityGradients  (Q,Q_x,Q_y,Q_z,U_x,U_y,U_z)

         gradV(1,:) = U_x(1:3)
         gradV(2,:) = U_y(1:3)
         gradV(3,:) = U_z(1:3)
 
         do i = 1, 3 
            do j = 1, 3 
               S(i,j)      = 0.5_RP*(gradV(i,j)+gradV(j,i))
               gradV2(i,j) = 0.5_RP*(gradV(i,j)*gradV(j,i))
            end do  
         end do  
         
         divV2 = gradV2(1,1) + gradV2(2,2) + gradV2(3,3)

         normS =  sum(S*S)

         do i = 1, 3 
            do j = 1, 3 
               Sd(i,j) = 0.5_RP*(gradV2(i,j)+gradV2(j,i))
            end do  
         end do  

         Sd(1,1) = Sd(1,1) - 1.0_RP / 3.0_RP * divV2
         Sd(2,2) = Sd(2,2) - 1.0_RP / 3.0_RP * divV2
         Sd(3,3) = Sd(3,3) - 1.0_RP / 3.0_RP * divV2

         normSd =  sum(Sd*Sd)
         LS = this % Cw * delta
         
         mu = Q(IRHO) * POW2(LS) * (normSd**(3.0_RP / 2.0_RP) / (normS**(5.0_RP / 2.0_RP)+normSd**(5.0_RP / 4.0_RP)))

         if (normS<1.0e-8_RP .and. normSd<1.0e-8_RP) mu=0.0_RP
         
      end subroutine WALE_ComputeViscosity

      subroutine WALE_Describe(self)
         implicit none
         class(WALE_t),   intent(in)  :: self

         if ( .not. MPI_Process % isRoot ) return

         write(STD_OUT,*)
         call SubSection_Header("LES Model")
         write(STD_OUT,'(30X,A,A30,A)') "->","LES model: ","Wale"
         write(STD_OUT,'(30X,A,A30,F10.3)') "->","LES model intensity: ", self % Cw
         
         select case (self % WallModel)
            case(NO_WALLMODEL)
               write(STD_OUT,'(30X,A,A30,A)') "->","Wall model: ", "Wale"
            case(LINEAR_WALLMODEL)
               write(STD_OUT,'(30X,A,A30,A)') "->","Wall model: ", "you do not need a linear model with Wale -> deactivate"
         end select
         
      end subroutine WALE_Describe

!
!//////////////////////////////////////////////////////////////////////////////////////
!
!           Vreman
!           -----------------------
!           C = 0.07 (in typical FVM)
!           C = 0.1 in Alya, also recommended by Vreman for highspeed flows 
!//////////////////////////////////////////////////////////////////////////////////////
!
      subroutine Vreman_Initialize(self, controlVariables)
         implicit none
         class(Vreman_t)                     :: self
         class(FTValueDictionary),  intent(in) :: controlVariables
!
!        ---------------
!        Local variables
!        ---------------
!
         self % active                = .true.

         if ( controlVariables % containsKey(LESIntensityKey) ) then
            self % C = controlVariables % doublePrecisionValueForKey(LESIntensityKey)

         else
            self % C = 0.07_RP      

         end if

      end subroutine Vreman_Initialize

      pure subroutine Vreman_ComputeViscosity (this, delta, dWall, Q, Q_x, Q_y, Q_z, mu)
         implicit none
         !-arguments---------------------------------------------
         class(Vreman_t), intent(in)    :: this
         real(kind=RP), intent(in)           :: delta
         real(kind=RP), intent(in)           :: dWall
         real(kind=RP), intent(in)           :: Q(NCONS)
         real(kind=RP), intent(in)           :: Q_x(NGRAD)
         real(kind=RP), intent(in)           :: Q_y(NGRAD)
         real(kind=RP), intent(in)           :: Q_z(NGRAD)
         real(kind=RP), intent(out)          :: mu
         !-local-variables---------------------------------------
         real(kind=RP)  :: G__ij(NDIM, NDIM)
         real(kind=RP)  :: gradV(NDIM, NDIM)
         real(kind=RP)  :: delta2, alpha, Bbeta, LS
         real(kind=RP)  :: U_x(NDIM)
         real(kind=RP)  :: U_y(NDIM)
         real(kind=RP)  :: U_z(NDIM)
         integer        :: i,j,k
         !-------------------------------------------------------
         
         call getVelocityGradients  (Q,Q_x,Q_y,Q_z,U_x,U_y,U_z)

         delta2 = delta*delta 
         gradV(1,:) = U_x(1:3)
         gradV(2,:) = U_y(1:3)
         gradV(3,:) = U_z(1:3)
         G__ij(:,:) = 0.0_RP

         do i = 1,3
            do j = 1,3
               do k = 1,3
                  G__ij(i,j) = G__ij(i,j) &
                     + (gradV(i,k)*gradV(j,k)*delta2)
               end do
            end do
         end do

         alpha =  sum(gradV*gradV)
         Bbeta = G__ij(1,1) * G__ij(2,2) &
            &  + G__ij(2,2) * G__ij(3,3) &
            &  + G__ij(3,3) * G__ij(1,1) &
            &  - G__ij(1,2) * G__ij(1,2) &
            &  - G__ij(2,3) * G__ij(2,3) &
            &  - G__ij(1,3) * G__ij(1,3)

         if(alpha>1.0e-10_RP) then
            mu = Q(IRHO) * this % C * sqrt (abs(Bbeta)/alpha)
         else 
            mu = 0.0_RP
         end if
         
      end subroutine Vreman_ComputeViscosity

      subroutine Vreman_Describe(self)
         implicit none
         class(Vreman_t),   intent(in)  :: self

         if ( .not. MPI_Process % isRoot ) return

         write(STD_OUT,*)
         call SubSection_Header("LES Model")
         write(STD_OUT,'(30X,A,A30,A)') "->","LES model: ","Vreman"
         write(STD_OUT,'(30X,A,A30,F10.3)') "->","LES model intensity: ", self % C
         
         select case (self % WallModel)
            case(NO_WALLMODEL)
               write(STD_OUT,'(30X,A,A30,A)') "->","Wall model: ", "Vreman"
            case(LINEAR_WALLMODEL)
               write(STD_OUT,'(30X,A,A30,A)') "->","Wall model: ", "you do not need a linear model with Vreman -> deactivate"
         end select
         
      end subroutine Vreman_Describe
end module LESModels