#include "Includes.h" module GenericBoundaryConditionClass use SMConstants use PhysicsStorage use FTValueDictionaryClass, only: FTValueDictionary use VariableConversion, only: GetGradientValues_f use FluidData implicit none ! ! ***************************** ! Default everything to private ! ***************************** ! private ! ! **************** ! Public variables ! **************** ! public NS_BC, C_BC, MU_BC ! ! ****************** ! Public definitions ! ****************** ! public GenericBC_t, GetValueWithDefault, CheckIfBoundaryNameIsContained ! ! **************************** ! Static variables definitions ! **************************** ! enum, bind(C) enumerator :: NONE_BC enumerator :: NS_BC enumerator :: C_BC, MU_BC end enum ! ! **************** ! Class definition ! **************** ! type GenericBC_t logical :: constructed = .false. character(len=LINE_LENGTH) :: bname character(len=LINE_LENGTH) :: BCType integer :: currentEqn = 1 contains procedure :: Destruct => GenericBC_Destruct procedure :: Describe => GenericBC_Describe procedure :: GetPeriodicPair => GenericBC_GetPeriodicPair #ifdef FLOW procedure :: FlowState => GenericBC_FlowState procedure :: FlowGradVars => GenericBC_FlowGradVars procedure :: FlowNeumann => GenericBC_FlowNeumann #endif #ifdef CAHNHILLIARD procedure :: PhaseFieldState => GenericBC_PhaseFieldState procedure :: PhaseFieldNeumann => GenericBC_PhaseFieldNeumann procedure :: ChemPotState => GenericBC_ChemPotState procedure :: ChemPotNeumann => GenericBC_ChemPotNeumann #endif #ifdef SCALAR procedure :: SlrState => GenericBC_SlrState procedure :: SlrGradVars => GenericBC_SlrGradVars procedure :: SlrNeumann => GenericBC_SlrNeumann #endif procedure :: StateForEqn procedure :: GradVarsForEqn procedure :: NeumannForEqn end type GenericBC_t ! ! ******************************************************************* ! Traditionally, constructors are exported with the name of the class ! ******************************************************************* ! interface GenericBC_t module procedure ConstructGenericBC end interface GenericBC_t ! ! ******************* ! Function prototypes ! ******************* ! abstract interface end interface ! ! ======== contains ! ======== ! !///////////////////////////////////////////////////////// ! ! Class constructor ! ----------------- ! !///////////////////////////////////////////////////////// ! function ConstructGenericBC() ! ! ************************************************************ ! This is a default constructor (i.e. without input arguments) ! ************************************************************ ! implicit none type(GenericBC_t) :: ConstructGenericBC print*, "Default Boundary condition class can not be constructed." errorMessage(STD_OUT) error stop end function ConstructGenericBC ! !///////////////////////////////////////////////////////// ! ! Class destructors ! ----------------- ! !///////////////////////////////////////////////////////// ! subroutine GenericBC_Destruct(self) implicit none class(GenericBC_t) :: self if (.not. self % constructed) return end subroutine GenericBC_Destruct ! !////////////////////////////////////////////////////////////////////////////////// ! ! This subroutine allows to call the State/Neumann for generic equations ! ---------------------------------------------------------------------- ! !////////////////////////////////////////////////////////////////////////////////// ! subroutine StateForEqn(self, nEqn, x, t, nHat, Q) implicit none class(GenericBC_t), intent(in) :: self integer, intent(in) :: nEqn real(kind=RP), intent(in) :: x(NDIM) real(kind=RP), intent(in) :: t real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(inout) :: Q(nEqn) #ifdef SCALAR call self % SlrState(x, t, nHat, Q) #elif !defined(CAHNHILLIARD) call self % FlowState(x, t, nHat, Q) #else select case(self % currentEqn) #ifdef FLOW case(NS_BC) call self % FlowState(x, t, nHat, Q) #endif case(C_BC) call self % PhaseFieldState(x, t, nHat, Q) case(MU_BC) call self % ChemPotState(x, t, nHat, Q) end select #endif end subroutine StateForEqn subroutine GradVarsForEqn(self, nEqn, nGradEqn, x, t, nHat, Q, U, GetGradients) implicit none class(GenericBC_t), intent(in) :: self integer, intent(in) :: nEqn integer, intent(in) :: nGradEqn real(kind=RP), intent(in) :: x(NDIM) real(kind=RP), intent(in) :: t real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(in) :: Q(nEqn) real(kind=RP), intent(inout) :: U(nGradEqn) procedure(GetGradientValues_f) :: GetGradients #ifdef SCALAR call self % SlrGradvars(x, t, nHat, Q, U, GetGradients) #elif !defined(CAHNHILLIARD) call self % FlowGradVars(x, t, nHat, Q, U, GetGradients) #else select case(self % currentEqn) #ifdef FLOW case(NS_BC) call self % FlowGradVars(x, t, nHat, Q, U, GetGradients) #endif case(C_BC) call self % PhaseFieldState(x, t, nHat, U) case(MU_BC) call self % ChemPotState(x, t, nHat, U) end select #endif end subroutine GradVarsForEqn subroutine NeumannForEqn(self, nEqn, nGradEqn, x, t, nHat, Q, U_x, U_y, U_z, flux) implicit none class(GenericBC_t), intent(in) :: self integer, intent(in) :: nEqn integer, intent(in) :: nGradEqn real(kind=RP), intent(in) :: x(NDIM) real(kind=RP), intent(in) :: t real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(in) :: Q(nEqn) real(kind=RP), intent(in) :: U_x(nGradEqn) real(kind=RP), intent(in) :: U_y(nGradEqn) real(kind=RP), intent(in) :: U_z(nGradEqn) real(kind=RP), intent(inout) :: flux(nEqn) #ifdef CAHNHILLIARD select case(self % currentEqn) case(C_BC) call self % PhaseFieldNeumann(x, t, nHat, Q, U_x, U_y, U_z, flux) case(MU_BC) call self % ChemPotNeumann(x, t, nHat, Q, U_x, U_y, U_z, flux) case default print*, "Unexpected equation choice" errorMessage(STD_OUT) error stop end select #else print*, "This function is only supported for Cahn-Hilliard" errorMessage(STD_OUT) error stop #endif end subroutine NeumannForEqn ! !//////////////////////////////////////////////////////////////////////////// ! ! Subroutines for Navier--Stokes equations ! ---------------------------------------- ! !//////////////////////////////////////////////////////////////////////////// ! #ifdef FLOW subroutine GenericBC_FlowState(self, x, t, nHat, Q) implicit none class(GenericBC_t), intent(in) :: self real(kind=RP), intent(in) :: x(NDIM) real(kind=RP), intent(in) :: t real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(inout) :: Q(NCONS) end subroutine GenericBC_FlowState subroutine GenericBC_FlowGradVars(self, x, t, nHat, Q, U, GetGradients) implicit none class(GenericBC_t), intent(in) :: self real(kind=RP), intent(in) :: x(NDIM) real(kind=RP), intent(in) :: t real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(in) :: Q(NCONS) real(kind=RP), intent(inout) :: U(NGRAD) procedure(GetGradientValues_f) :: GetGradients ! ! --------------- ! Local variables ! --------------- ! real(kind=RP) :: Q_aux(NCONS), U_aux(NGRAD), rho Q_aux = Q U_aux = U call self % FlowState(x,t,nHat,Q_aux) #ifdef MULTIPHASE ! ! Set the chemical potential to the interior ! ------------------------------------------ rho = dimensionless % rho(1) * Q_aux(IMC) + dimensionless % rho(2) * (1.0_RP-Q_aux(IMC)) rho = min(max(rho, dimensionless % rho_min),dimensionless % rho_max) call GetGradients(NCONS,NGRAD,Q_aux, U_aux, rho) U_aux(IGMU) = U(IGMU) #else call GetGradients(NCONS,NGRAD,Q_aux, U_aux) #endif U = 0.5_RP * (U_aux + U) end subroutine GenericBC_FlowGradVars subroutine GenericBC_FlowNeumann(self, x, t, nHat, Q, U_x, U_y, U_z, flux) implicit none class(GenericBC_t), intent(in) :: self real(kind=RP), intent(in) :: x(NDIM) real(kind=RP), intent(in) :: t real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(in) :: Q(NCONS) real(kind=RP), intent(in) :: U_x(NGRAD) real(kind=RP), intent(in) :: U_y(NGRAD) real(kind=RP), intent(in) :: U_z(NGRAD) real(kind=RP), intent(inout) :: flux(NCONS) end subroutine GenericBC_FlowNeumann #endif ! !//////////////////////////////////////////////////////////////////////////// ! ! Subroutines for Cahn--Hilliard ! ------------------------------ ! !//////////////////////////////////////////////////////////////////////////// ! #ifdef CAHNHILLIARD subroutine GenericBC_PhaseFieldState(self, x, t, nHat, Q) implicit none class(GenericBC_t), intent(in) :: self real(kind=RP), intent(in) :: x(NDIM) real(kind=RP), intent(in) :: t real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(inout) :: Q(NCOMP) end subroutine GenericBC_PhaseFieldState subroutine GenericBC_PhaseFieldNeumann(self, x, t, nHat, Q, U_x, U_y, U_z, flux) implicit none class(GenericBC_t), intent(in) :: self real(kind=RP), intent(in) :: x(NDIM) real(kind=RP), intent(in) :: t real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(in) :: Q(NCOMP) real(kind=RP), intent(in) :: U_x(NCOMP) real(kind=RP), intent(in) :: U_y(NCOMP) real(kind=RP), intent(in) :: U_z(NCOMP) real(kind=RP), intent(inout) :: flux(NCOMP) end subroutine GenericBC_PhaseFieldNeumann subroutine GenericBC_ChemPotState(self, x, t, nHat, Q) implicit none class(GenericBC_t), intent(in) :: self real(kind=RP), intent(in) :: x(NDIM) real(kind=RP), intent(in) :: t real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(inout) :: Q(NCOMP) end subroutine GenericBC_ChemPotState subroutine GenericBC_ChemPotNeumann(self, x, t, nHat, Q, U_x, U_y, U_z, flux) implicit none class(GenericBC_t), intent(in) :: self real(kind=RP), intent(in) :: x(NDIM) real(kind=RP), intent(in) :: t real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(in) :: Q(NCOMP) real(kind=RP), intent(in) :: U_x(NCOMP) real(kind=RP), intent(in) :: U_y(NCOMP) real(kind=RP), intent(in) :: U_z(NCOMP) real(kind=RP), intent(inout) :: flux(NCOMP) end subroutine GenericBC_ChemPotNeumann #endif subroutine GenericBC_Describe(self) implicit none class(GenericBC_t), intent(in) :: self end subroutine GenericBC_Describe subroutine GenericBC_GetPeriodicPair(self, bname) ! ! ***************************************** ! Only for periodic BCs, empty for the rest ! ***************************************** ! implicit none class(GenericBC_t), intent(in) :: self character(len=*), intent(out) :: bname end subroutine GenericBC_GetPeriodicPair ! ! !//////////////////////////////////////////////////////////////////////////// ! ! Subroutines for Scalar ! ------------------------------ ! !//////////////////////////////////////////////////////////////////////////// ! #ifdef SCALAR subroutine GenericBC_SlrState(self, x, t, nHat, Q) implicit none class(GenericBC_t), intent(in) :: self real(kind=RP), intent(in) :: x(NDIM) real(kind=RP), intent(in) :: t real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(inout) :: Q(NCONS) end subroutine GenericBC_SlrState subroutine GenericBC_SlrGradVars(self, x, t, nHat, Q, U, GetGradients) implicit none class(GenericBC_t), intent(in) :: self real(kind=RP), intent(in) :: x(NDIM) real(kind=RP), intent(in) :: t real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(in) :: Q(NCONS) real(kind=RP), intent(inout) :: U(NGRAD) procedure(GetGradientValues_f) :: GetGradients ! ! --------------- ! Local variables ! --------------- ! real(kind=RP) :: Q_aux(NCONS), U_aux(NGRAD), rho Q_aux = Q U_aux = U call self % SlrState(x,t,nHat,Q_aux) U = 0.5_RP * (U_aux + U) end subroutine GenericBC_SlrGradVars subroutine GenericBC_SlrNeumann(self, x, t, nHat, Q, U_x, U_y, U_z, flux) implicit none class(GenericBC_t), intent(in) :: self real(kind=RP), intent(in) :: x(NDIM) real(kind=RP), intent(in) :: t real(kind=RP), intent(in) :: nHat(NDIM) real(kind=RP), intent(in) :: Q(NCONS) real(kind=RP), intent(in) :: U_x(NGRAD) real(kind=RP), intent(in) :: U_y(NGRAD) real(kind=RP), intent(in) :: U_z(NGRAD) real(kind=RP), intent(inout) :: flux(NCONS) end subroutine GenericBC_SlrNeumann #endif !//////////////////////////////////////////////////////////////////////////// ! ! Some utilities ! -------------- ! !//////////////////////////////////////////////////////////////////////////// ! subroutine GetValueWithDefault(controlVariables, keyword, default, val) implicit none type(FTValueDictionary), intent(in) :: controlVariables character(len=*), intent(in) :: keyword real(kind=RP), intent(in) :: default real(kind=RP), intent(out) :: val ! ! --------------- ! Local variables ! --------------- ! if ( controlVariables % ContainsKey(trim(keyword)) ) then val = controlVariables % DoublePrecisionValueForKey(trim(keyword)) else val = default end if end subroutine GetValueWithDefault logical function CheckIfBoundaryNameIsContained(line, bname) ! ! ********************************************************************** ! We will allow several boundary names defined within a single region. ! They should be separated by two underscores (e.g. bname1__bname2) ! ********************************************************************** ! implicit none character(len=*), intent(in) :: line character(len=*), intent(in) :: bname ! ! --------------- ! Local variables ! --------------- ! integer :: pos1, pos2 character(len=LINE_LENGTH) :: str, curName logical :: found str = "#define boundary" ! ! Exit if not a #define boundary sentinel ! --------------------------------------- if ( line(1:len_trim(str)) .ne. trim(str) ) then CheckIfBoundaryNameIsContained = .false. return end if ! ! Get only the boundary names ! --------------------------- str = adjustl(line(len_trim(str)+1:len_trim(line))) ! ! Exit if empty ! ------------- if (len_trim(str) .eq. 0) then CheckIfBoundaryNameIsContained = .false. return end if ! ! Check the entries ! ----------------- pos1 = 1 pos2 = len_trim(str) found = .false. do while(pos2 .ne. 0) pos2 = index(str(pos1:len_trim(str)),"__") + pos1 - 1 if ( pos2 .eq. pos1-1 ) then ! ! Last iteration ! -------------- curName = str(pos1:len_trim(str)) pos2 = 0 else curName = str(pos1:pos2-1) end if if ( trim(curName) .eq. trim(bname) ) then found = .true. CheckIfBoundaryNameIsContained = .true. return else pos1 = pos2+2 end if end do CheckIfBoundarynameIsContained = .false. end function CheckIfBoundaryNameIsContained end module GenericBoundaryConditionClass