spx_smoothed_kernel_function.f90 Source File


Contents


Source Code

!> author: 左志华
!> date: 2022-07-04
!> version: alpha
!>
!> Smoothed kernel function <br>
!> 光滑核函数
module spx_smoothed_kernel_function

    use spx_kinds, only: rk
    use seakeeping_module, only: pi
    use spx_math, only: r23
    use spx_configuration, only: spc_obj
    use fffc_module, only: terminal_obj
    use spx_env, only: rgn_obj
    implicit none

    !> 光滑核函数
    type smoothed_kernel_function_type
        real(rk) :: selfden     !! 粒子的自身物理量加权系数, 一般用于计算粒子密度
        real(rk) :: hsml        !! 光滑长度
        integer :: scale = 2    !! 光滑长度缩尺比例
        real(rk) :: scale_hsml  !! 缩尺后的光滑长度
        character(:), allocatable :: type   !! 光滑函数类型
        procedure(kernel_fcn), pointer :: kernel => cubic_spline_kernel  !! 光滑核函数句柄
        real(rk), private :: factor         !! 核函数常量
    contains
        procedure :: init
    end type smoothed_kernel_function_type

    type(smoothed_kernel_function_type) :: skf_obj  !! 光滑核函数对象

    abstract interface
        !> Kernel function <br>
        !> 光滑核函数
        pure subroutine kernel_fcn(skf, r, dx, w, dwdx)
            import :: rk, smoothed_kernel_function_type
            class(smoothed_kernel_function_type), intent(in) :: skf  !! Smoothed kernel function <br>
                                                                !! 光滑核函数
            real(rk), intent(in) :: r                   !! Euclidean distance between two points <br>
                                                        !! 欧氏距离
            real(rk), intent(in) :: dx(2)               !! dimensional distance between two points <br>
                                                        !! 对应坐标轴距离
            real(rk), intent(out) :: w                  !! kernel value <br>
                                                        !! 核函数
            real(rk), intent(out) :: dwdx(2)            !! derivative of kernel value <br>
                                                        !! 核函数导数
        end subroutine kernel_fcn
    end interface

contains

    !> 建立光滑核函数句柄
    subroutine init(self)
        class(smoothed_kernel_function_type), intent(inout) :: self
        real(rk) :: hv(2)

        self%hsml = rgn_obj%hsml
        select case (spc_obj%smoothed_kernel_function)
        case ('cubic-spline')
            self%scale = 2
            self%kernel => cubic_spline_kernel
            self%factor = 15.0_rk/(7.0_rk*Pi*self%hsml*self%hsml)
        case ('quintic-spline')
            self%scale = 3
            self%kernel => quintic_spline_kernel
            self%factor = 7.0_rk/(478.0_rk*Pi*self%hsml*self%hsml)
        case default
            self%scale = 2
            self%kernel => cubic_spline_kernel
            self%factor = 15.0_rk/(7.0_rk*Pi*self%hsml*self%hsml)
            call terminal_obj%warning('Unknown kernel type, use cubic-spline kernel by default')
        end select
        call self%kernel(0.0_rk, [0.0_rk, 0.0_rk], self%selfden, hv)
        self%scale_hsml = self%hsml*self%scale

    end subroutine init

    !> Smoothed kernel function: Cubic spline <br>
    !> 三次样条曲线 (monaghan 1985) <br>
    !> 计算光滑函数 \( W_{ij} \) 及其导数 \( \frac{dW}{dx_{ij}} \) 的子例程
    pure subroutine cubic_spline_kernel(skf, r, dx, w, dwdx)
        class(smoothed_kernel_function_type), intent(in) :: skf
        real(rk), intent(in) :: r           !! Euclidean distance between two points <br>
                                            !! 欧氏距离
        real(rk), intent(in) :: dx(2)       !! Dimensional distance between two points <br>
                                            !! 对应坐标轴距离
        real(rk), intent(out) :: w          !! kernel value <br>
                                            !! 核函数值
        real(rk), intent(out) :: dwdx(2)    !! Derivative of kernel value <br>
                                            !! 核函数导数
        real(rk) :: q

        q = r/skf%hsml
        if (q <= 1.0_rk) then
            w = skf%factor*(r23 - q*q + q**3/2)
            dwdx = skf%factor*(-2.0_rk + 1.5_rk*q)*dx/(skf%hsml*skf%hsml)     ! 计算机原则,先乘后除
        else if (q > 1.0_rk) then
            w = skf%factor*(2.0_rk - q)**3/6.0_rk
            dwdx = -skf%factor*(2.0_rk - q)**2*dx/(2.0_rk*skf%hsml*r)
        end if

    end subroutine cubic_spline_kernel

    !> Smoothed kernel function: Quintic spline <br>
    !> 四次样条曲线 (Liu 2010)
    pure subroutine quintic_spline_kernel(skf, r, dx, w, dwdx)
        class(smoothed_kernel_function_type), intent(in) :: skf
        real(rk), intent(in) :: r           !! Euclidean distance between two points <br>
                                            !! 欧氏距离
        real(rk), intent(in) :: dx(2)       !! Dimensional distance between two points <br>
                                            !! 对应坐标轴距离
        real(rk), intent(out) :: w          !! kernel value <br>
                                            !! 核函数值
        real(rk), intent(out) :: dwdx(2)    !! Derivative of kernel value <br>
                                            !! 核函数导数
        real(rk) :: q

        q = r/skf%hsml
        if (q <= 1.0_rk) then
            w = skf%factor*((3 - q)**5 - 6*(2 - q)**5 + 15*(1 - q)**5)
            dwdx = skf%factor*(-120.0_rk + 120.0_rk*q - 50.0_rk*q**2)*dx/skf%hsml**2
        else if (q > 1.0_rk .and. q <= 2.0_rk) then
            w = skf%factor*((3 - q)**5 - 6*(2 - q)**5)
            dwdx = skf%factor*(-5.0_rk*(3 - q)**4 + 30.0_rk*(2 - q)**4)*dx/(skf%hsml*r)
        else if (q > 2.0_rk .and. q <= 3.0_rk) then
            w = skf%factor*((3 - q)**5)
            dwdx = skf%factor*(-5.0_rk*(3 - q)**4)*dx/(skf%hsml*r)
        else
            w = 0.0_rk
            dwdx = 0.0_rk
        end if

    end subroutine quintic_spline_kernel

end module spx_smoothed_kernel_function