Skip to content
Snippets Groups Projects
ppm_comp_pp_mk_table.f 10.45 KiB
      !-------------------------------------------------------------------------
      !  Subroutine   :               ppm_comp_pp_mk_table
      !-------------------------------------------------------------------------
      !  Parallel Particle Mesh Library (PPM)
      !  ETH Zurich
      !  CH-8092 Zurich, Switzerland
      !-------------------------------------------------------------------------

#if   __KERNEL == __INTERNAL
#if   __KIND == __SINGLE_PRECISION
      SUBROUTINE ppm_comp_pp_mk_table_si(kernel,kpar,ntable,cutoff2,   &
     &    ktab,dxtableinv,info)
#elif __KIND == __DOUBLE_PRECISION
      SUBROUTINE ppm_comp_pp_mk_table_di(kernel,kpar,ntable,cutoff2,   &
     &    ktab,dxtableinv,info)
#elif __KIND == __SINGLE_PRECISION_COMPLEX
      SUBROUTINE ppm_comp_pp_mk_table_sci(kernel,kpar,ntable,cutoff2,   &
     &    ktab,dxtableinv,info)
#elif __KIND == __DOUBLE_PRECISION_COMPLEX
      SUBROUTINE ppm_comp_pp_mk_table_dci(kernel,kpar,ntable,cutoff2,   &
     &    ktab,dxtableinv,info)
#endif
#elif __KERNEL == __USER_FUNCTION
#if   __KIND == __SINGLE_PRECISION
      SUBROUTINE ppm_comp_pp_mk_table_su(kernel,kpar,ntable,cutoff2,   &
     &    ktab,dxtableinv,info)
#elif __KIND == __DOUBLE_PRECISION
      SUBROUTINE ppm_comp_pp_mk_table_du(kernel,kpar,ntable,cutoff2,   &
     &    ktab,dxtableinv,info)
#elif __KIND == __SINGLE_PRECISION_COMPLEX
      SUBROUTINE ppm_comp_pp_mk_table_scu(kernel,kpar,ntable,cutoff2,   &
     &    ktab,dxtableinv,info)
#elif __KIND == __DOUBLE_PRECISION_COMPLEX
      SUBROUTINE ppm_comp_pp_mk_table_dcu(kernel,kpar,ntable,cutoff2,   &
     &    ktab,dxtableinv,info)
#endif
#endif
      !!! Creates a lookup table for a PP interaction kernel.
      !!! The result is returned in the variables ktab with
      !!! indices running from 0 to ntable-1. The table
      !!! contains kernel values eta as a function of the
      !!! _squared_ distance x**2.
      !-------------------------------------------------------------------------
      !  Modules
      !-------------------------------------------------------------------------
      USE ppm_module_data
      USE ppm_module_substart
      USE ppm_module_substop
      USE ppm_module_error
      USE ppm_module_alloc
      IMPLICIT NONE
#if   __KIND == __SINGLE_PRECISION | __KIND == __SINGLE_PRECISION_COMPLEX
      INTEGER, PARAMETER :: MK = ppm_kind_single
#elif __KIND == __DOUBLE_PRECISION | __KIND == __DOUBLE_PRECISION_COMPLEX
      INTEGER, PARAMETER :: MK = ppm_kind_double
#endif
      !-------------------------------------------------------------------------
      !  Includes
      !-------------------------------------------------------------------------
#include "ppm_define.h"
      !-------------------------------------------------------------------------
      !  Arguments
      !-------------------------------------------------------------------------
      INTEGER                    , INTENT(IN   ) :: ntable
      !!! Number of table entries to be created.
      REAL(MK)                   , INTENT(IN   ) :: cutoff2
      !!! Square of the cutoff used for PP interactions. The kernel will be
      !!! tabulated up to this value.
#if   __KIND == __SINGLE_PRECISION | __KIND == __DOUBLE_PRECISION
      REAL(MK)     , DIMENSION(:), POINTER       :: ktab
      !!! Tabulated kernel values 0...ntable-1.
      !!! Overloaded types: single,double.
#elif __KIND == __SINGLE_PRECISION_COMPLEX | __KIND == __DOUBLE_PRECISION_COMPLEX
      COMPLEX(MK)  , DIMENSION(:), POINTER       :: ktab
      !!! Tabulated kernel values 0...ntable-1.
      !!! Overloaded types: single complex,double complex.
#endif
#if   __KERNEL == __INTERNAL
      INTEGER                    , INTENT(IN   ) :: kernel
      !!! kernel for which to compute the correction. To use ppm-internal
      !!! kernels, specify one of:
      !!!
      !!! ---------------------------------------
      !!!    ppm_param_kerel_laplace2d_2p
      !!!      (2nd order Laplacian,
      !!!      polynomial in 2D)
      !!!    ppm_param_kerel_laplace3d_2p
      !!!      (2nd order Laplacian,
      !!!      polynomial in 3D)
      !!! ---------------------------------------
      !!!
      !!! To use your own kernel function, pass the function pointer here. Your
      !!! function should take one argument and return one value.
#if   __KIND == __SINGLE_PRECISION | __KIND == __DOUBLE_PRECISION
      REAL(MK)   , DIMENSION(:)  , INTENT(IN   ) :: kpar
#elif __KIND == __SINGLE_PRECISION_COMPLEX | __KIND == __DOUBLE_PRECISION_COMPLEX
      COMPLEX(MK), DIMENSION(:)  , INTENT(IN   ) :: kpar
#endif
      !!! Kernel parameters. See documentation or ppm_comp_pp_kernels.inc for
      !!! description. Type can be single, double, single complex or double
      !!! complex. Omit this argument when using a lookup table.
#endif
      REAL(MK)                   , INTENT(  OUT) :: dxtableinv
      !!! inverse of the dx (kernel evaluation locations) used to create
      !!! the table. To use the table, look up the value
      !!! `ktab(INT(dxtableinv*x))`.
      INTEGER                    , INTENT(  OUT) :: info
      !!! Returns status, 0 upon success
      !-------------------------------------------------------------------------
      !  Local variables
      !-------------------------------------------------------------------------
      INTEGER                  :: i,atable,iopt,idx
      INTEGER, DIMENSION(1)    :: ldl,ldu
      REAL(MK), PARAMETER      :: Rmin = 0.0_MK
      REAL(MK)                 :: dxtable,Rmax,factor,factor2
      REAL(MK)                 :: t0,dij,dij2,dij4,dij5,dx,dy,dz
#if   __KIND == __SINGLE_PRECISION | __KIND == __DOUBLE_PRECISION
      REAL(MK)                 :: eta
#elif __KIND == __SINGLE_PRECISION_COMPLEX | __KIND == __DOUBLE_PRECISION_COMPLEX
      COMPLEX(MK)              :: eta
#endif
      !-------------------------------------------------------------------------
      !  Externals
      !-------------------------------------------------------------------------
#if   __KERNEL == __USER_FUNCTION
#if   __KIND == __SINGLE_PRECISION | __KIND == __DOUBLE_PRECISION
      REAL(MK)   , DIMENSION(:)  , INTENT(IN   ) :: kpar
      INTERFACE
          FUNCTION kernel(x,kpar)
              IMPLICIT NONE
#if   __KIND == __SINGLE_PRECISION | __KIND == __SINGLE_PRECISION_COMPLEX
              INTEGER, PARAMETER :: MK = KIND(1.0E0)
#elif __KIND == __DOUBLE_PRECISION | __KIND == __DOUBLE_PRECISION_COMPLEX
              INTEGER, PARAMETER :: MK = KIND(1.0D0)
#endif
              REAL(MK), INTENT(IN) :: x
              REAL(MK), DIMENSION(:), INTENT(IN) :: kpar
              REAL(MK) :: kernel
          END FUNCTION kernel
      END INTERFACE
#elif __KIND == __SINGLE_PRECISION_COMPLEX | __KIND == __DOUBLE_PRECISION_COMPLEX
      COMPLEX(MK), DIMENSION(:)  , INTENT(IN   ) :: kpar
      INTERFACE
          FUNCTION kernel(x,kpar)
              IMPLICIT NONE
#if   __KIND == __SINGLE_PRECISION | __KIND == __SINGLE_PRECISION_COMPLEX
              INTEGER, PARAMETER :: MK = KIND(1.0E0)
#elif __KIND == __DOUBLE_PRECISION | __KIND == __DOUBLE_PRECISION_COMPLEX
              INTEGER, PARAMETER :: MK = KIND(1.0D0)
#endif
              REAL(MK), INTENT(IN) :: x
              COMPLEX(MK), DIMENSION(:), INTENT(IN) :: kpar
              COMPLEX(MK) :: kernel
          END FUNCTION kernel
      END INTERFACE
#endif
#endif

      !-------------------------------------------------------------------------
      !  Initialise
      !-------------------------------------------------------------------------
      CALL substart('ppm_comp_pp_mk_table',t0,info)

      !-------------------------------------------------------------------------
      !  Check arguments.
      !-------------------------------------------------------------------------
      IF (ppm_debug .GT. 0) THEN
          IF (ntable .LT. 1) THEN
              info = ppm_error_error
              CALL ppm_error(ppm_err_argument,'ppm_comp_pp_mk_table',  &
     &            'ntable must be >0',__LINE__,info)
              GOTO 9999
          ENDIF
          IF (cutoff2 .LT. 0.0_MK) THEN
              info = ppm_error_error
              CALL ppm_error(ppm_err_argument,'ppm_comp_pp_mk_table',  &
     &            'cutoff2 must be >=0',__LINE__,info)
              GOTO 9999
          ENDIF
      ENDIF

      !-------------------------------------------------------------------------
      !  Compute Rmax
      !-------------------------------------------------------------------------
      Rmax = cutoff2

      !-------------------------------------------------------------------------
      !  Allocate memory for table lookup
      !-------------------------------------------------------------------------
      atable = ntable-1

      iopt = ppm_param_alloc_fit
      ldl(1) = 0
      ldu(1) = atable
      CALL ppm_alloc(ktab,ldl,ldu,iopt,info)
      IF (info .NE. ppm_param_success) THEN
          info = ppm_error_fatal
          CALL ppm_error(ppm_err_alloc,'ppm_comp_pp_mk_table',     &
     &        'kernel lookup table KTAB',__LINE__,info)
          GOTO 9999
      ENDIF

      !-------------------------------------------------------------------------
      !  Compute values
      !-------------------------------------------------------------------------
      dxtable    = (Rmax - Rmin)/REAL(atable,MK)
      dxtableinv = 1.0_MK/dxtable

      ! This hack is needed since some kernels use dx,dy,dz explicitly. DO
      ! NOT MAKE TABLES FOR THOSE KERNELS!
      dx = 0.0_MK
      dy = 0.0_MK
      dz = 0.0_MK
      DO i=0,atable
         dij = Rmin + REAL(i,MK)*dxtable
#include "ppm_comp_pp_kernels.inc"
         ktab(i) = eta
      ENDDO

      !-------------------------------------------------------------------------
      !  Return
      !-------------------------------------------------------------------------
 9999 CONTINUE
      CALL substop('ppm_comp_pp_mk_table',t0,info)
      RETURN
#if   __KERNEL == __INTERNAL
#if   __KIND == __SINGLE_PRECISION
      END SUBROUTINE ppm_comp_pp_mk_table_si
#elif __KIND == __DOUBLE_PRECISION
      END SUBROUTINE ppm_comp_pp_mk_table_di
#elif __KIND == __SINGLE_PRECISION_COMPLEX
      END SUBROUTINE ppm_comp_pp_mk_table_sci
#elif __KIND == __DOUBLE_PRECISION_COMPLEX
      END SUBROUTINE ppm_comp_pp_mk_table_dci
#endif

#elif __KERNEL == __USER_FUNCTION
#if   __KIND == __SINGLE_PRECISION
      END SUBROUTINE ppm_comp_pp_mk_table_su
#elif __KIND == __DOUBLE_PRECISION
      END SUBROUTINE ppm_comp_pp_mk_table_du
#elif __KIND == __SINGLE_PRECISION_COMPLEX
      END SUBROUTINE ppm_comp_pp_mk_table_scu
#elif __KIND == __DOUBLE_PRECISION_COMPLEX
      END SUBROUTINE ppm_comp_pp_mk_table_dcu
#endif
#endif