bounded_ext_derivation_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 (bounded_ext_derivation_class) bounded_ext_derivation_procedures
!! author: Stefan Mijin 
!! 
!! Contains module procedures associated with the bounded extrapolation derivation class

implicit none

!-----------------------------------------------------------------------------------------------------------------------------------
contains
!-----------------------------------------------------------------------------------------------------------------------------------
module subroutine initBExt(this,partitionObj,procRank,extrapolationObj,fixedLowerBound,fixedUpperBound,&
                        expectLowerBoundVar,expectUpperBoundVar)
    !! Initialize bounded extrapolation derivation object

    class(BoundedExtDerivation)   ,intent(inout)  :: this
    type(Partition)               ,intent(in)     :: partitionObj !! Partition object used to determine local processor grid chunk
    integer(ik)                   ,intent(in)     :: procRank !! Current processor rank
    class(Extrapolation)          ,intent(in)     :: extrapolationObj !! Extrapolation object used to calculate the extrapolated values
    real(rk) ,optional            ,intent(in)     :: fixedLowerBound !! Optional fixed lower bound value
    real(rk) ,optional            ,intent(in)     :: fixedUpperBound !! Optional fixed upper bound value
    logical  ,optional            ,intent(in)     :: expectLowerBoundVar !! True if lower bound variable is expected. Defaults to false. 
    logical  ,optional            ,intent(in)     :: expectUpperBoundVar !! True if lower bound variable is expected. Defaults to false. 

    logical :: sVars

    integer(ik) :: minX ,maxX, inferredGridSize

    if (assertions) call assert(partitionObj%isDefined(),"Partition passed to initBExt not defined")

    if (present(fixedLowerBound)) this%fixedLowerBound = fixedLowerBound
    if (present(fixedUpperBound)) this%fixedUpperBound = fixedUpperBound

    if (allocated(this%fixedLowerBound) .and. (allocated(this%fixedUpperBound))) &
    call assert(abs(this%fixedUpperBound)>abs(this%fixedLowerBound),&
    "Fixed upper bound passed to initBExt greater than passed lower bound")

    this%expectLowerBoundVar = .false. 
    this%expectUpperBoundVar = .false. 

    if (present(expectLowerBoundVar)) this%expectLowerBoundVar = expectLowerBoundVar
    if (present(expectUpperBoundVar)) this%expectUpperBoundVar = expectUpperBoundVar

    allocate(this%extrapolationObj,source=extrapolationObj)

    call this%makeDefined()

end subroutine initBExt  
!-----------------------------------------------------------------------------------------------------------------------------------
module function calculateBExt(this,inputArray,indices) result(output)

    class(BoundedExtDerivation)         ,intent(inout)    :: this 
    type(RealArray)       ,dimension(:)  ,intent(in)    :: inputArray 
    integer(ik)           ,dimension(:)  ,intent(in)    :: indices
    real(rk) ,allocatable ,dimension(:)                 :: output

    integer(ik) :: expectedNumIndices

    real(rk) :: lowerBound ,upperBound

    logical :: applyLBound ,applyUBound

    if (assertions) call assertPure(this%isDefined(),"calculateBExt called on undefined derivation object")

    expectedNumIndices = 1 
    if (this%expectLowerBoundVar) expectedNumIndices = expectedNumIndices + 1
    if (this%expectUpperBoundVar) expectedNumIndices = expectedNumIndices + 1

    if (assertions) then 

        call assertPure(size(indices) == expectedNumIndices,"Unexpected number of indices passed to calculateBExt")
        call assertPure(all(indices>0),"indices passed to calculateBExt out of bounds - lower")
        call assertPure(all(indices<=size(inputArray)),"indices passed to calculateBExt out of bounds - upper")

    end if

    allocate(output(1))
    output(1) = 0
    if (this%extrapolationObj%hasBoundary()) then
        !Perform initial linear extrapolation
        output(1) = this%extrapolationObj%extrapolate(inputArray(indices(1))%entry)
        !Check for bounds 
        applyLBound = allocated(this%fixedLowerBound) .or. this%expectLowerBoundVar
        applyUBound = allocated(this%fixedUpperBound) .or. this%expectUpperBoundVar

        if (applyLBound) then 
            if (this%expectLowerBoundVar) then 
                if (size(inputArray(indices(2))%entry) == 1) then 
                    lowerBound = inputArray(indices(2))%entry(1)
                else
                    lowerBound = this%extrapolationObj%extrapolate(inputArray(indices(2))%entry)
                end if
            else
                lowerBound = this%fixedLowerBound
            end if
        end if

        if (applyUBound) then 
            if (this%expectUpperBoundVar) then 
                if (size(inputArray(indices(expectedNumIndices))%entry) == 1) then 
                    upperBound = inputArray(indices(expectedNumIndices))%entry(1)
                else
                    upperBound = this%extrapolationObj%extrapolate(inputArray(indices(expectedNumIndices))%entry)
                end if
            else
                upperBound = this%fixedUpperBound
            end if
        end if

        if (applyLBound .and. applyUBound) &
        call assertPure(abs(lowerBound) < abs(upperBound),"Lower bound not smaller than upper bound in calculateBExt")
        
        if (this%extrapolationObj%isLeftBoundary()) then 
            if (applyLBound) output(1) = min(output(1),-abs(lowerBound))
            if (applyUBound) output(1) = max(output(1),-abs(upperBound))

        else
            if (applyLBound) output(1) = max(output(1),abs(lowerBound))
            if (applyUBound) output(1) = min(output(1),abs(upperBound))
        end if
    end if
    
end function calculateBExt
!-----------------------------------------------------------------------------------------------------------------------------------
!-----------------------------------------------------------------------------------------------------------------------------------
end submodule bounded_ext_derivation_procedures
!-----------------------------------------------------------------------------------------------------------------------------------