geometry_procedures.f90 Source File


Source Code

!-----------------------------------------------------------------------------------------------------------------------------------
! This file is part of ReMKiT1D.
!
! ReMKiT1D 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 3 of the License, or (at your option) any later version.
!
! ReMKiT1D 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 ReMKiT1D. If not, see <https://www.gnu.org/licenses/>. 
!
! Copyright 2023 United Kingdom Atomic Energy Authority (stefan.mijin@ukaea.uk)
!-----------------------------------------------------------------------------------------------------------------------------------
submodule (geometry_class) geometry_procedures
    !! author: Stefan Mijin 
    !! 
    !! Contains module procedures associated with the geometry class

implicit none

!-----------------------------------------------------------------------------------------------------------------------------------
contains
!-----------------------------------------------------------------------------------------------------------------------------------
pure module subroutine initGeometry(this,cellWidths,jLeft,jRight,periodicGrid) 
    !! Geometry initialization routine

    class(Geometry)           ,intent(inout)  :: this
    real(rk)    ,dimension(:) ,intent(in)     :: cellWidths !! Spatial cell widths
    real(rk)    ,dimension(:) ,intent(in)     :: jLeft !! Left face jacobian values
    real(rk)    ,dimension(:) ,intent(in)     :: jRight !! Right face jacobian values
    logical     ,optional     ,intent(in)     :: periodicGrid !! Set to true if the grid is periodic

    integer(ik) :: i

    logical :: periodic

    if (assertions .or. assertionLvl >= 0) then
        call assertPure((size(cellWidths) == size(jLeft)) .and. (size(jLeft) == size(jRight)),&
        "Cell widths and face jacobians passed to geometry initializations must all be of same size")
    end if

    this%cellWidths = cellWidths 
    this%jacobianLeft = jLeft 
    this%jacobianRight = jRight 
    this%jacobianCentre = (jLeft + jRight)/2 

    periodic = .false. 
    if (present(periodicGrid)) periodic = periodicGrid

   
    allocate(this%linInterp(0:size(cellWidths)))
    
    this%linInterp = 0

    do i = 1,size(cellWidths)-1
        this%linInterp(i) = cellWidths(i)/(cellWidths(i)+cellWidths(i+1)) 
    end do 

    this%linInterp(size(cellWidths)) = real(1.0d0,kind=rk) !Handle non-periodic interpolation without explicit checks

    if (periodic) then 
        this%linInterp(size(cellWidths)) = cellWidths(size(cellWidths))/(cellWidths(size(cellWidths))+cellWidths(1)) 
        this%linInterp(0) = this%linInterp(size(cellWidths))
    end if

    this%periodicGrid = periodic 
    
    call this%makeDefined()
    
end subroutine initGeometry
!-----------------------------------------------------------------------------------------------------------------------------------
pure module function getCellWidths (this,dualGrid,extendedBoundaryCells) result(dx)
    !! Getter for cellWidths, if dualGrid is true returns dual grid values based off of cellWidths. If extendedBoundaryCells is
    !! true will extend dual grid cells at boundaries to the boundaries themselves if not periodic (defaults to true)

    class(Geometry)                       ,intent(in) :: this
    logical ,optional                     ,intent(in) :: dualGrid
    logical ,optional                     ,intent(in) :: extendedBoundaryCells
    real(rk)   ,allocatable ,dimension(:)             :: dx

    logical :: dGrid,exBoundaryCells

    if (assertions) call assertPure(this%isDefined(),"getCellWidths called from undefined geometry object")

    dGrid = .false.
    if (present(dualGrid)) dGrid = dualGrid

    exBoundaryCells = .true.
    if (present(extendedBoundaryCells)) exBoundaryCells = extendedBoundaryCells

    dx = this%cellWidths

    if (dGrid) then 
        dx(1:size(dx)-1) = (this%cellWidths(1:size(dx)-1) + this%cellWidths(2:size(dx)))/2
        if (this%periodicGrid) then 
            dx(size(dx)) = (this%cellWidths(1) + this%cellWidths(size(dx)))/2
        else if (exBoundaryCells) then
            dx(1) = this%cellWidths(1) + this%cellWidths(2)/2
            dx(size(dx)-1) = this%cellWidths(size(dx)) + this%cellWidths(size(dx)-1)/2
            dx(size(dx)) = 10*epsilon(dx) ! Set to this to avoid divide by 0 errors
        end if
    end if
end function getCellWidths
!-----------------------------------------------------------------------------------------------------------------------------------
pure module function getJacobianLeft (this,dualGrid) result(jLeft)
    !! Getter for jacobianLeft, if dualGrid is true returns dual grid values 

    class(Geometry)                       ,intent(in) :: this
    logical ,optional                     ,intent(in) :: dualGrid
    real(rk)   ,allocatable ,dimension(:)             :: jLeft
    logical :: dGrid

    if (assertions) call assertPure(this%isDefined(),"getJacobianLeft called from undefined geometry object")

    dGrid = .false.
    if (present(dualGrid)) dGrid = dualGrid

    jLeft = this%jacobianLeft

    if (dGrid) then 
        jLeft = this%jacobianCentre
        if (.not. this%periodicGrid) then 
            jLeft(1) = this%jacobianLeft(1)
            jLeft(size(jLeft)) = this%jacobianRight(size(jLeft))
        end if
    end if

end function getJacobianLeft
!-----------------------------------------------------------------------------------------------------------------------------------
pure module function getJacobianRight (this,dualGrid,extendedBoundaryCells) result(jRight)
    !! Getter for jacobianRight, if dualGrid is true returns dual grid values 

    class(Geometry)                       ,intent(in) :: this
    logical ,optional                     ,intent(in) :: dualGrid
    logical ,optional                     ,intent(in) :: extendedBoundaryCells
    real(rk)   ,allocatable ,dimension(:)             :: jRight
    logical :: dGrid, exBoundaryCells

    if (assertions) call assertPure(this%isDefined(),"getJacobianRight called from undefined geometry object")

    dGrid = .false.
    if (present(dualGrid)) dGrid = dualGrid

    exBoundaryCells = .true.
    if (present(extendedBoundaryCells)) exBoundaryCells = extendedBoundaryCells

    jRight = this%jacobianRight

    if (dGrid) then 

        jRight(1:size(jRight)-1) = this%jacobianCentre(2:size(jRight))

        if (this%periodicGrid) then 
            jRight(size(jRight)) = this%jacobianCentre(1)
        else if (exBoundaryCells) then
            jRight(size(jRight)-1) = this%jacobianRight(size(jRight))
            jRight(size(jRight)) = this%jacobianRight(size(jRight))
        end if
    end if

end function getJacobianRight
!-----------------------------------------------------------------------------------------------------------------------------------
pure module function getJacobianCentre (this,dualGrid,extendedBoundaryCells) result(jCentre)
    !! Getter for jacobianCentre, if dualGrid is true returns dual grid values 

    class(Geometry)                       ,intent(in) :: this
    logical ,optional                     ,intent(in) :: dualGrid
    logical ,optional                     ,intent(in) :: extendedBoundaryCells
    real(rk)   ,allocatable ,dimension(:)             :: jCentre
    logical :: dGrid ,exBoundaryCells

    if (assertions) call assertPure(this%isDefined(),"getJacobianCentre called from undefined geometry object")

    dGrid = .false.
    if (present(dualGrid)) dGrid = dualGrid

    exBoundaryCells = .true.
    if (present(extendedBoundaryCells)) exBoundaryCells = extendedBoundaryCells

    jCentre = this%jacobianCentre

    if (dGrid) then 

        !The straightforward thing here is to take jCentre on the dual grid to be jRight on the original grid. However, since 
        !jCentre is used to get the (dual) cell volume as jCentre*dx, this would not be accurate for the dual grid, since the 
        !dual cell cross-section is in general two connected trapezoids. Hence the following is done to make sure that the dual cell volume is correct.
        !NOTE: In the non-periodic case, the first and second to last dual cells extend to the actual system boundaries so that the dual grid 
        !covers the original grid 

        jCentre(1:size(jCentre)-1) =  this%jacobianRight(1:size(jCentre)-1)/2 &
                                    + (this%jacobianCentre(1:size(jCentre)-1)*this%cellWidths(1:size(jCentre)-1) &
                                    + this%jacobianCentre(2:size(jCentre))*this%cellWidths(2:size(jCentre)))&
                                    / (2*(this%cellWidths(1:size(jCentre)-1)+this%cellWidths(2:size(jCentre))))
        

        if (this%periodicGrid) then 
            jCentre(size(jCentre)) = this%jacobianRight(size(jCentre))/2 &
                                    + (this%jacobianCentre(size(jCentre))*this%cellWidths(size(jCentre)) &
                                    + this%jacobianCentre(1)*this%cellWidths(1))&
                                    / (2*(this%cellWidths(size(jCentre))+this%cellWidths(1)))
        else if (exBoundaryCells) then

            jCentre(1) = this%cellWidths(1)*this%jacobianCentre(1) &
                        + (this%jacobianRight(1)+this%jacobianCentre(2))*this%cellWidths(2)/4
            jCentre(1) = jCentre(1)/(this%cellWidths(1)+this%cellWidths(2)/2)

            jCentre(size(jCentre)-1) = this%cellWidths(size(jCentre))*this%jacobianCentre(size(jCentre)) &
                                        + (this%jacobianRight(size(jCentre)-1)+this%jacobianCentre(size(jCentre)-1))&
                                        *this%cellWidths(size(jCentre)-1)/4

            jCentre(size(jCentre)-1) = jCentre(size(jCentre)-1)/(this%cellWidths(size(jCentre))&
                                      +this%cellWidths(size(jCentre)-1)/2)

            jCentre(size(jCentre)) = 10*epsilon(jCentre) ! Set to this to avoid divide by 0 errors

        end if
    end if

end function getJacobianCentre
!-----------------------------------------------------------------------------------------------------------------------------------
pure module function getLinInterp (this,dualGrid) result(linInterp)
    !! Getter for linInterp, if dualGrid is true returns dual grid values (0.5 everywhere)

    class(Geometry)                       ,intent(in) :: this
    logical ,optional                     ,intent(in) :: dualGrid
    real(rk)   ,allocatable ,dimension(:)             :: linInterp
    logical :: dGrid

    if (assertions) call assertPure(this%isDefined(),"getLinInterp called from undefined geometry object")

    dGrid = .false.
    if (present(dualGrid)) dGrid = dualGrid

    linInterp = this%linInterp

    if (dGrid) linInterp = real(0.5d0,kind=rk)

end function getLinInterp
!-----------------------------------------------------------------------------------------------------------------------------------
pure module function isPeriodic (this) result(periodic)
    !! Getter for periodicGrid

    class(Geometry) ,intent(in) :: this
    logical                     :: periodic

    if (assertions) call assertPure(this%isDefined(),"isPeriodic called from undefined geometry object")

    periodic = this%periodicGrid

end function isPeriodic
!-----------------------------------------------------------------------------------------------------------------------------------
end submodule geometry_procedures
!-----------------------------------------------------------------------------------------------------------------------------------