LCOV - code coverage report
Current view: top level - src/pw - fft_tools.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:e08e82d) Lines: 52.4 % 1373 719
Test Date: 2026-10-16 00:55:08 Functions: 58.1 % 31 18

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \par History
      10              : !>      JGH (30-Nov-2000): ESSL FFT Library added
      11              : !>      JGH (05-Jan-2001): Added SGI library FFT
      12              : !>      JGH (14-Jan-2001): Added parallel 3d FFT
      13              : !>      JGH (10-Feb-2006): New interface type
      14              : !>      JGH (31-Mar-2008): Remove local allocates and reshapes (performance)
      15              : !>                         Possible problems can be related with setting arrays
      16              : !>                         not to zero
      17              : !>                         Some interfaces could be further simplified by avoiding
      18              : !>                         an initial copy. However, this assumes contiguous arrays
      19              : !>      IAB (15-Oct-2008): Moved mp_cart_sub calls out of cube_tranpose_* and into
      20              : !>                         fft_scratch type, reducing number of calls dramatically
      21              : !>      IAB (05-Dec-2008): Moved all other non-essential MPI calls into scratch type
      22              : !>      IAB (09-Jan-2009): Added fft_plan_type to store FFT data, including cached FFTW plans
      23              : !>      IAB (13-Feb-2009): Extended plan caching to serial 3D FFT (fft3d_s)
      24              : !>      IAB (09-Oct-2009): Added OpenMP directives to parallel 3D FFT
      25              : !>                         (c) The Numerical Algorithms Group (NAG) Ltd, 2008-2009 on behalf of the HECToR project
      26              : !>      HFP (17-Oct-2024): Thread-safety insurance (CPASSERT), and OMP ATOMIC (tick_fft_pool)
      27              : !> \author JGH
      28              : ! **************************************************************************************************
      29              : MODULE fft_tools
      30              :    USE ISO_C_BINDING,                   ONLY: C_F_POINTER,&
      31              :                                               C_LOC,&
      32              :                                               C_PTR,&
      33              :                                               C_SIZE_T
      34              :    USE cp_log_handling,                 ONLY: cp_logger_get_default_io_unit
      35              :    USE fft_lib,                         ONLY: &
      36              :         fft_1d, fft_3d, fft_alloc, fft_create_plan_1d, fft_create_plan_3d, fft_dealloc, &
      37              :         fft_destroy_plan, fft_do_cleanup, fft_do_init, fft_get_lengths
      38              :    USE fft_plan,                        ONLY: fft_plan_type
      39              :    USE kinds,                           ONLY: dp,&
      40              :                                               dp_size,&
      41              :                                               sp
      42              :    USE mathconstants,                   ONLY: z_zero
      43              :    USE message_passing,                 ONLY: mp_cart_type,&
      44              :                                               mp_comm_null,&
      45              :                                               mp_comm_type,&
      46              :                                               mp_request_type,&
      47              :                                               mp_waitall
      48              :    USE offload_api,                     ONLY: offload_free_pinned_mem,&
      49              :                                               offload_malloc_pinned_mem
      50              : 
      51              : !$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num, omp_in_parallel
      52              : 
      53              : #include "../base/base_uses.f90"
      54              : 
      55              :    IMPLICIT NONE
      56              : 
      57              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'fft_tools'
      58              : 
      59              :    ! Types for the pool of scratch data needed in FFT routines
      60              :    ! keep the subroutine "is_equal" up-to-date
      61              :    ! needs a default initialization
      62              :    TYPE fft_scratch_sizes
      63              :       INTEGER                              :: nx = 0, ny = 0, nz = 0
      64              :       INTEGER                              :: lmax = 0, mmax = 0, nmax = 0
      65              :       INTEGER                              :: mx1 = 0, mx2 = 0, mx3 = 0
      66              :       INTEGER                              :: my1 = 0, my2 = 0, my3 = 0
      67              :       INTEGER                              :: mz1 = 0, mz2 = 0, mz3 = 0
      68              :       INTEGER                              :: mcz1 = 0, mcz2 = 0, mcy3 = 0, mcx2 = 0
      69              :       INTEGER                              :: lg = 0, mg = 0
      70              :       INTEGER                              :: nbx = 0, nbz = 0
      71              :       INTEGER                              :: nmray = 0, nyzray = 0
      72              :       TYPE(mp_cart_type)                   :: rs_group = mp_cart_type()
      73              :       INTEGER, DIMENSION(2)                :: g_pos = 0, r_pos = 0, r_dim = 0
      74              :       INTEGER                              :: numtask = 0
      75              :    END TYPE fft_scratch_sizes
      76              : 
      77              :    TYPE fft_scratch_type
      78              :       INTEGER                              :: fft_scratch_id = 0
      79              :       INTEGER                              :: tf_type = -1
      80              :       LOGICAL                              :: in_use = .TRUE.
      81              :       TYPE(mp_comm_type)                   :: group = mp_comm_type()
      82              :       INTEGER, DIMENSION(3)                :: nfft = -1
      83              :       ! to be used in cube_transpose_* routines
      84              :       TYPE(mp_cart_type), DIMENSION(2)     :: cart_sub_comm = mp_cart_type()
      85              :       INTEGER, DIMENSION(2)                :: dim = -1, pos = -1
      86              :       ! to be used in fft3d_s
      87              :       COMPLEX(KIND=dp), DIMENSION(:, :, :), POINTER, CONTIGUOUS &
      88              :          :: ziptr => NULL(), zoptr => NULL()
      89              :       ! to be used in fft3d_ps : block distribution
      90              :       COMPLEX(KIND=dp), DIMENSION(:, :), CONTIGUOUS, POINTER &
      91              :          :: p1buf => NULL(), p2buf => NULL(), p3buf => NULL(), p4buf => NULL(), &
      92              :             p5buf => NULL(), p6buf => NULL(), p7buf => NULL()
      93              :       ! to be used in fft3d_ps : plane distribution
      94              :       COMPLEX(KIND=dp), DIMENSION(:, :), POINTER, CONTIGUOUS &
      95              :          :: r1buf => NULL(), r2buf => NULL()
      96              :       COMPLEX(KIND=dp), DIMENSION(:, :, :), POINTER, CONTIGUOUS &
      97              :          :: tbuf => NULL()
      98              :       ! to be used in fft3d_pb
      99              :       COMPLEX(KIND=dp), DIMENSION(:, :), POINTER, CONTIGUOUS &
     100              :          :: a1buf => NULL(), a2buf => NULL(), a3buf => NULL(), &
     101              :             a4buf => NULL(), a5buf => NULL(), a6buf => NULL()
     102              :       ! to be used in communication routines
     103              :       INTEGER, DIMENSION(:), CONTIGUOUS, POINTER    :: scount => NULL(), rcount => NULL(), sdispl => NULL(), rdispl => NULL()
     104              :       INTEGER, DIMENSION(:, :), CONTIGUOUS, POINTER :: pgcube => NULL()
     105              :       INTEGER, DIMENSION(:), CONTIGUOUS, POINTER    :: xzcount => NULL(), yzcount => NULL(), xzdispl => NULL(), yzdispl => NULL()
     106              :       INTEGER                                       :: in = 0, mip = -1
     107              :       REAL(KIND=dp)                                 :: rsratio = 1.0_dp
     108              :       COMPLEX(KIND=dp), DIMENSION(:), POINTER, CONTIGUOUS &
     109              :          :: xzbuf => NULL(), yzbuf => NULL()
     110              :       COMPLEX(KIND=sp), DIMENSION(:), POINTER, CONTIGUOUS &
     111              :          :: xzbuf_sgl => NULL(), yzbuf_sgl => NULL()
     112              :       COMPLEX(KIND=dp), DIMENSION(:, :), POINTER, CONTIGUOUS &
     113              :          :: rbuf1 => NULL(), rbuf2 => NULL(), rbuf3 => NULL(), rbuf4 => NULL(), &
     114              :             rbuf5 => NULL(), rbuf6 => NULL(), rr => NULL()
     115              :       COMPLEX(KIND=sp), DIMENSION(:, :), POINTER, CONTIGUOUS &
     116              :          :: ss => NULL(), tt => NULL()
     117              :       INTEGER, DIMENSION(:, :), POINTER, CONTIGUOUS :: pgrid => NULL()
     118              :       INTEGER, DIMENSION(:), POINTER, CONTIGUOUS    :: xcor => NULL(), zcor => NULL(), pzcoord => NULL()
     119              :       TYPE(fft_scratch_sizes)                       :: sizes = fft_scratch_sizes()
     120              :       TYPE(fft_plan_type), DIMENSION(6)             :: fft_plan = fft_plan_type()
     121              :       INTEGER                                       :: last_tick = -1
     122              :    END TYPE fft_scratch_type
     123              : 
     124              :    TYPE fft_scratch_pool_type
     125              :       TYPE(fft_scratch_type), POINTER       :: fft_scratch => NULL()
     126              :       TYPE(fft_scratch_pool_type), POINTER  :: fft_scratch_next => NULL()
     127              :    END TYPE fft_scratch_pool_type
     128              : 
     129              :    INTEGER, SAVE                              :: init_fft_pool = 0
     130              :    ! the clock for fft pool. Allows to identify the least recently used scratch
     131              :    INTEGER, SAVE                              :: tick_fft_pool = 0
     132              :    ! limit the number of scratch pools to fft_pool_scratch_limit.
     133              :    INTEGER, SAVE                              :: fft_pool_scratch_limit = 15
     134              :    TYPE(fft_scratch_pool_type), POINTER, SAVE :: fft_scratch_first
     135              :    ! END of types for the pool of scratch data needed in FFT routines
     136              : 
     137              :    PRIVATE
     138              :    PUBLIC :: init_fft, fft3d, finalize_fft
     139              :    PUBLIC :: fft_alloc, fft_dealloc
     140              :    PUBLIC :: init_fft_scratch_pool
     141              :    PUBLIC :: fft_radix_operations, fft_1d_many
     142              :    PUBLIC :: FWFFT, BWFFT
     143              :    PUBLIC :: FFT_RADIX_CLOSEST, FFT_RADIX_NEXT
     144              :    PUBLIC :: FFT_RADIX_NEXT_ODD
     145              : 
     146              :    INTEGER, PARAMETER :: FWFFT = +1, BWFFT = -1
     147              :    INTEGER, PARAMETER :: FFT_RADIX_CLOSEST = 493, FFT_RADIX_NEXT = 494
     148              :    INTEGER, PARAMETER :: FFT_RADIX_ALLOWED = 495, FFT_RADIX_DISALLOWED = 496
     149              :    INTEGER, PARAMETER :: FFT_RADIX_NEXT_ODD = 497
     150              : 
     151              :    REAL(KIND=dp), PARAMETER :: ratio_sparse_alltoall = 0.5_dp
     152              : 
     153              :    ! these saved variables are FFT globals
     154              :    LOGICAL, SAVE :: alltoall_sgl = .FALSE.
     155              : 
     156              :    ! these are only needed for pw_gpu (-D__OFFLOAD)
     157              :    PUBLIC :: get_fft_scratch, release_fft_scratch
     158              :    PUBLIC :: cube_transpose_1, cube_transpose_2
     159              :    PUBLIC :: yz_to_x, x_to_yz, xz_to_yz, yz_to_xz
     160              :    PUBLIC :: fft_scratch_sizes, fft_scratch_type
     161              : 
     162              :    INTERFACE fft3d
     163              :       MODULE PROCEDURE fft3d_s, fft3d_ps, fft3d_pb
     164              :    END INTERFACE
     165              : 
     166              : ! **************************************************************************************************
     167              : 
     168              : CONTAINS
     169              : 
     170              : ! **************************************************************************************************
     171              : !> \brief ...
     172              : !> \param fftlib ...
     173              : !> \param alltoall ...
     174              : !> \param pool_limit ...
     175              : !> \param wisdom_file ...
     176              : !> \param plan_style ...
     177              : !> \author JGH
     178              : ! **************************************************************************************************
     179        11732 :    SUBROUTINE init_fft(fftlib, alltoall, pool_limit, wisdom_file, &
     180              :                        plan_style)
     181              : 
     182              :       CHARACTER(LEN=*), INTENT(IN)                       :: fftlib
     183              :       LOGICAL, INTENT(IN)                                :: alltoall
     184              :       INTEGER, INTENT(IN)                                :: pool_limit
     185              :       CHARACTER(LEN=*), INTENT(IN)                       :: wisdom_file
     186              :       INTEGER, INTENT(IN)                                :: plan_style
     187              : 
     188        11732 :       alltoall_sgl = alltoall
     189        11732 :       fft_pool_scratch_limit = pool_limit
     190              : 
     191        11732 :       CALL release_fft_scratch_pool()
     192              : 
     193        11732 :       CALL fft_do_init(fftlib, plan_style, wisdom_file)
     194              : 
     195              :       ! setup the FFT scratch pool, if one is associated, clear first
     196        11732 :       CALL init_fft_scratch_pool()
     197              : 
     198        11732 :    END SUBROUTINE init_fft
     199              : 
     200              : ! **************************************************************************************************
     201              : !> \brief does whatever is needed to finalize the current fft setup
     202              : !> \param para_env ...
     203              : !> \param wisdom_file ...
     204              : !> \param export_wisdom Export the FFTW wisdom to wisdom_file (default: no export)
     205              : !> \par History
     206              : !>      10.2007 created [Joost VandeVondele]
     207              : ! **************************************************************************************************
     208        11521 :    SUBROUTINE finalize_fft(para_env, wisdom_file, export_wisdom)
     209              :       CLASS(mp_comm_type)                    :: para_env
     210              :       CHARACTER(LEN=*), INTENT(IN)           :: wisdom_file
     211              :       LOGICAL, INTENT(IN), OPTIONAL          :: export_wisdom
     212              : 
     213              : ! release the FFT scratch pool
     214              : 
     215        11521 :       CALL release_fft_scratch_pool()
     216              : 
     217              :       ! finalize fft libs
     218              : 
     219        11521 :       CALL fft_do_cleanup(wisdom_file, para_env%is_source(), export_wisdom)
     220              : 
     221        11521 :    END SUBROUTINE finalize_fft
     222              : 
     223              : ! **************************************************************************************************
     224              : !> \brief Determine the allowed lengths of FFT's   '''
     225              : !> \param radix_in ...
     226              : !> \param radix_out ...
     227              : !> \param operation ...
     228              : !> \par History
     229              : !>      new library structure (JGH)
     230              : !> \author Ari Seitsonen
     231              : ! **************************************************************************************************
     232       270964 :    SUBROUTINE fft_radix_operations(radix_in, radix_out, operation)
     233              : 
     234              :       INTEGER, INTENT(IN)                                :: radix_in
     235              :       INTEGER, INTENT(OUT)                               :: radix_out
     236              :       INTEGER, INTENT(IN)                                :: operation
     237              : 
     238              :       INTEGER, PARAMETER                                 :: number_of_small_radices = 81
     239              :       INTEGER, DIMENSION(number_of_small_radices), PARAMETER :: small_radices = [2, 4, 6, 8, 9, 12,&
     240              :          15, 16, 18, 20, 24, 25, 27, 30, 32, 36, 40, 45, 48, 54, 60, 64, 72, 75, 80, 81, 90, 96, &
     241              :          100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192, 200, 216, 225, 240, 243, 256, &
     242              :          270, 288, 300, 320, 324, 360, 375, 384, 400, 405, 432, 450, 480, 486, 500, 512, 540, 576, &
     243              :          600, 625, 640, 648, 675, 720, 729, 750, 768, 800, 810, 864, 900, 960, 972, 1000, 1024]
     244              : 
     245              :       INTEGER                                            :: i, iloc, ldata, trial_number
     246       270964 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: DATA
     247              : 
     248       270964 :       ldata = 1024
     249       270964 :       ALLOCATE (DATA(ldata))
     250    277738100 :       DATA = -1
     251              : 
     252     22219048 :       DATA(1:number_of_small_radices) = small_radices(1:number_of_small_radices)
     253              : 
     254              :       ! First run: try smaller radices
     255              :       ! Second run: Fetch extended list of radices and try these
     256       270964 :       DO trial_number = 1, 2
     257       270964 :          IF (trial_number == 2) CALL fft_get_lengths(DATA, ldata)
     258       270964 :          iloc = 0
     259      3508745 :          DO i = 1, ldata
     260      3508745 :             IF (DATA(i) == radix_in) THEN
     261              :                iloc = i
     262              :                EXIT
     263              :             ELSE
     264      3362681 :                IF (OPERATION == FFT_RADIX_ALLOWED) THEN
     265              :                   CYCLE
     266      3362681 :                ELSE IF (DATA(i) > radix_in) THEN
     267              :                   iloc = i
     268              :                   EXIT
     269              :                END IF
     270              :             END IF
     271              :          END DO
     272              : 
     273       270964 :          IF (iloc == 0) THEN
     274            0 :             IF (trial_number == 1) THEN
     275              :                ! We haven't found any suitable size in the list of smaller radices
     276              :                ! because the requested radix is too large (large cell or large cutoff)
     277              :                ! So, try again with the larger radices
     278              :                CYCLE
     279              :             ELSE
     280            0 :                IF (OPERATION == FFT_RADIX_CLOSEST) THEN
     281            0 :                   radix_out = MAXVAL(DATA)
     282              :                ELSE
     283              :                   CALL cp_abort(__LOCATION__, &
     284            0 :                                 "No suitable FFT lengths found! Either enable FFTW or reduce the grid size!")
     285              :                END IF
     286            0 :                RETURN
     287              :             END IF
     288              : 
     289              :          END IF
     290              : 
     291       270964 :          IF (OPERATION == FFT_RADIX_ALLOWED) THEN
     292            0 :             IF (DATA(iloc) == radix_in) THEN
     293            0 :                radix_out = FFT_RADIX_ALLOWED
     294              :             ELSE
     295            0 :                radix_out = FFT_RADIX_DISALLOWED
     296              :             END IF
     297              : 
     298       270964 :          ELSE IF (OPERATION == FFT_RADIX_CLOSEST) THEN
     299          282 :             IF (DATA(iloc) == radix_in) THEN
     300          120 :                radix_out = DATA(iloc)
     301              :             ELSE
     302          162 :                IF (ABS(DATA(iloc - 1) - radix_in) <= &
     303              :                    ABS(DATA(iloc) - radix_in)) THEN
     304          156 :                   radix_out = DATA(iloc - 1)
     305              :                ELSE
     306            6 :                   radix_out = DATA(iloc)
     307              :                END IF
     308              :             END IF
     309              : 
     310       270682 :          ELSE IF (OPERATION == FFT_RADIX_NEXT) THEN
     311       268672 :             radix_out = DATA(iloc)
     312              : 
     313         2010 :          ELSE IF (OPERATION == FFT_RADIX_NEXT_ODD) THEN
     314         3458 :             DO i = iloc, ldata
     315         3458 :                IF (MOD(DATA(i), 2) == 1) THEN
     316         2010 :                   radix_out = DATA(i)
     317         2010 :                   EXIT
     318              :                END IF
     319              :             END DO
     320         2010 :             IF (MOD(radix_out, 2) == 0) THEN
     321              :                ! No larger odd radix found
     322            0 :                IF (trial_number == 1) THEN
     323              :                   CYCLE
     324              :                ELSE
     325            0 :                   radix_out = radix_in + 1 - MOD(radix_in, 2)
     326              :                END IF
     327              :             END IF
     328              : 
     329              :          END IF
     330            0 :          EXIT
     331              :       END DO
     332              : 
     333       270964 :       DEALLOCATE (DATA)
     334              : 
     335            0 :    END SUBROUTINE fft_radix_operations
     336              : 
     337              : ! **************************************************************************************************
     338              : !> \brief Performs m 1-D forward FFT-s of size n.
     339              : !> \param sign ...
     340              : !> \param n      size of the FFT
     341              : !> \param m      number of FFT-s
     342              : !> \param trans_in transposition state of the input array
     343              : !> \param trans_out transposition state of the output array
     344              : !> \param ldx_in ...
     345              : !> \param ldx_out ...
     346              : !> \param zin    input array
     347              : !> \param zout   output array
     348              : !> \param scale  scaling factor
     349              : !> \param stat   status of the operation, non-zero code indicates an error
     350              : ! **************************************************************************************************
     351         1020 :    SUBROUTINE fft_1d_many(sign, n, m, trans_in, trans_out, ldx_in, ldx_out, zin, zout, scale, stat)
     352              :       INTEGER, INTENT(in)                                :: sign, n, m
     353              :       LOGICAL, INTENT(in)                                :: trans_in, trans_out
     354              :       INTEGER, INTENT(in)                                :: ldx_in, ldx_out
     355              :       COMPLEX(kind=dp), DIMENSION(*), INTENT(inout)      :: zin, zout
     356              :       REAL(kind=dp), INTENT(in)                          :: scale
     357              :       INTEGER, INTENT(out)                               :: stat
     358              : 
     359              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'fft_1d_many'
     360              : 
     361              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:), &
     362         1020 :          POINTER                                         :: ztmp
     363              :       INTEGER                                            :: handle
     364              :       TYPE(fft_plan_type)                                :: fft_plan
     365              : 
     366         1020 :       CALL timeset(routineN, handle)
     367              : 
     368         1020 :       IF (sign /= FWFFT .AND. sign /= BWFFT) THEN
     369            0 :          CPABORT("Unknown FFT-direction!")
     370              :       END IF
     371              : 
     372         1020 :       NULLIFY (ztmp)
     373         1020 :       IF (trans_in) THEN
     374            0 :          CALL fft_alloc(ztmp, [ldx_in*n])
     375              :       ELSE
     376         2040 :          CALL fft_alloc(ztmp, [ldx_in*m])
     377              :       END IF
     378         1020 :       CALL fft_create_plan_1d(fft_plan, sign, trans_in, trans_out, ldx_in, ldx_out, n, m, ztmp, zout)
     379         1020 :       CALL fft_dealloc(ztmp)
     380         1020 :       CALL fft_1d(fft_plan, zin, zout, scale, stat)
     381         1020 :       CALL fft_destroy_plan(fft_plan)
     382              : 
     383         1020 :       CALL timestop(handle)
     384         4080 :    END SUBROUTINE fft_1d_many
     385              : 
     386              : ! **************************************************************************************************
     387              : !> \brief Calls the 3D-FFT function from the initialized library
     388              : !> \param fsign ...
     389              : !> \param n ...
     390              : !> \param zin ...
     391              : !> \param zout ...
     392              : !> \param status ...
     393              : !> \param debug ...
     394              : !> \par History
     395              : !>      none
     396              : !> \author JGH
     397              : ! **************************************************************************************************
     398       698574 :    SUBROUTINE fft3d_s(fsign, n, zin, zout, status, debug)
     399              : 
     400              :       INTEGER, INTENT(IN)                                :: fsign
     401              :       INTEGER, DIMENSION(:), INTENT(INOUT)               :: n
     402              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :, :), &
     403              :          INTENT(INOUT)                                   :: zin
     404              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :, :), &
     405              :          INTENT(INOUT), OPTIONAL, TARGET                 :: zout
     406              :       INTEGER, INTENT(OUT), OPTIONAL                     :: status
     407              :       LOGICAL, INTENT(IN), OPTIONAL                      :: debug
     408              : 
     409              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'fft3d_s'
     410              : 
     411              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :, :), &
     412       698574 :          POINTER                                         :: zoptr
     413              :       COMPLEX(KIND=dp), DIMENSION(1, 1, 1), TARGET       :: zdum
     414              :       INTEGER                                            :: handle, ld(3), lo(3), output_unit, sign, &
     415              :                                                             stat
     416              :       LOGICAL                                            :: fft_in_place, test
     417              :       REAL(KIND=dp)                                      :: in_sum, norm, out_sum
     418              :       TYPE(fft_scratch_type), POINTER                    :: fft_scratch
     419              : 
     420       698574 :       CALL timeset(routineN, handle)
     421       698574 :       output_unit = cp_logger_get_default_io_unit()
     422              : 
     423       698574 :       IF (fsign == FWFFT) THEN
     424      1368988 :          norm = 1.0_dp/REAL(PRODUCT(n), KIND=dp)
     425       356327 :       ELSE IF (fsign == BWFFT) THEN
     426       356327 :          norm = 1.0_dp
     427              :       ELSE
     428            0 :          CPABORT("Unknown FFT direction!")
     429              :       END IF
     430              : 
     431       698574 :       IF (PRESENT(debug)) THEN
     432       618424 :          test = debug
     433              :       ELSE
     434              :          test = .FALSE.
     435              :       END IF
     436              : 
     437       698574 :       IF (PRESENT(zout)) THEN
     438              :          fft_in_place = .FALSE.
     439              :       ELSE
     440       669514 :          fft_in_place = .TRUE.
     441              :       END IF
     442              : 
     443       698574 :       IF (test) THEN
     444            0 :          in_sum = SUM(ABS(zin))
     445              :       END IF
     446              : 
     447       698574 :       ld(1) = SIZE(zin, 1)
     448       698574 :       ld(2) = SIZE(zin, 2)
     449       698574 :       ld(3) = SIZE(zin, 3)
     450              : 
     451       698574 :       IF (n(1) /= ld(1) .OR. n(2) /= ld(2) .OR. n(3) /= ld(3)) THEN
     452            0 :          CPABORT("Size and dimension (zin) have to be the same.")
     453              :       END IF
     454              : 
     455       698574 :       sign = fsign
     456       698574 :       CALL get_fft_scratch(fft_scratch, tf_type=400, n=n)
     457              : 
     458       698574 :       IF (fft_in_place) THEN
     459       669514 :          zoptr => zdum
     460       669514 :          IF (fsign == FWFFT) THEN
     461       313395 :             CALL fft_3d(fft_scratch%fft_plan(1), norm, zin, zoptr, stat)
     462              :          ELSE
     463       356119 :             CALL fft_3d(fft_scratch%fft_plan(2), norm, zin, zoptr, stat)
     464              :          END IF
     465              :       ELSE
     466        29060 :          IF (fsign == FWFFT) THEN
     467        28852 :             CALL fft_3d(fft_scratch%fft_plan(3), norm, zin, zout, stat)
     468              :          ELSE
     469          208 :             CALL fft_3d(fft_scratch%fft_plan(4), norm, zin, zout, stat)
     470              :          END IF
     471              :       END IF
     472              : 
     473       698574 :       CALL release_fft_scratch(fft_scratch)
     474              : 
     475       698574 :       IF (PRESENT(zout)) THEN
     476        29060 :          lo(1) = SIZE(zout, 1)
     477        29060 :          lo(2) = SIZE(zout, 2)
     478        29060 :          lo(3) = SIZE(zout, 3)
     479        29060 :          IF (n(1) /= lo(1) .OR. n(2) /= lo(2) .OR. n(3) /= lo(3)) THEN
     480            0 :             CPABORT("Size and dimension (zout) have to be the same.")
     481              :          END IF
     482              :       END IF
     483              : 
     484       698574 :       IF (PRESENT(status)) THEN
     485        40768 :          status = stat
     486              :       END IF
     487              : 
     488       698574 :       IF (test .AND. output_unit > 0) THEN
     489            0 :          IF (PRESENT(zout)) THEN
     490            0 :             out_sum = SUM(ABS(zout))
     491            0 :             WRITE (output_unit, '(A)') "  Out of place 3D FFT (local)  : fft3d_s"
     492            0 :             WRITE (output_unit, '(A,T60,3I7)') "     Transform lengths ", n
     493            0 :             WRITE (output_unit, '(A,T60,3I7)') "     Input array dimensions ", ld
     494            0 :             WRITE (output_unit, '(A,T60,3I7)') "     Output array dimensions ", lo
     495            0 :             WRITE (output_unit, '(A,T61,E20.14)') "     Sum of input data ", in_sum
     496            0 :             WRITE (output_unit, '(A,T61,E20.14)') "     Sum of output data ", out_sum
     497              :          ELSE
     498            0 :             out_sum = SUM(ABS(zin))
     499            0 :             WRITE (output_unit, '(A)') "  In place 3D FFT (local)  : fft3d_s"
     500            0 :             WRITE (output_unit, '(A,T60,3I7)') "     Transform lengths ", n
     501            0 :             WRITE (output_unit, '(A,T60,3I7)') "     Input/output array dimensions ", ld
     502            0 :             WRITE (output_unit, '(A,T61,E20.14)') "     Sum of input data ", in_sum
     503            0 :             WRITE (output_unit, '(A,T61,E20.14)') "     Sum of output data ", out_sum
     504              :          END IF
     505              :       END IF
     506              : 
     507       698574 :       CALL timestop(handle)
     508              : 
     509       698574 :    END SUBROUTINE fft3d_s
     510              : 
     511              : ! **************************************************************************************************
     512              : !> \brief ...
     513              : !> \param fsign ...
     514              : !> \param n ...
     515              : !> \param cin ...
     516              : !> \param gin ...
     517              : !> \param rs_group ...
     518              : !> \param yzp ...
     519              : !> \param nyzray ...
     520              : !> \param bo ...
     521              : !> \param status ...
     522              : !> \param debug ...
     523              : ! **************************************************************************************************
     524      3658909 :    SUBROUTINE fft3d_ps(fsign, n, cin, gin, rs_group, yzp, nyzray, &
     525      3658909 :                        bo, status, debug)
     526              : 
     527              :       INTEGER, INTENT(IN)                                :: fsign
     528              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: n
     529              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :, :), &
     530              :          INTENT(INOUT)                                   :: cin
     531              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     532              :          INTENT(INOUT)                                   :: gin
     533              :       TYPE(mp_cart_type), INTENT(IN)                     :: rs_group
     534              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), &
     535              :          INTENT(IN)                                      :: yzp
     536              :       INTEGER, CONTIGUOUS, DIMENSION(0:), INTENT(IN)     :: nyzray
     537              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:, :), &
     538              :          INTENT(IN)                                      :: bo
     539              :       INTEGER, INTENT(OUT), OPTIONAL                     :: status
     540              :       LOGICAL, INTENT(IN), OPTIONAL                      :: debug
     541              : 
     542              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'fft3d_ps'
     543              : 
     544              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     545      3658909 :          POINTER                                         :: pbuf, qbuf, rbuf, sbuf
     546              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :, :), &
     547      3658909 :          POINTER                                         :: tbuf
     548              :       INTEGER :: g_pos, handle, lg, lmax, mcx2, mcz1, mcz2, mg, mmax, mx1, mx2, my1, mz2, n1, n2, &
     549              :          nmax, numtask, nx, ny, nz, output_unit, r_dim(2), r_pos(2), rp, sign, stat
     550      3658909 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: p2p
     551              :       LOGICAL                                            :: test
     552              :       REAL(KIND=dp)                                      :: norm, sum_data
     553     25612363 :       TYPE(fft_scratch_sizes)                            :: fft_scratch_size
     554              :       TYPE(fft_scratch_type), POINTER                    :: fft_scratch
     555              : 
     556      3658909 :       CALL timeset(routineN, handle)
     557      3658909 :       output_unit = cp_logger_get_default_io_unit()
     558              : 
     559      3658909 :       IF (PRESENT(debug)) THEN
     560      3658909 :          test = debug
     561              :       ELSE
     562              :          test = .FALSE.
     563              :       END IF
     564              : 
     565      3658909 :       g_pos = rs_group%mepos
     566      3658909 :       numtask = rs_group%num_pe
     567     10976727 :       r_dim = rs_group%num_pe_cart
     568     10976727 :       r_pos = rs_group%mepos_cart
     569              : 
     570      3658909 :       IF (fsign == FWFFT) THEN
     571      7321444 :          norm = 1.0_dp/REAL(PRODUCT(n), KIND=dp)
     572      1828548 :       ELSE IF (fsign == BWFFT) THEN
     573      1828548 :          norm = 1.0_dp
     574              :       ELSE
     575            0 :          CPABORT("Unknown FFT direction!")
     576              :       END IF
     577              : 
     578      3658909 :       sign = fsign
     579              : 
     580      3658909 :       lg = SIZE(gin, 1)
     581      3658909 :       mg = SIZE(gin, 2)
     582              : 
     583      3658909 :       nx = SIZE(cin, 1)
     584      3658909 :       ny = SIZE(cin, 2)
     585      3658909 :       nz = SIZE(cin, 3)
     586              : 
     587      3658909 :       IF (mg == 0) THEN
     588              :          mmax = 1
     589              :       ELSE
     590      3658909 :          mmax = mg
     591              :       END IF
     592      3658909 :       lmax = MAX(lg, (nx*ny*nz)/mmax + 1)
     593              : 
     594     10976727 :       ALLOCATE (p2p(0:numtask - 1))
     595              : 
     596      3658909 :       CALL rs_group%rank_compare(rs_group, p2p)
     597              : 
     598      3658909 :       rp = p2p(g_pos)
     599      3658909 :       mx1 = bo(2, 1, rp, 1) - bo(1, 1, rp, 1) + 1
     600      3658909 :       my1 = bo(2, 2, rp, 1) - bo(1, 2, rp, 1) + 1
     601      3658909 :       mx2 = bo(2, 1, rp, 2) - bo(1, 1, rp, 2) + 1
     602      3658909 :       mz2 = bo(2, 3, rp, 2) - bo(1, 3, rp, 2) + 1
     603              : 
     604     10976727 :       n1 = MAXVAL(bo(2, 1, :, 1) - bo(1, 1, :, 1) + 1)
     605     10976727 :       n2 = MAXVAL(bo(2, 2, :, 1) - bo(1, 2, :, 1) + 1)
     606      3658909 :       nmax = MAX((2*n2)/numtask, 2)*mx2*mz2
     607     10976727 :       nmax = MAX(nmax, n1*MAXVAL(nyzray))
     608     10976727 :       n1 = MAXVAL(bo(2, 1, :, 2))
     609     10976727 :       n2 = MAXVAL(bo(2, 3, :, 2))
     610              : 
     611      3658909 :       fft_scratch_size%nx = nx
     612      3658909 :       fft_scratch_size%ny = ny
     613      3658909 :       fft_scratch_size%nz = nz
     614      3658909 :       fft_scratch_size%lmax = lmax
     615      3658909 :       fft_scratch_size%mmax = mmax
     616      3658909 :       fft_scratch_size%mx1 = mx1
     617      3658909 :       fft_scratch_size%mx2 = mx2
     618      3658909 :       fft_scratch_size%my1 = my1
     619      3658909 :       fft_scratch_size%mz2 = mz2
     620      3658909 :       fft_scratch_size%lg = lg
     621      3658909 :       fft_scratch_size%mg = mg
     622      3658909 :       fft_scratch_size%nbx = n1
     623      3658909 :       fft_scratch_size%nbz = n2
     624     10976727 :       mcz1 = MAXVAL(bo(2, 3, :, 1) - bo(1, 3, :, 1) + 1)
     625     10976727 :       mcx2 = MAXVAL(bo(2, 1, :, 2) - bo(1, 1, :, 2) + 1)
     626     10976727 :       mcz2 = MAXVAL(bo(2, 3, :, 2) - bo(1, 3, :, 2) + 1)
     627      3658909 :       fft_scratch_size%mcz1 = mcz1
     628      3658909 :       fft_scratch_size%mcx2 = mcx2
     629      3658909 :       fft_scratch_size%mcz2 = mcz2
     630      3658909 :       fft_scratch_size%nmax = nmax
     631     10976727 :       fft_scratch_size%nmray = MAXVAL(nyzray)
     632      3658909 :       fft_scratch_size%nyzray = nyzray(g_pos)
     633      3658909 :       fft_scratch_size%rs_group = rs_group
     634     10976727 :       fft_scratch_size%g_pos = g_pos
     635     10976727 :       fft_scratch_size%r_pos = r_pos
     636     10976727 :       fft_scratch_size%r_dim = r_dim
     637      3658909 :       fft_scratch_size%numtask = numtask
     638              : 
     639      3658909 :       IF (test) THEN
     640            8 :          IF (g_pos == 0 .AND. output_unit > 0) THEN
     641            4 :             WRITE (output_unit, '(A)') "  Parallel 3D FFT : fft3d_ps"
     642            4 :             WRITE (output_unit, '(A,T60,3I7)') "     Transform lengths ", n
     643            4 :             WRITE (output_unit, '(A,T67,2I7)') "     Array dimensions (gin) ", lg, mg
     644            4 :             WRITE (output_unit, '(A,T60,3I7)') "     Array dimensions (cin) ", nx, ny, nz
     645              :          END IF
     646              :       END IF
     647              : 
     648      3658909 :       IF (r_dim(2) > 1) THEN
     649              : 
     650              :          !
     651              :          ! real space is distributed over x and y coordinate
     652              :          ! we have two stages of communication
     653              :          !
     654              : 
     655            0 :          IF (r_dim(1) == 1) THEN
     656            0 :             CPABORT("This processor distribution is not supported.")
     657              :          END IF
     658            0 :          CALL get_fft_scratch(fft_scratch, tf_type=300, n=n, fft_sizes=fft_scratch_size)
     659              : 
     660            0 :          IF (sign == FWFFT) THEN
     661              :             ! cin -> gin
     662              : 
     663            0 :             IF (test) THEN
     664            0 :                sum_data = ABS(SUM(cin))
     665            0 :                CALL rs_group%sum(sum_data)
     666            0 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     667            0 :                   WRITE (output_unit, '(A)') "  Two step communication algorithm "
     668            0 :                   WRITE (output_unit, '(A,T60,3I7)') "     Transform Z ", n(3), mx1*my1
     669            0 :                   WRITE (output_unit, '(A,T60,3I7)') "     Transform Y ", n(2), mx2*mz2
     670            0 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform X ", n(1), nyzray(g_pos)
     671            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(1) ", sum_data
     672              :                END IF
     673              :             END IF
     674              : 
     675            0 :             pbuf => fft_scratch%p1buf
     676            0 :             qbuf => fft_scratch%p2buf
     677              : 
     678              :             ! FFT along z
     679            0 :             CALL fft_1d(fft_scratch%fft_plan(1), cin, qbuf, norm, stat)
     680              : 
     681            0 :             rbuf => fft_scratch%p3buf
     682              : 
     683            0 :             IF (test) THEN
     684            0 :                sum_data = ABS(SUM(qbuf))
     685            0 :                CALL rs_group%sum(sum_data)
     686            0 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     687            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(2) T", sum_data
     688              :                END IF
     689              :             END IF
     690              : 
     691              :             ! Exchange data ( transpose of matrix )
     692            0 :             CALL cube_transpose_2(qbuf, bo(:, :, :, 1), bo(:, :, :, 2), rbuf, fft_scratch)
     693              : 
     694            0 :             IF (test) THEN
     695            0 :                sum_data = ABS(SUM(rbuf))
     696            0 :                CALL rs_group%sum(sum_data)
     697            0 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     698            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(3) T", sum_data
     699              :                END IF
     700              :             END IF
     701              : 
     702            0 :             pbuf => fft_scratch%p4buf
     703              : 
     704              :             ! FFT along y
     705            0 :             CALL fft_1d(fft_scratch%fft_plan(2), rbuf, pbuf, 1.0_dp, stat)
     706              : 
     707            0 :             qbuf => fft_scratch%p5buf
     708              : 
     709            0 :             IF (test) THEN
     710            0 :                sum_data = ABS(SUM(pbuf))
     711            0 :                CALL rs_group%sum(sum_data)
     712            0 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     713            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(4) TS", sum_data
     714              :                END IF
     715              :             END IF
     716              : 
     717              :             ! Exchange data ( transpose of matrix ) and sort
     718              :             CALL xz_to_yz(pbuf, rs_group, r_dim, g_pos, p2p, yzp, nyzray, &
     719            0 :                           bo(:, :, :, 2), qbuf, fft_scratch)
     720              : 
     721            0 :             IF (test) THEN
     722            0 :                sum_data = ABS(SUM(qbuf))
     723            0 :                CALL rs_group%sum(sum_data)
     724            0 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     725            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(5) TS", sum_data
     726              :                END IF
     727              :             END IF
     728              : 
     729              :             ! FFT along x
     730            0 :             CALL fft_1d(fft_scratch%fft_plan(3), qbuf, gin, 1.0_dp, stat)
     731              : 
     732            0 :             IF (test) THEN
     733            0 :                sum_data = ABS(SUM(gin))
     734            0 :                CALL rs_group%sum(sum_data)
     735            0 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     736            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(6) ", sum_data
     737              :                END IF
     738              :             END IF
     739              : 
     740            0 :          ELSE IF (sign == BWFFT) THEN
     741              :             ! gin -> cin
     742              : 
     743            0 :             IF (test) THEN
     744            0 :                sum_data = ABS(SUM(gin))
     745            0 :                CALL rs_group%sum(sum_data)
     746            0 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     747            0 :                   WRITE (output_unit, '(A)') "  Two step communication algorithm "
     748            0 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform X ", n(1), nyzray(g_pos)
     749            0 :                   WRITE (output_unit, '(A,T60,3I7)') "     Transform Y ", n(2), mx2*mz2
     750            0 :                   WRITE (output_unit, '(A,T60,3I7)') "     Transform Z ", n(3), mx1*my1
     751            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(1) ", sum_data
     752              :                END IF
     753              :             END IF
     754              : 
     755            0 :             pbuf => fft_scratch%p7buf
     756              : 
     757              :             ! FFT along x
     758            0 :             CALL fft_1d(fft_scratch%fft_plan(4), gin, pbuf, norm, stat)
     759              : 
     760            0 :             qbuf => fft_scratch%p4buf
     761              : 
     762            0 :             IF (test) THEN
     763            0 :                sum_data = ABS(SUM(pbuf))
     764            0 :                CALL rs_group%sum(sum_data)
     765            0 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     766            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(2) TS", sum_data
     767              :                END IF
     768              :             END IF
     769              : 
     770              :             ! Exchange data ( transpose of matrix ) and sort
     771              :             CALL yz_to_xz(pbuf, rs_group, r_dim, g_pos, p2p, yzp, nyzray, &
     772            0 :                           bo(:, :, :, 2), qbuf, fft_scratch)
     773              : 
     774            0 :             IF (test) THEN
     775            0 :                sum_data = ABS(SUM(qbuf))
     776            0 :                CALL rs_group%sum(sum_data)
     777            0 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     778            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(3) TS", sum_data
     779              :                END IF
     780              :             END IF
     781              : 
     782            0 :             rbuf => fft_scratch%p3buf
     783              : 
     784              :             ! FFT along y
     785            0 :             CALL fft_1d(fft_scratch%fft_plan(5), qbuf, rbuf, 1.0_dp, stat)
     786              : 
     787            0 :             pbuf => fft_scratch%p2buf
     788              : 
     789            0 :             IF (test) THEN
     790            0 :                sum_data = ABS(SUM(rbuf))
     791            0 :                CALL rs_group%sum(sum_data)
     792            0 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     793            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(4) T", sum_data
     794              :                END IF
     795              :             END IF
     796              : 
     797              :             ! Exchange data ( transpose of matrix )
     798            0 :             CALL cube_transpose_1(rbuf, bo(:, :, :, 2), bo(:, :, :, 1), pbuf, fft_scratch)
     799              : 
     800            0 :             IF (test) THEN
     801            0 :                sum_data = ABS(SUM(pbuf))
     802            0 :                CALL rs_group%sum(sum_data)
     803            0 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     804            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(5) T", sum_data
     805              :                END IF
     806              :             END IF
     807              : 
     808            0 :             qbuf => fft_scratch%p1buf
     809              : 
     810              :             ! FFT along z
     811            0 :             CALL fft_1d(fft_scratch%fft_plan(6), pbuf, cin, 1.0_dp, stat)
     812              : 
     813            0 :             IF (test) THEN
     814            0 :                sum_data = ABS(SUM(cin))
     815            0 :                CALL rs_group%sum(sum_data)
     816            0 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     817            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(6) ", sum_data
     818              :                END IF
     819              :             END IF
     820              : 
     821              :          ELSE
     822              : 
     823            0 :             CPABORT("Illegal fsign parameter.")
     824              : 
     825              :          END IF
     826              : 
     827            0 :          CALL release_fft_scratch(fft_scratch)
     828              : 
     829              :       ELSE
     830              : 
     831              :          !
     832              :          ! real space is only distributed over x coordinate
     833              :          ! we have one stage of communication, after the transform of
     834              :          ! direction x
     835              :          !
     836              : 
     837      3658909 :          CALL get_fft_scratch(fft_scratch, tf_type=200, n=n, fft_sizes=fft_scratch_size)
     838              : 
     839      3658909 :          sbuf => fft_scratch%r1buf
     840      3658909 :          tbuf => fft_scratch%tbuf
     841              : 
     842      3658909 :          sbuf = z_zero
     843      3658909 :          tbuf = z_zero
     844              : 
     845      3658909 :          IF (sign == FWFFT) THEN
     846              :             ! cin -> gin
     847              : 
     848      1830361 :             IF (test) THEN
     849         9284 :                sum_data = ABS(SUM(cin))
     850            4 :                CALL rs_group%sum(sum_data)
     851            4 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     852            2 :                   WRITE (output_unit, '(A)') "     One step communication algorithm "
     853            2 :                   WRITE (output_unit, '(A,T60,3I7)') "     Transform YZ ", n(2), n(3), nx
     854            2 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform X ", n(1), nyzray(g_pos)
     855            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(1) ", sum_data
     856              :                END IF
     857              :             END IF
     858              : 
     859              :             ! FFT along y and z
     860      1830361 :             CALL fft_1d(fft_scratch%fft_plan(1), cin, sbuf, 1._dp, stat)
     861      1830361 :             CALL fft_1d(fft_scratch%fft_plan(2), sbuf, tbuf, 1._dp, stat)
     862              : 
     863      1830361 :             IF (test) THEN
     864         8740 :                sum_data = ABS(SUM(tbuf))
     865            4 :                CALL rs_group%sum(sum_data)
     866            4 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     867            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(2) TS", sum_data
     868              :                END IF
     869              :             END IF
     870              : 
     871              :             ! Exchange data ( transpose of matrix ) and sort
     872              :             CALL yz_to_x(tbuf, rs_group, g_pos, p2p, yzp, nyzray, &
     873      1830361 :                          bo(:, :, :, 2), sbuf, fft_scratch)
     874              : 
     875      1830361 :             IF (test) THEN
     876         8776 :                sum_data = ABS(SUM(sbuf))
     877            4 :                CALL rs_group%sum(sum_data)
     878            4 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     879            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(3) TS", sum_data
     880              :                END IF
     881              :             END IF
     882              :             ! FFT along x
     883      1830361 :             CALL fft_1d(fft_scratch%fft_plan(3), sbuf, gin, norm, stat)
     884              : 
     885      1830361 :             IF (test) THEN
     886         8708 :                sum_data = ABS(SUM(gin))
     887            4 :                CALL rs_group%sum(sum_data)
     888            4 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     889            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(4) ", sum_data
     890              :                END IF
     891              :             END IF
     892              : 
     893      1828548 :          ELSE IF (sign == BWFFT) THEN
     894              :             ! gin -> cin
     895              : 
     896      1828548 :             IF (test) THEN
     897         8708 :                sum_data = ABS(SUM(gin))
     898            4 :                CALL rs_group%sum(sum_data)
     899            4 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     900            2 :                   WRITE (output_unit, '(A)') "  One step communication algorithm "
     901            2 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform X ", n(1), nyzray(g_pos)
     902            2 :                   WRITE (output_unit, '(A,T60,3I7)') "     Transform YZ ", n(2), n(3), nx
     903            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(1) ", sum_data
     904              :                END IF
     905              :             END IF
     906              : 
     907              :             ! FFT along x
     908      1828548 :             CALL fft_1d(fft_scratch%fft_plan(4), gin, sbuf, norm, stat)
     909              : 
     910      1828548 :             IF (test) THEN
     911         8776 :                sum_data = ABS(SUM(sbuf))
     912            4 :                CALL rs_group%sum(sum_data)
     913            4 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     914            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(2) TS", sum_data
     915              :                END IF
     916              :             END IF
     917              : 
     918              :             ! Exchange data ( transpose of matrix ) and sort
     919              :             CALL x_to_yz(sbuf, rs_group, g_pos, p2p, yzp, nyzray, &
     920      1828548 :                          bo(:, :, :, 2), tbuf, fft_scratch)
     921              : 
     922      1828548 :             IF (test) THEN
     923         8740 :                sum_data = ABS(SUM(tbuf))
     924            4 :                CALL rs_group%sum(sum_data)
     925            4 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     926            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(3) TS", sum_data
     927              :                END IF
     928              :             END IF
     929              : 
     930              :             ! FFT along y and z
     931      1828548 :             CALL fft_1d(fft_scratch%fft_plan(5), tbuf, sbuf, 1._dp, stat)
     932      1828548 :             CALL fft_1d(fft_scratch%fft_plan(6), sbuf, cin, 1._dp, stat)
     933              : 
     934      1828548 :             IF (test) THEN
     935         9284 :                sum_data = ABS(SUM(cin))
     936            4 :                CALL rs_group%sum(sum_data)
     937            4 :                IF (g_pos == 0 .AND. output_unit > 0) THEN
     938            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(4) ", sum_data
     939              :                END IF
     940              :             END IF
     941              :          ELSE
     942            0 :             CPABORT("Illegal fsign parameter.")
     943              :          END IF
     944              : 
     945      3658909 :          CALL release_fft_scratch(fft_scratch)
     946              : 
     947              :       END IF
     948              : 
     949      3658909 :       DEALLOCATE (p2p)
     950              : 
     951      3658909 :       IF (PRESENT(status)) THEN
     952            0 :          status = stat
     953              :       END IF
     954      3658909 :       CALL timestop(handle)
     955              : 
     956      7317818 :    END SUBROUTINE fft3d_ps
     957              : 
     958              : ! **************************************************************************************************
     959              : !> \brief ...
     960              : !> \param fsign ...
     961              : !> \param n ...
     962              : !> \param zin ...
     963              : !> \param gin ...
     964              : !> \param group ...
     965              : !> \param bo ...
     966              : !> \param status ...
     967              : !> \param debug ...
     968              : ! **************************************************************************************************
     969          208 :    SUBROUTINE fft3d_pb(fsign, n, zin, gin, group, bo, status, debug)
     970              : 
     971              :       INTEGER, INTENT(IN)                                :: fsign
     972              :       INTEGER, DIMENSION(3), INTENT(IN)                  :: n
     973              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :, :), &
     974              :          INTENT(INOUT)                                   :: zin
     975              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     976              :          INTENT(INOUT)                                   :: gin
     977              :       TYPE(mp_cart_type), INTENT(IN)                     :: group
     978              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:, :), &
     979              :          INTENT(IN)                                      :: bo
     980              :       INTEGER, INTENT(OUT), OPTIONAL                     :: status
     981              :       LOGICAL, INTENT(IN), OPTIONAL                      :: debug
     982              : 
     983              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'fft3d_pb'
     984              : 
     985              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     986          208 :          POINTER                                         :: abuf, bbuf
     987              :       INTEGER                                            :: handle, lg(2), lz(3), mcx2, mcy3, mcz1, &
     988              :                                                             mcz2, mx1, mx2, mx3, my1, my2, my3, &
     989              :                                                             my_pos, mz1, mz2, mz3, output_unit, &
     990              :                                                             sign, stat
     991              :       INTEGER, DIMENSION(2)                              :: dim
     992              :       LOGICAL                                            :: test
     993              :       REAL(KIND=dp)                                      :: norm, sum_data
     994         1456 :       TYPE(fft_scratch_sizes)                            :: fft_scratch_size
     995              :       TYPE(fft_scratch_type), POINTER                    :: fft_scratch
     996              : 
     997              : !------------------------------------------------------------------------------
     998              : ! "Real Space"  1) xyZ      or      1) xYZ
     999              : !               2) xYz      or         not used
    1000              : ! "G Space"     3) Xyz      or      3) XYz
    1001              : !
    1002              : ! There is one communicator (2-dimensional) for all distributions
    1003              : ! np = n1 * n2, where np is the total number of processors
    1004              : ! If n2 = 1, we have the second case and only one transpose step is needed
    1005              : !
    1006              : ! Assignment of dimensions to axis for different steps
    1007              : ! First case: 1) n1=x; n2=y
    1008              : !             2) n1=x; n2=z
    1009              : !             3) n1=y; n2=z
    1010              : ! Second case 1) n1=x
    1011              : !             3) n1=z
    1012              : !
    1013              : ! The more general case with two communicators for the initial and final
    1014              : ! distribution is not covered.
    1015              : !------------------------------------------------------------------------------
    1016              : 
    1017          208 :       CALL timeset(routineN, handle)
    1018          208 :       output_unit = cp_logger_get_default_io_unit()
    1019              : 
    1020          624 :       dim = group%num_pe_cart
    1021          208 :       my_pos = group%mepos
    1022              : 
    1023          208 :       IF (PRESENT(debug)) THEN
    1024          208 :          test = debug
    1025              :       ELSE
    1026              :          test = .FALSE.
    1027              :       END IF
    1028              : 
    1029          208 :       IF (fsign == FWFFT) THEN
    1030          416 :          norm = 1.0_dp/REAL(PRODUCT(n), KIND=dp)
    1031          104 :       ELSE IF (fsign == BWFFT) THEN
    1032          104 :          norm = 1.0_dp
    1033              :       ELSE
    1034            0 :          CPABORT("Unknown FFT direction!")
    1035              :       END IF
    1036              : 
    1037          208 :       sign = fsign
    1038              : 
    1039          208 :       IF (test) THEN
    1040            8 :          lg(1) = SIZE(gin, 1)
    1041            8 :          lg(2) = SIZE(gin, 2)
    1042            8 :          lz(1) = SIZE(zin, 1)
    1043            8 :          lz(2) = SIZE(zin, 2)
    1044            8 :          lz(3) = SIZE(zin, 3)
    1045            8 :          IF (my_pos == 0 .AND. output_unit > 0) THEN
    1046            4 :             WRITE (output_unit, '(A)') "  Parallel 3D FFT : fft3d_pb"
    1047            4 :             WRITE (output_unit, '(A,T60,3I7)') "     Transform lengths ", n
    1048            4 :             WRITE (output_unit, '(A,T67,2I7)') "     Array dimensions (gin) ", lg
    1049            4 :             WRITE (output_unit, '(A,T60,3I7)') "     Array dimensions (cin) ", lz
    1050              :          END IF
    1051              :       END IF
    1052              : 
    1053          208 :       mx1 = bo(2, 1, my_pos, 1) - bo(1, 1, my_pos, 1) + 1
    1054          208 :       my1 = bo(2, 2, my_pos, 1) - bo(1, 2, my_pos, 1) + 1
    1055          208 :       mz1 = bo(2, 3, my_pos, 1) - bo(1, 3, my_pos, 1) + 1
    1056          208 :       mx2 = bo(2, 1, my_pos, 2) - bo(1, 1, my_pos, 2) + 1
    1057          208 :       my2 = bo(2, 2, my_pos, 2) - bo(1, 2, my_pos, 2) + 1
    1058          208 :       mz2 = bo(2, 3, my_pos, 2) - bo(1, 3, my_pos, 2) + 1
    1059          208 :       mx3 = bo(2, 1, my_pos, 3) - bo(1, 1, my_pos, 3) + 1
    1060          208 :       my3 = bo(2, 2, my_pos, 3) - bo(1, 2, my_pos, 3) + 1
    1061          208 :       mz3 = bo(2, 3, my_pos, 3) - bo(1, 3, my_pos, 3) + 1
    1062          208 :       fft_scratch_size%mx1 = mx1
    1063          208 :       fft_scratch_size%mx2 = mx2
    1064          208 :       fft_scratch_size%mx3 = mx3
    1065          208 :       fft_scratch_size%my1 = my1
    1066          208 :       fft_scratch_size%my2 = my2
    1067          208 :       fft_scratch_size%my3 = my3
    1068          208 :       fft_scratch_size%mz1 = mz1
    1069          208 :       fft_scratch_size%mz2 = mz2
    1070          208 :       fft_scratch_size%mz3 = mz3
    1071          624 :       mcz1 = MAXVAL(bo(2, 3, :, 1) - bo(1, 3, :, 1) + 1)
    1072          624 :       mcx2 = MAXVAL(bo(2, 1, :, 2) - bo(1, 1, :, 2) + 1)
    1073          624 :       mcz2 = MAXVAL(bo(2, 3, :, 2) - bo(1, 3, :, 2) + 1)
    1074          624 :       mcy3 = MAXVAL(bo(2, 2, :, 3) - bo(1, 2, :, 3) + 1)
    1075          208 :       fft_scratch_size%mcz1 = mcz1
    1076          208 :       fft_scratch_size%mcx2 = mcx2
    1077          208 :       fft_scratch_size%mcz2 = mcz2
    1078          208 :       fft_scratch_size%mcy3 = mcy3
    1079          208 :       fft_scratch_size%rs_group = group
    1080          624 :       fft_scratch_size%g_pos = my_pos
    1081          208 :       fft_scratch_size%numtask = DIM(1)*DIM(2)
    1082              : 
    1083          208 :       IF (DIM(1) > 1 .AND. DIM(2) > 1) THEN
    1084              : 
    1085              :          !
    1086              :          ! First case; two stages of communication
    1087              :          !
    1088              : 
    1089            0 :          CALL get_fft_scratch(fft_scratch, tf_type=100, n=n, fft_sizes=fft_scratch_size)
    1090              : 
    1091            0 :          IF (sign == FWFFT) THEN
    1092              :             ! Stage 1 -> 3
    1093              : 
    1094            0 :             bbuf => fft_scratch%a2buf
    1095              : 
    1096            0 :             IF (test) THEN
    1097            0 :                sum_data = ABS(SUM(zin))
    1098            0 :                CALL group%sum(sum_data)
    1099            0 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1100            0 :                   WRITE (output_unit, '(A)') "  Two step communication algorithm "
    1101            0 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform Z ", n(3), mx1*my1
    1102            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(1) ", sum_data
    1103              :                END IF
    1104              :             END IF
    1105              : 
    1106              :             ! FFT along z
    1107            0 :             CALL fft_1d(fft_scratch%fft_plan(1), zin, bbuf, norm, stat)
    1108              : 
    1109            0 :             abuf => fft_scratch%a3buf
    1110              : 
    1111            0 :             IF (test) THEN
    1112            0 :                sum_data = ABS(SUM(bbuf))
    1113            0 :                CALL group%sum(sum_data)
    1114            0 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1115            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(2) T", sum_data
    1116              :                END IF
    1117              :             END IF
    1118              : 
    1119            0 :             CALL cube_transpose_2(bbuf, bo(:, :, :, 1), bo(:, :, :, 2), abuf, fft_scratch)
    1120              : 
    1121            0 :             bbuf => fft_scratch%a4buf
    1122              : 
    1123            0 :             IF (test) THEN
    1124            0 :                sum_data = ABS(SUM(abuf))
    1125            0 :                CALL group%sum(sum_data)
    1126            0 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1127            0 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform Y ", n(2), mx2*mz2
    1128            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(3) ", sum_data
    1129              :                END IF
    1130              :             END IF
    1131              : 
    1132              :             ! FFT along y
    1133            0 :             CALL fft_1d(fft_scratch%fft_plan(2), abuf, bbuf, 1.0_dp, stat)
    1134              : 
    1135            0 :             abuf => fft_scratch%a5buf
    1136              : 
    1137            0 :             IF (test) THEN
    1138            0 :                sum_data = ABS(SUM(bbuf))
    1139            0 :                CALL group%sum(sum_data)
    1140            0 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1141            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(4) T", sum_data
    1142              :                END IF
    1143              :             END IF
    1144              : 
    1145            0 :             CALL cube_transpose_4(bbuf, bo(:, :, :, 2), bo(:, :, :, 3), abuf, fft_scratch)
    1146              : 
    1147            0 :             IF (test) THEN
    1148            0 :                sum_data = ABS(SUM(abuf))
    1149            0 :                CALL group%sum(sum_data)
    1150            0 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1151            0 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform X ", n(1), my3*mz3
    1152            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(5) ", sum_data
    1153              :                END IF
    1154              :             END IF
    1155              : 
    1156              :             ! FFT along x
    1157            0 :             CALL fft_1d(fft_scratch%fft_plan(3), abuf, gin, 1.0_dp, stat)
    1158              : 
    1159            0 :             IF (test) THEN
    1160            0 :                sum_data = ABS(SUM(gin))
    1161            0 :                CALL group%sum(sum_data)
    1162            0 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1163            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(6) ", sum_data
    1164              :                END IF
    1165              :             END IF
    1166              : 
    1167            0 :          ELSE IF (sign == BWFFT) THEN
    1168              :             ! Stage 3 -> 1
    1169              : 
    1170            0 :             bbuf => fft_scratch%a5buf
    1171              : 
    1172            0 :             IF (test) THEN
    1173            0 :                sum_data = ABS(SUM(gin))
    1174            0 :                CALL group%sum(sum_data)
    1175            0 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1176            0 :                   WRITE (output_unit, '(A)') "  Two step communication algorithm "
    1177            0 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform X ", n(1), my3*mz3
    1178            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(1) ", sum_data
    1179              :                END IF
    1180              :             END IF
    1181              : 
    1182              :             ! FFT along x
    1183            0 :             CALL fft_1d(fft_scratch%fft_plan(4), gin, bbuf, 1.0_dp, stat)
    1184              : 
    1185            0 :             abuf => fft_scratch%a4buf
    1186              : 
    1187            0 :             IF (test) THEN
    1188            0 :                sum_data = ABS(SUM(bbuf))
    1189            0 :                CALL group%sum(sum_data)
    1190            0 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1191            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(2) T", sum_data
    1192              :                END IF
    1193              :             END IF
    1194              : 
    1195            0 :             CALL cube_transpose_3(bbuf, bo(:, :, :, 3), bo(:, :, :, 2), abuf, fft_scratch)
    1196              : 
    1197            0 :             bbuf => fft_scratch%a3buf
    1198              : 
    1199            0 :             IF (test) THEN
    1200            0 :                sum_data = ABS(SUM(abuf))
    1201            0 :                CALL group%sum(sum_data)
    1202            0 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1203            0 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform Y ", n(2), mx2*mz2
    1204            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(3) ", sum_data
    1205              :                END IF
    1206              :             END IF
    1207              : 
    1208              :             ! FFT along y
    1209            0 :             CALL fft_1d(fft_scratch%fft_plan(5), abuf, bbuf, 1.0_dp, stat)
    1210              : 
    1211            0 :             abuf => fft_scratch%a2buf
    1212              : 
    1213            0 :             IF (test) THEN
    1214            0 :                sum_data = ABS(SUM(bbuf))
    1215            0 :                CALL group%sum(sum_data)
    1216            0 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1217            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(4) T", sum_data
    1218              :                END IF
    1219              :             END IF
    1220              : 
    1221            0 :             CALL cube_transpose_1(bbuf, bo(:, :, :, 2), bo(:, :, :, 1), abuf, fft_scratch)
    1222              : 
    1223            0 :             IF (test) THEN
    1224            0 :                sum_data = ABS(SUM(abuf))
    1225            0 :                CALL group%sum(sum_data)
    1226            0 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1227            0 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform Z ", n(3), mx1*my1
    1228            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(5) ", sum_data
    1229              :                END IF
    1230              :             END IF
    1231              : 
    1232              :             ! FFT along z
    1233            0 :             CALL fft_1d(fft_scratch%fft_plan(6), abuf, zin, norm, stat)
    1234              : 
    1235            0 :             IF (test) THEN
    1236            0 :                sum_data = ABS(SUM(zin))
    1237            0 :                CALL group%sum(sum_data)
    1238            0 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1239            0 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(6) ", sum_data
    1240              :                END IF
    1241              :             END IF
    1242              : 
    1243              :          ELSE
    1244            0 :             CPABORT("Illegal fsign parameter.")
    1245              :          END IF
    1246              : 
    1247            0 :          CALL release_fft_scratch(fft_scratch)
    1248              : 
    1249          208 :       ELSE IF (DIM(2) == 1) THEN
    1250              : 
    1251              :          !
    1252              :          ! Second case; one stage of communication
    1253              :          !
    1254              : 
    1255          208 :          CALL get_fft_scratch(fft_scratch, tf_type=101, n=n, fft_sizes=fft_scratch_size)
    1256              : 
    1257          208 :          IF (sign == FWFFT) THEN
    1258              :             ! Stage 1 -> 3
    1259              : 
    1260          104 :             IF (test) THEN
    1261         9284 :                sum_data = ABS(SUM(zin))
    1262            4 :                CALL group%sum(sum_data)
    1263            4 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1264            2 :                   WRITE (output_unit, '(A)') "  one step communication algorithm "
    1265            2 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform Z ", n(3), mx1*my1
    1266            2 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform Y ", n(2), mx1*mz1
    1267            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(1) ", sum_data
    1268              :                END IF
    1269              :             END IF
    1270              : 
    1271          104 :             abuf => fft_scratch%a3buf
    1272          104 :             bbuf => fft_scratch%a4buf
    1273              :             ! FFT along z and y
    1274          104 :             CALL fft_1d(fft_scratch%fft_plan(1), zin, abuf, norm, stat)
    1275          104 :             CALL fft_1d(fft_scratch%fft_plan(2), abuf, bbuf, 1.0_dp, stat)
    1276              : 
    1277          104 :             abuf => fft_scratch%a5buf
    1278              : 
    1279          104 :             IF (test) THEN
    1280         8708 :                sum_data = ABS(SUM(bbuf))
    1281            4 :                CALL group%sum(sum_data)
    1282            4 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1283            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(2) T", sum_data
    1284              :                END IF
    1285              :             END IF
    1286              : 
    1287          104 :             CALL cube_transpose_6(bbuf, group, bo(:, :, :, 1), bo(:, :, :, 3), abuf, fft_scratch)
    1288              : 
    1289          104 :             IF (test) THEN
    1290         8260 :                sum_data = ABS(SUM(abuf))
    1291            4 :                CALL group%sum(sum_data)
    1292            4 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1293            2 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform X ", n(1), my3*mz3
    1294            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(3) ", sum_data
    1295              :                END IF
    1296              :             END IF
    1297              : 
    1298              :             ! FFT along x
    1299          104 :             CALL fft_1d(fft_scratch%fft_plan(3), abuf, gin, 1.0_dp, stat)
    1300              : 
    1301          104 :             IF (test) THEN
    1302         8708 :                sum_data = ABS(SUM(gin))
    1303            4 :                CALL group%sum(sum_data)
    1304            4 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1305            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(4) ", sum_data
    1306              :                END IF
    1307              :             END IF
    1308              : 
    1309          104 :          ELSE IF (sign == BWFFT) THEN
    1310              :             ! Stage 3 -> 1
    1311              : 
    1312          104 :             IF (test) THEN
    1313         8708 :                sum_data = ABS(SUM(gin))
    1314            4 :                CALL group%sum(sum_data)
    1315            4 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1316            2 :                   WRITE (output_unit, '(A)') "  one step communication algorithm "
    1317            2 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform X ", n(1), my3*mz3
    1318            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(1) ", sum_data
    1319              :                END IF
    1320              :             END IF
    1321              : 
    1322          104 :             bbuf => fft_scratch%a5buf
    1323              : 
    1324              :             ! FFT along x
    1325          104 :             CALL fft_1d(fft_scratch%fft_plan(4), gin, bbuf, 1.0_dp, stat)
    1326              : 
    1327          104 :             abuf => fft_scratch%a4buf
    1328              : 
    1329          104 :             IF (test) THEN
    1330         8260 :                sum_data = ABS(SUM(bbuf))
    1331            4 :                CALL group%sum(sum_data)
    1332            4 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1333            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(2) T", sum_data
    1334              :                END IF
    1335              :             END IF
    1336              : 
    1337          104 :             CALL cube_transpose_5(bbuf, group, bo(:, :, :, 3), bo(:, :, :, 1), abuf, fft_scratch)
    1338              : 
    1339          104 :             bbuf => fft_scratch%a3buf
    1340              : 
    1341          104 :             IF (test) THEN
    1342         8708 :                sum_data = ABS(SUM(abuf))
    1343            4 :                CALL group%sum(sum_data)
    1344            4 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1345            2 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform Y ", n(2), mx1*mz1
    1346            2 :                   WRITE (output_unit, '(A,T67,2I7)') "     Transform Z ", n(3), mx1*my1
    1347            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(3) ", sum_data
    1348              :                END IF
    1349              :             END IF
    1350              : 
    1351              :             ! FFT along y
    1352          104 :             CALL fft_1d(fft_scratch%fft_plan(5), abuf, bbuf, 1.0_dp, stat)
    1353              : 
    1354              :             ! FFT along z
    1355          104 :             CALL fft_1d(fft_scratch%fft_plan(6), bbuf, zin, norm, stat)
    1356              : 
    1357          104 :             IF (test) THEN
    1358         9284 :                sum_data = ABS(SUM(zin))
    1359            4 :                CALL group%sum(sum_data)
    1360            4 :                IF (my_pos == 0 .AND. output_unit > 0) THEN
    1361            2 :                   WRITE (output_unit, '(A,T61,E20.14)') "     Sum of data(4) ", sum_data
    1362              :                END IF
    1363              :             END IF
    1364              : 
    1365              :          ELSE
    1366            0 :             CPABORT("Illegal fsign parameter.")
    1367              :          END IF
    1368              : 
    1369          208 :          CALL release_fft_scratch(fft_scratch)
    1370              : 
    1371              :       ELSE
    1372              : 
    1373            0 :          CPABORT("Partition not implemented.")
    1374              : 
    1375              :       END IF
    1376              : 
    1377          208 :       IF (PRESENT(status)) THEN
    1378            0 :          status = stat
    1379              :       END IF
    1380              : 
    1381          208 :       CALL timestop(handle)
    1382              : 
    1383          416 :    END SUBROUTINE fft3d_pb
    1384              : 
    1385              : ! **************************************************************************************************
    1386              : !> \brief ...
    1387              : !> \param sb ...
    1388              : !> \param group ...
    1389              : !> \param my_pos ...
    1390              : !> \param p2p ...
    1391              : !> \param yzp ...
    1392              : !> \param nray ...
    1393              : !> \param bo ...
    1394              : !> \param tb ...
    1395              : !> \param fft_scratch ...
    1396              : !> \par History
    1397              : !>      15. Feb. 2006 : single precision all_to_all
    1398              : !> \author JGH (14-Jan-2001)
    1399              : ! **************************************************************************************************
    1400      1828548 :    SUBROUTINE x_to_yz(sb, group, my_pos, p2p, yzp, nray, bo, tb, fft_scratch)
    1401              : 
    1402              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    1403              :          INTENT(IN)                                      :: sb
    1404              : 
    1405              :       CLASS(mp_comm_type), INTENT(IN)                    :: group
    1406              :       INTEGER, INTENT(IN)                                :: my_pos
    1407              :       INTEGER, CONTIGUOUS, DIMENSION(0:), INTENT(IN)     :: p2p
    1408              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), &
    1409              :          INTENT(IN)                                      :: yzp
    1410              :       INTEGER, CONTIGUOUS, DIMENSION(0:), INTENT(IN)     :: nray
    1411              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), &
    1412              :          INTENT(IN)                                      :: bo
    1413              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :, :), &
    1414              :          INTENT(INOUT)                                   :: tb
    1415              :       TYPE(fft_scratch_type), INTENT(IN)                 :: fft_scratch
    1416              : 
    1417              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'x_to_yz'
    1418              : 
    1419              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    1420      1828548 :          POINTER                                         :: rr
    1421              :       COMPLEX(KIND=sp), CONTIGUOUS, DIMENSION(:, :), &
    1422      1828548 :          POINTER                                         :: ss, tt
    1423              :       INTEGER                                            :: handle, ip, ir, ix, ixx, iy, iz, mpr, &
    1424              :                                                             nm, np, nr, nx
    1425      1828548 :       INTEGER, CONTIGUOUS, DIMENSION(:), POINTER         :: rcount, rdispl, scount, sdispl
    1426              : 
    1427      1828548 :       CALL timeset(routineN, handle)
    1428              : 
    1429      1828548 :       np = SIZE(p2p)
    1430      1828548 :       scount => fft_scratch%scount
    1431      1828548 :       rcount => fft_scratch%rcount
    1432      1828548 :       sdispl => fft_scratch%sdispl
    1433      1828548 :       rdispl => fft_scratch%rdispl
    1434              : 
    1435      1828548 :       IF (alltoall_sgl) THEN
    1436          230 :          ss => fft_scratch%ss
    1437          230 :          tt => fft_scratch%tt
    1438      3441099 :          ss(:, :) = CMPLX(sb(:, :), KIND=sp)
    1439          230 :          tt(:, :) = 0._sp
    1440              :       ELSE
    1441      1828318 :          rr => fft_scratch%rr
    1442              :       END IF
    1443              : 
    1444      1828548 :       mpr = p2p(my_pos)
    1445      5485644 :       nm = MAXVAL(nray(0:np - 1))
    1446      1828548 :       nr = nray(my_pos)
    1447              : !$OMP PARALLEL DO DEFAULT(NONE), &
    1448              : !$OMP             PRIVATE(ix,nx), &
    1449      1828548 : !$OMP             SHARED(np,p2p,bo,nr,scount,sdispl)
    1450              :       DO ip = 0, np - 1
    1451              :          ix = p2p(ip)
    1452              :          nx = bo(2, 1, ix) - bo(1, 1, ix) + 1
    1453              :          scount(ip) = nr*nx
    1454              :          sdispl(ip) = nr*(bo(1, 1, ix) - 1)
    1455              :       END DO
    1456              : !$OMP END PARALLEL DO
    1457      1828548 :       nx = bo(2, 1, mpr) - bo(1, 1, mpr) + 1
    1458              : !$OMP PARALLEL DO DEFAULT(NONE), &
    1459              : !$OMP             PRIVATE(nr), &
    1460      1828548 : !$OMP             SHARED(np,nray,nx,rcount,rdispl,nm)
    1461              :       DO ip = 0, np - 1
    1462              :          nr = nray(ip)
    1463              :          rcount(ip) = nr*nx
    1464              :          rdispl(ip) = nm*nx*ip
    1465              :       END DO
    1466              : !$OMP END PARALLEL DO
    1467      1828548 :       IF (alltoall_sgl) THEN
    1468          230 :          CALL group%alltoall(ss, scount, sdispl, tt, rcount, rdispl)
    1469              :       ELSE
    1470      1828318 :          CALL group%alltoall(sb, scount, sdispl, rr, rcount, rdispl)
    1471              :       END IF
    1472              : 
    1473      1828548 :       nx = bo(2, 1, mpr) - bo(1, 1, mpr) + 1
    1474              : !$OMP PARALLEL DO DEFAULT(NONE) COLLAPSE(2) &
    1475              : !$OMP             PRIVATE(ixx,ir,iy,iz,ix) &
    1476      1828548 : !$OMP             SHARED(np,nray,nx,alltoall_sgl,yzp,tt,rr,tb)
    1477              :       DO ip = 0, np - 1
    1478              :          DO ix = 1, nx
    1479              :             ixx = nray(ip)*(ix - 1)
    1480              :             IF (alltoall_sgl) THEN
    1481              :                DO ir = 1, nray(ip)
    1482              :                   iy = yzp(1, ir, ip)
    1483              :                   iz = yzp(2, ir, ip)
    1484              :                   tb(iy, iz, ix) = tt(ir + ixx, ip)
    1485              :                END DO
    1486              :             ELSE
    1487              :                DO ir = 1, nray(ip)
    1488              :                   iy = yzp(1, ir, ip)
    1489              :                   iz = yzp(2, ir, ip)
    1490              :                   tb(iy, iz, ix) = rr(ir + ixx, ip)
    1491              :                END DO
    1492              :             END IF
    1493              :          END DO
    1494              :       END DO
    1495              : !$OMP END PARALLEL DO
    1496              : 
    1497      1828548 :       CALL timestop(handle)
    1498              : 
    1499      1828548 :    END SUBROUTINE x_to_yz
    1500              : 
    1501              : ! **************************************************************************************************
    1502              : !> \brief ...
    1503              : !> \param tb ...
    1504              : !> \param group ...
    1505              : !> \param my_pos ...
    1506              : !> \param p2p ...
    1507              : !> \param yzp ...
    1508              : !> \param nray ...
    1509              : !> \param bo ...
    1510              : !> \param sb ...
    1511              : !> \param fft_scratch ...
    1512              : !> \par History
    1513              : !>      15. Feb. 2006 : single precision all_to_all
    1514              : !> \author JGH (14-Jan-2001)
    1515              : ! **************************************************************************************************
    1516      1830361 :    SUBROUTINE yz_to_x(tb, group, my_pos, p2p, yzp, nray, bo, sb, fft_scratch)
    1517              : 
    1518              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :, :), &
    1519              :          INTENT(IN)                                      :: tb
    1520              : 
    1521              :       CLASS(mp_comm_type), INTENT(IN)                    :: group
    1522              :       INTEGER, INTENT(IN)                                :: my_pos
    1523              :       INTEGER, CONTIGUOUS, DIMENSION(0:), INTENT(IN)     :: p2p
    1524              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), &
    1525              :          INTENT(IN)                                      :: yzp
    1526              :       INTEGER, CONTIGUOUS, DIMENSION(0:), INTENT(IN)     :: nray
    1527              :       INTEGER, DIMENSION(:, :, 0:), INTENT(IN)           :: bo
    1528              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    1529              :          INTENT(INOUT)                                   :: sb
    1530              :       TYPE(fft_scratch_type), INTENT(IN)                 :: fft_scratch
    1531              : 
    1532              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'yz_to_x'
    1533              : 
    1534              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    1535      1830361 :          POINTER                                         :: rr
    1536              :       COMPLEX(KIND=sp), CONTIGUOUS, DIMENSION(:, :), &
    1537      1830361 :          POINTER                                         :: ss, tt
    1538              :       INTEGER                                            :: handle, ip, ir, ix, ixx, iy, iz, mpr, &
    1539              :                                                             nm, np, nr, nx
    1540      1830361 :       INTEGER, CONTIGUOUS, DIMENSION(:), POINTER         :: rcount, rdispl, scount, sdispl
    1541              : 
    1542      1830361 :       CALL timeset(routineN, handle)
    1543              : 
    1544      1830361 :       np = SIZE(p2p)
    1545      1830361 :       mpr = p2p(my_pos)
    1546      1830361 :       scount => fft_scratch%scount
    1547      1830361 :       rcount => fft_scratch%rcount
    1548      1830361 :       sdispl => fft_scratch%sdispl
    1549      1830361 :       rdispl => fft_scratch%rdispl
    1550              : 
    1551      1830361 :       IF (alltoall_sgl) THEN
    1552          238 :          ss => fft_scratch%ss
    1553          238 :          tt => fft_scratch%tt
    1554          238 :          ss = 0._sp
    1555          238 :          tt = 0._sp
    1556              :       ELSE
    1557      1830123 :          rr => fft_scratch%rr
    1558              :       END IF
    1559              : 
    1560      1830361 :       nx = bo(2, 1, mpr) - bo(1, 1, mpr) + 1
    1561              : !$OMP PARALLEL DO DEFAULT(NONE) COLLAPSE(2) &
    1562              : !$OMP             PRIVATE(ip, ixx, ir, iy, iz, ix) &
    1563      1830361 : !$OMP             SHARED(np,nray,nx,alltoall_sgl,yzp,tb,tt,rr)
    1564              :       DO ip = 0, np - 1
    1565              :          DO ix = 1, nx
    1566              :             ixx = nray(ip)*(ix - 1)
    1567              :             IF (alltoall_sgl) THEN
    1568              :                DO ir = 1, nray(ip)
    1569              :                   iy = yzp(1, ir, ip)
    1570              :                   iz = yzp(2, ir, ip)
    1571              :                   tt(ir + ixx, ip) = CMPLX(tb(iy, iz, ix), KIND=sp)
    1572              :                END DO
    1573              :             ELSE
    1574              :                DO ir = 1, nray(ip)
    1575              :                   iy = yzp(1, ir, ip)
    1576              :                   iz = yzp(2, ir, ip)
    1577              :                   rr(ir + ixx, ip) = tb(iy, iz, ix)
    1578              :                END DO
    1579              :             END IF
    1580              :          END DO
    1581              :       END DO
    1582              : !$OMP END PARALLEL DO
    1583      5491083 :       nm = MAXVAL(nray(0:np - 1))
    1584      1830361 :       nr = nray(my_pos)
    1585              : !$OMP PARALLEL DO DEFAULT(NONE), &
    1586              : !$OMP             PRIVATE(ix,nx), &
    1587      1830361 : !$OMP             SHARED(np,p2p,bo,rcount,rdispl,nr)
    1588              :       DO ip = 0, np - 1
    1589              :          ix = p2p(ip)
    1590              :          nx = bo(2, 1, ix) - bo(1, 1, ix) + 1
    1591              :          rcount(ip) = nr*nx
    1592              :          rdispl(ip) = nr*(bo(1, 1, ix) - 1)
    1593              :       END DO
    1594              : !$OMP END PARALLEL DO
    1595      1830361 :       nx = bo(2, 1, mpr) - bo(1, 1, mpr) + 1
    1596              : !$OMP PARALLEL DO DEFAULT(NONE), &
    1597              : !$OMP             PRIVATE(nr), &
    1598      1830361 : !$OMP             SHARED(np,nray,scount,sdispl,nx,nm)
    1599              :       DO ip = 0, np - 1
    1600              :          nr = nray(ip)
    1601              :          scount(ip) = nr*nx
    1602              :          sdispl(ip) = nm*nx*ip
    1603              :       END DO
    1604              : !$OMP END PARALLEL DO
    1605              : 
    1606      1830361 :       IF (alltoall_sgl) THEN
    1607          238 :          CALL group%alltoall(tt, scount, sdispl, ss, rcount, rdispl)
    1608      3703835 :          sb = ss
    1609              :       ELSE
    1610      1830123 :          CALL group%alltoall(rr, scount, sdispl, sb, rcount, rdispl)
    1611              :       END IF
    1612              : 
    1613      1830361 :       CALL timestop(handle)
    1614              : 
    1615      1830361 :    END SUBROUTINE yz_to_x
    1616              : 
    1617              : ! **************************************************************************************************
    1618              : !> \brief ...
    1619              : !> \param sb ...
    1620              : !> \param group ...
    1621              : !> \param dims ...
    1622              : !> \param my_pos ...
    1623              : !> \param p2p ...
    1624              : !> \param yzp ...
    1625              : !> \param nray ...
    1626              : !> \param bo ...
    1627              : !> \param tb ...
    1628              : !> \param fft_scratch ...
    1629              : !> \par History
    1630              : !>      15. Feb. 2006 : single precision all_to_all
    1631              : !> \author JGH (18-Jan-2001)
    1632              : ! **************************************************************************************************
    1633            0 :    SUBROUTINE yz_to_xz(sb, group, dims, my_pos, p2p, yzp, nray, bo, tb, fft_scratch)
    1634              : 
    1635              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    1636              :          INTENT(IN)                                      :: sb
    1637              : 
    1638              :       CLASS(mp_comm_type), INTENT(IN)                    :: group
    1639              :       INTEGER, DIMENSION(2), INTENT(IN)                  :: dims
    1640              :       INTEGER, INTENT(IN)                                :: my_pos
    1641              :       INTEGER, CONTIGUOUS, DIMENSION(0:), INTENT(IN)                 :: p2p
    1642              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), INTENT(IN)           :: yzp
    1643              :       INTEGER, CONTIGUOUS, DIMENSION(0:), INTENT(IN)                 :: nray
    1644              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), INTENT(IN)           :: bo
    1645              :       COMPLEX(KIND=dp), DIMENSION(:, :), INTENT(INOUT), CONTIGUOUS   :: tb
    1646              :       TYPE(fft_scratch_type), INTENT(INOUT)              :: fft_scratch
    1647              : 
    1648              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'yz_to_xz'
    1649              : 
    1650            0 :       COMPLEX(KIND=dp), DIMENSION(:), POINTER, CONTIGUOUS            :: xzbuf, yzbuf
    1651            0 :       COMPLEX(KIND=sp), DIMENSION(:), POINTER, CONTIGUOUS            :: xzbuf_sgl, yzbuf_sgl
    1652              :       INTEGER                                            :: handle, icrs, ip, ipl, ipr, ir, ix, iz, &
    1653              :                                                             jj, jx, jy, jz, myx, myz, np, npx, &
    1654              :                                                             npz, nx, nz, rs_pos
    1655            0 :       INTEGER, DIMENSION(:), POINTER, CONTIGUOUS                     :: pzcoord, rcount, rdispl, scount, sdispl, &
    1656            0 :                                                                         xcor, zcor
    1657            0 :       INTEGER, DIMENSION(:, :), CONTIGUOUS, POINTER                  :: pgrid
    1658              : 
    1659            0 :       CALL timeset(routineN, handle)
    1660              : 
    1661            0 :       np = SIZE(p2p)
    1662              : 
    1663            0 :       rs_pos = p2p(my_pos)
    1664              : 
    1665            0 :       IF (alltoall_sgl) THEN
    1666            0 :          yzbuf_sgl => fft_scratch%yzbuf_sgl
    1667            0 :          xzbuf_sgl => fft_scratch%xzbuf_sgl
    1668              :       ELSE
    1669            0 :          yzbuf => fft_scratch%yzbuf
    1670            0 :          xzbuf => fft_scratch%xzbuf
    1671              :       END IF
    1672            0 :       npx = dims(1)
    1673            0 :       npz = dims(2)
    1674            0 :       pgrid => fft_scratch%pgrid
    1675            0 :       xcor => fft_scratch%xcor
    1676            0 :       zcor => fft_scratch%zcor
    1677            0 :       pzcoord => fft_scratch%pzcoord
    1678            0 :       scount => fft_scratch%scount
    1679            0 :       rcount => fft_scratch%rcount
    1680            0 :       sdispl => fft_scratch%sdispl
    1681            0 :       rdispl => fft_scratch%rdispl
    1682              : 
    1683            0 :       nx = SIZE(sb, 2)
    1684              : 
    1685              : ! If the send and recv counts are not already cached, then
    1686              : ! calculate and store them
    1687            0 :       IF (fft_scratch%in == 0) THEN
    1688              : 
    1689            0 :          scount = 0
    1690              : 
    1691            0 :          DO ix = 0, npx - 1
    1692            0 :             ip = pgrid(ix, 0)
    1693            0 :             xcor(bo(1, 1, ip):bo(2, 1, ip)) = ix
    1694              :          END DO
    1695            0 :          DO iz = 0, npz - 1
    1696            0 :             ip = pgrid(0, iz)
    1697            0 :             zcor(bo(1, 3, ip):bo(2, 3, ip)) = iz
    1698              :          END DO
    1699            0 :          DO jx = 1, nx
    1700            0 :             IF (alltoall_sgl) THEN
    1701            0 :                DO ir = 1, nray(my_pos)
    1702            0 :                   jy = yzp(1, ir, my_pos)
    1703            0 :                   jz = yzp(2, ir, my_pos)
    1704            0 :                   ip = pgrid(xcor(jx), zcor(jz))
    1705            0 :                   scount(ip) = scount(ip) + 1
    1706              :                END DO
    1707              :             ELSE
    1708            0 :                DO ir = 1, nray(my_pos)
    1709            0 :                   jy = yzp(1, ir, my_pos)
    1710            0 :                   jz = yzp(2, ir, my_pos)
    1711            0 :                   ip = pgrid(xcor(jx), zcor(jz))
    1712            0 :                   scount(ip) = scount(ip) + 1
    1713              :                END DO
    1714              :             END IF
    1715              :          END DO
    1716              : 
    1717            0 :          CALL group%alltoall(scount, rcount, 1)
    1718            0 :          fft_scratch%yzcount = scount
    1719            0 :          fft_scratch%xzcount = rcount
    1720              : 
    1721              :          ! Work out the correct displacements in the buffers
    1722            0 :          sdispl(0) = 0
    1723            0 :          rdispl(0) = 0
    1724            0 :          DO ip = 1, np - 1
    1725            0 :             sdispl(ip) = sdispl(ip - 1) + scount(ip - 1)
    1726            0 :             rdispl(ip) = rdispl(ip - 1) + rcount(ip - 1)
    1727              :          END DO
    1728              : 
    1729            0 :          fft_scratch%yzdispl = sdispl
    1730            0 :          fft_scratch%xzdispl = rdispl
    1731              : 
    1732            0 :          icrs = 0
    1733            0 :          DO ip = 0, np - 1
    1734            0 :             IF (scount(ip) /= 0) icrs = icrs + 1
    1735            0 :             IF (rcount(ip) /= 0) icrs = icrs + 1
    1736              :          END DO
    1737            0 :          CALL group%sum(icrs)
    1738            0 :          fft_scratch%rsratio = REAL(icrs, KIND=dp)/(REAL(2*np, KIND=dp)*REAL(np, KIND=dp))
    1739              : 
    1740            0 :          fft_scratch%in = 1
    1741              :       ELSE
    1742            0 :          scount = fft_scratch%yzcount
    1743            0 :          rcount = fft_scratch%xzcount
    1744            0 :          sdispl = fft_scratch%yzdispl
    1745            0 :          rdispl = fft_scratch%xzdispl
    1746              :       END IF
    1747              : 
    1748              : ! Do the actual packing
    1749              : !$OMP PARALLEL DO DEFAULT(NONE), &
    1750              : !$OMP             PRIVATE(ipl,jj,nx,ir,jx,jy,jz),&
    1751              : !$OMP             SHARED(np,p2p,pzcoord,bo,nray,yzp,zcor),&
    1752              : !$OMP             SHARED(yzbuf,sb,scount,sdispl,my_pos),&
    1753            0 : !$OMP             SHARED(yzbuf_sgl,alltoall_sgl)
    1754              :       DO ip = 0, np - 1
    1755              :          IF (scount(ip) == 0) CYCLE
    1756              :          ipl = p2p(ip)
    1757              :          jj = 0
    1758              :          nx = bo(2, 1, ipl) - bo(1, 1, ipl) + 1
    1759              :          DO ir = 1, nray(my_pos)
    1760              :             jz = yzp(2, ir, my_pos)
    1761              :             IF (zcor(jz) == pzcoord(ipl)) THEN
    1762              :                jj = jj + 1
    1763              :                jy = yzp(1, ir, my_pos)
    1764              :                IF (alltoall_sgl) THEN
    1765              :                   DO jx = 0, nx - 1
    1766              :                      yzbuf_sgl(sdispl(ip) + jj + jx*scount(ip)/nx) = CMPLX(sb(ir, jx + bo(1, 1, ipl)), KIND=sp)
    1767              :                   END DO
    1768              :                ELSE
    1769              :                   DO jx = 0, nx - 1
    1770              :                      yzbuf(sdispl(ip) + jj + jx*scount(ip)/nx) = sb(ir, jx + bo(1, 1, ipl))
    1771              :                   END DO
    1772              :                END IF
    1773              :             END IF
    1774              :          END DO
    1775              :       END DO
    1776              : !$OMP END PARALLEL DO
    1777              : 
    1778            0 :       IF (alltoall_sgl) THEN
    1779            0 :          CALL group%alltoall(yzbuf_sgl, scount, sdispl, xzbuf_sgl, rcount, rdispl)
    1780              :       ELSE
    1781            0 :          IF (fft_scratch%rsratio < ratio_sparse_alltoall) THEN
    1782            0 :             CALL sparse_alltoall(yzbuf, scount, sdispl, xzbuf, rcount, rdispl, group)
    1783              :          ELSE
    1784            0 :             CALL group%alltoall(yzbuf, scount, sdispl, xzbuf, rcount, rdispl)
    1785              :          END IF
    1786              :       END IF
    1787              : 
    1788            0 :       myx = fft_scratch%sizes%r_pos(1)
    1789            0 :       myz = fft_scratch%sizes%r_pos(2)
    1790            0 :       nz = bo(2, 3, rs_pos) - bo(1, 3, rs_pos) + 1
    1791              : 
    1792              : !$OMP PARALLEL DO DEFAULT(NONE), &
    1793              : !$OMP             PRIVATE(ipr,jj,ir,jx,jy,jz),&
    1794              : !$OMP             SHARED(tb,np,p2p,bo,rs_pos,nray),&
    1795              : !$OMP             SHARED(yzp,alltoall_sgl,zcor,myz),&
    1796            0 : !$OMP             SHARED(xzbuf,xzbuf_sgl,nz,rdispl)
    1797              :       DO ip = 0, np - 1
    1798              :          ipr = p2p(ip)
    1799              :          jj = 0
    1800              :          DO jx = 0, bo(2, 1, rs_pos) - bo(1, 1, rs_pos)
    1801              :             DO ir = 1, nray(ip)
    1802              :                jz = yzp(2, ir, ip)
    1803              :                IF (alltoall_sgl) THEN
    1804              :                   IF (zcor(jz) == myz) THEN
    1805              :                      jj = jj + 1
    1806              :                      jy = yzp(1, ir, ip)
    1807              :                      jz = jz - bo(1, 3, rs_pos) + 1
    1808              :                      tb(jy, jz + jx*nz) = xzbuf_sgl(jj + rdispl(ipr))
    1809              :                   END IF
    1810              :                ELSE
    1811              :                   IF (zcor(jz) == myz) THEN
    1812              :                      jj = jj + 1
    1813              :                      jy = yzp(1, ir, ip)
    1814              :                      jz = jz - bo(1, 3, rs_pos) + 1
    1815              :                      tb(jy, jz + jx*nz) = xzbuf(jj + rdispl(ipr))
    1816              :                   END IF
    1817              :                END IF
    1818              :             END DO
    1819              :          END DO
    1820              :       END DO
    1821              : !$OMP END PARALLEL DO
    1822              : 
    1823            0 :       CALL timestop(handle)
    1824              : 
    1825            0 :    END SUBROUTINE yz_to_xz
    1826              : 
    1827              : ! **************************************************************************************************
    1828              : !> \brief ...
    1829              : !> \param sb ...
    1830              : !> \param group ...
    1831              : !> \param dims ...
    1832              : !> \param my_pos ...
    1833              : !> \param p2p ...
    1834              : !> \param yzp ...
    1835              : !> \param nray ...
    1836              : !> \param bo ...
    1837              : !> \param tb ...
    1838              : !> \param fft_scratch ...
    1839              : !> \par History
    1840              : !>      15. Feb. 2006 : single precision all_to_all
    1841              : !> \author JGH (19-Jan-2001)
    1842              : ! **************************************************************************************************
    1843            0 :    SUBROUTINE xz_to_yz(sb, group, dims, my_pos, p2p, yzp, nray, bo, tb, fft_scratch)
    1844              : 
    1845              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    1846              :          INTENT(IN)                                      :: sb
    1847              : 
    1848              :       CLASS(mp_comm_type), INTENT(IN)                    :: group
    1849              :       INTEGER, DIMENSION(2), INTENT(IN)                  :: dims
    1850              :       INTEGER, INTENT(IN)                                :: my_pos
    1851              :       INTEGER, CONTIGUOUS, DIMENSION(0:), INTENT(IN)                 :: p2p
    1852              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), INTENT(IN)           :: yzp
    1853              :       INTEGER, CONTIGUOUS, DIMENSION(0:), INTENT(IN)                 :: nray
    1854              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), INTENT(IN)           :: bo
    1855              :       COMPLEX(KIND=dp), DIMENSION(:, :), INTENT(INOUT), CONTIGUOUS   :: tb
    1856              :       TYPE(fft_scratch_type), INTENT(INOUT)              :: fft_scratch
    1857              : 
    1858              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'xz_to_yz'
    1859              : 
    1860            0 :       COMPLEX(KIND=dp), DIMENSION(:), POINTER, CONTIGUOUS            :: xzbuf, yzbuf
    1861            0 :       COMPLEX(KIND=sp), DIMENSION(:), POINTER, CONTIGUOUS            :: xzbuf_sgl, yzbuf_sgl
    1862              :       INTEGER                                            :: handle, icrs, ip, ipl, ir, ix, ixx, iz, &
    1863              :                                                             jj, jx, jy, jz, mp, myx, myz, np, npx, &
    1864              :                                                             npz, nx, nz
    1865            0 :       INTEGER, DIMENSION(:), POINTER, CONTIGUOUS                     :: pzcoord, rcount, rdispl, scount, sdispl, &
    1866            0 :                                                                         xcor, zcor
    1867            0 :       INTEGER, DIMENSION(:, :), CONTIGUOUS, POINTER                  :: pgrid
    1868              : 
    1869            0 :       CALL timeset(routineN, handle)
    1870              : 
    1871            0 :       np = SIZE(p2p)
    1872              : 
    1873            0 :       IF (alltoall_sgl) THEN
    1874            0 :          yzbuf_sgl => fft_scratch%yzbuf_sgl
    1875            0 :          xzbuf_sgl => fft_scratch%xzbuf_sgl
    1876              :       ELSE
    1877            0 :          yzbuf => fft_scratch%yzbuf
    1878            0 :          xzbuf => fft_scratch%xzbuf
    1879              :       END IF
    1880            0 :       npx = dims(1)
    1881            0 :       npz = dims(2)
    1882            0 :       pgrid => fft_scratch%pgrid
    1883            0 :       xcor => fft_scratch%xcor
    1884            0 :       zcor => fft_scratch%zcor
    1885            0 :       pzcoord => fft_scratch%pzcoord
    1886            0 :       scount => fft_scratch%scount
    1887            0 :       rcount => fft_scratch%rcount
    1888            0 :       sdispl => fft_scratch%sdispl
    1889            0 :       rdispl => fft_scratch%rdispl
    1890              : 
    1891              : ! If the send and recv counts are not already cached, then
    1892              : ! calculate and store them
    1893            0 :       IF (fft_scratch%in == 0) THEN
    1894              : 
    1895            0 :          rcount = 0
    1896            0 :          nx = MAXVAL(bo(2, 1, :))
    1897              : 
    1898            0 :          DO ix = 0, npx - 1
    1899            0 :             ip = pgrid(ix, 0)
    1900            0 :             xcor(bo(1, 1, ip):bo(2, 1, ip)) = ix
    1901              :          END DO
    1902            0 :          DO iz = 0, npz - 1
    1903            0 :             ip = pgrid(0, iz)
    1904            0 :             zcor(bo(1, 3, ip):bo(2, 3, ip)) = iz
    1905              :          END DO
    1906            0 :          DO jx = 1, nx
    1907            0 :             DO ir = 1, nray(my_pos)
    1908            0 :                jy = yzp(1, ir, my_pos)
    1909            0 :                jz = yzp(2, ir, my_pos)
    1910            0 :                ip = pgrid(xcor(jx), zcor(jz))
    1911            0 :                rcount(ip) = rcount(ip) + 1
    1912              :             END DO
    1913              :          END DO
    1914              : 
    1915            0 :          CALL group%alltoall(rcount, scount, 1)
    1916            0 :          fft_scratch%xzcount = scount
    1917            0 :          fft_scratch%yzcount = rcount
    1918              : 
    1919              :          ! Work out the correct displacements in the buffers
    1920            0 :          sdispl(0) = 0
    1921            0 :          rdispl(0) = 0
    1922            0 :          DO ip = 1, np - 1
    1923            0 :             sdispl(ip) = sdispl(ip - 1) + scount(ip - 1)
    1924            0 :             rdispl(ip) = rdispl(ip - 1) + rcount(ip - 1)
    1925              :          END DO
    1926              : 
    1927            0 :          fft_scratch%xzdispl = sdispl
    1928            0 :          fft_scratch%yzdispl = rdispl
    1929              : 
    1930            0 :          icrs = 0
    1931            0 :          DO ip = 0, np - 1
    1932            0 :             IF (scount(ip) /= 0) icrs = icrs + 1
    1933            0 :             IF (rcount(ip) /= 0) icrs = icrs + 1
    1934              :          END DO
    1935            0 :          CALL group%sum(icrs)
    1936            0 :          fft_scratch%rsratio = REAL(icrs, KIND=dp)/(REAL(2*np, KIND=dp)*REAL(np, KIND=dp))
    1937              : 
    1938            0 :          fft_scratch%in = 1
    1939              :       ELSE
    1940            0 :          scount = fft_scratch%xzcount
    1941            0 :          rcount = fft_scratch%yzcount
    1942            0 :          sdispl = fft_scratch%xzdispl
    1943            0 :          rdispl = fft_scratch%yzdispl
    1944              :       END IF
    1945              : 
    1946              : ! Now do the actual packing
    1947            0 :       myx = fft_scratch%sizes%r_pos(1)
    1948            0 :       myz = fft_scratch%sizes%r_pos(2)
    1949            0 :       mp = p2p(my_pos)
    1950            0 :       nz = bo(2, 3, mp) - bo(1, 3, mp) + 1
    1951            0 :       nx = bo(2, 1, mp) - bo(1, 1, mp) + 1
    1952              : 
    1953              : !$OMP PARALLEL DO DEFAULT(NONE), &
    1954              : !$OMP             PRIVATE(jj,ipl,ir,jx,jy,jz,ixx),&
    1955              : !$OMP             SHARED(np,p2p,nray,yzp,zcor,myz,bo,mp),&
    1956              : !$OMP             SHARED(alltoall_sgl,nx,scount,sdispl),&
    1957            0 : !$OMP             SHARED(xzbuf,xzbuf_sgl,sb,nz)
    1958              :       DO ip = 0, np - 1
    1959              :          jj = 0
    1960              :          ipl = p2p(ip)
    1961              :          DO ir = 1, nray(ip)
    1962              :             jz = yzp(2, ir, ip)
    1963              :             IF (zcor(jz) == myz) THEN
    1964              :                jj = jj + 1
    1965              :                jy = yzp(1, ir, ip)
    1966              :                jz = yzp(2, ir, ip) - bo(1, 3, mp) + 1
    1967              :                IF (alltoall_sgl) THEN
    1968              :                   DO jx = 0, nx - 1
    1969              :                      ixx = jj + jx*scount(ipl)/nx
    1970              :                      xzbuf_sgl(ixx + sdispl(ipl)) = CMPLX(sb(jy, jz + jx*nz), KIND=sp)
    1971              :                   END DO
    1972              :                ELSE
    1973              :                   DO jx = 0, nx - 1
    1974              :                      ixx = jj + jx*scount(ipl)/nx
    1975              :                      xzbuf(ixx + sdispl(ipl)) = sb(jy, jz + jx*nz)
    1976              :                   END DO
    1977              :                END IF
    1978              :             END IF
    1979              :          END DO
    1980              :       END DO
    1981              : !$OMP END PARALLEL DO
    1982              : 
    1983            0 :       IF (alltoall_sgl) THEN
    1984            0 :          CALL group%alltoall(xzbuf_sgl, scount, sdispl, yzbuf_sgl, rcount, rdispl)
    1985              :       ELSE
    1986            0 :          IF (fft_scratch%rsratio < ratio_sparse_alltoall) THEN
    1987            0 :             CALL sparse_alltoall(xzbuf, scount, sdispl, yzbuf, rcount, rdispl, group)
    1988              :          ELSE
    1989            0 :             CALL group%alltoall(xzbuf, scount, sdispl, yzbuf, rcount, rdispl)
    1990              :          END IF
    1991              :       END IF
    1992              : 
    1993              : !$OMP PARALLEL DO DEFAULT(NONE), &
    1994              : !$OMP             PRIVATE(ipl,jj,nx,ir,jx,jy,jz),&
    1995              : !$OMP             SHARED(p2p,pzcoord,bo,nray,my_pos,yzp),&
    1996              : !$OMP             SHARED(rcount,rdispl,tb,yzbuf,zcor),&
    1997            0 : !$OMP             SHARED(yzbuf_sgl,alltoall_sgl,np)
    1998              :       DO ip = 0, np - 1
    1999              :          IF (rcount(ip) == 0) CYCLE
    2000              :          ipl = p2p(ip)
    2001              :          jj = 0
    2002              :          nx = bo(2, 1, ipl) - bo(1, 1, ipl) + 1
    2003              :          DO ir = 1, nray(my_pos)
    2004              :             jz = yzp(2, ir, my_pos)
    2005              :             IF (zcor(jz) == pzcoord(ipl)) THEN
    2006              :                jj = jj + 1
    2007              :                jy = yzp(1, ir, my_pos)
    2008              :                IF (alltoall_sgl) THEN
    2009              :                   DO jx = 0, nx - 1
    2010              :                      tb(ir, jx + bo(1, 1, ipl)) = yzbuf_sgl(rdispl(ip) + jj + jx*rcount(ip)/nx)
    2011              :                   END DO
    2012              :                ELSE
    2013              :                   DO jx = 0, nx - 1
    2014              :                      tb(ir, jx + bo(1, 1, ipl)) = yzbuf(rdispl(ip) + jj + jx*rcount(ip)/nx)
    2015              :                   END DO
    2016              :                END IF
    2017              :             END IF
    2018              :          END DO
    2019              :       END DO
    2020              : !$OMP END PARALLEL DO
    2021              : 
    2022            0 :       CALL timestop(handle)
    2023              : 
    2024            0 :    END SUBROUTINE xz_to_yz
    2025              : 
    2026              : ! **************************************************************************************************
    2027              : !> \brief ...
    2028              : !> \param cin ...
    2029              : !> \param boin ...
    2030              : !> \param boout ...
    2031              : !> \param sout ...
    2032              : !> \param fft_scratch ...
    2033              : !> \par History
    2034              : !>      none
    2035              : !> \author JGH (20-Jan-2001)
    2036              : ! **************************************************************************************************
    2037            0 :    SUBROUTINE cube_transpose_1(cin, boin, boout, sout, fft_scratch)
    2038              : 
    2039              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2040              :          INTENT(IN)                                      :: cin
    2041              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), &
    2042              :          INTENT(IN)                                      :: boin, boout
    2043              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2044              :          INTENT(OUT)                                     :: sout
    2045              :       TYPE(fft_scratch_type), INTENT(IN)                 :: fft_scratch
    2046              : 
    2047              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cube_transpose_1'
    2048              : 
    2049              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2050            0 :          POINTER                                         :: rbuf
    2051              :       INTEGER                                            :: handle, ip, ipl, ir, is, ixy, iz, mip, &
    2052              :                                                             mz, np, nx, ny, nz
    2053            0 :       INTEGER, CONTIGUOUS, DIMENSION(:), POINTER         :: rcount, rdispl, scount, sdispl
    2054            0 :       INTEGER, CONTIGUOUS, DIMENSION(:, :), POINTER      :: pgrid
    2055              :       INTEGER, DIMENSION(2)                              :: dim, pos
    2056              : 
    2057            0 :       CALL timeset(routineN, handle)
    2058              : 
    2059            0 :       mip = fft_scratch%mip
    2060            0 :       dim = fft_scratch%dim
    2061            0 :       pos = fft_scratch%pos
    2062            0 :       scount => fft_scratch%scount
    2063            0 :       rcount => fft_scratch%rcount
    2064            0 :       sdispl => fft_scratch%sdispl
    2065            0 :       rdispl => fft_scratch%rdispl
    2066            0 :       pgrid => fft_scratch%pgcube
    2067            0 :       np = DIM(2)
    2068              : 
    2069            0 :       nx = boin(2, 1, mip) - boin(1, 1, mip) + 1
    2070            0 :       nz = boin(2, 3, mip) - boin(1, 3, mip) + 1
    2071              : 
    2072              : !$OMP PARALLEL DO DEFAULT(NONE), &
    2073              : !$OMP             PRIVATE(ipl,ny), &
    2074            0 : !$OMP             SHARED(np,pgrid,boout,scount,sdispl,nx,nz)
    2075              :       DO ip = 0, np - 1
    2076              :          ipl = pgrid(ip, 2)
    2077              :          ny = boout(2, 2, ipl) - boout(1, 2, ipl) + 1
    2078              :          scount(ip) = nx*nz*ny
    2079              :          sdispl(ip) = nx*nz*(boout(1, 2, ipl) - 1)
    2080              :       END DO
    2081              : !$OMP END PARALLEL DO
    2082            0 :       ny = boout(2, 2, mip) - boout(1, 2, mip) + 1
    2083            0 :       mz = MAXVAL(boin(2, 3, :) - boin(1, 3, :) + 1)
    2084              : !$OMP PARALLEL DO DEFAULT(NONE), &
    2085              : !$OMP             PRIVATE(ipl,nz), &
    2086            0 : !$OMP             SHARED(np,pgrid,boin,nx,ny,rcount,rdispl,mz)
    2087              :       DO ip = 0, np - 1
    2088              :          ipl = pgrid(ip, 2)
    2089              :          nz = boin(2, 3, ipl) - boin(1, 3, ipl) + 1
    2090              :          rcount(ip) = nx*nz*ny
    2091              :          rdispl(ip) = nx*ny*mz*ip
    2092              :       END DO
    2093              : !$OMP END PARALLEL DO
    2094              : 
    2095            0 :       rbuf => fft_scratch%rbuf1
    2096              : 
    2097            0 :       CALL fft_scratch%cart_sub_comm(2)%alltoall(cin, scount, sdispl, rbuf, rcount, rdispl)
    2098              : 
    2099              : !$OMP PARALLEL DO DEFAULT(NONE) COLLAPSE(2) &
    2100              : !$OMP             PRIVATE(ip,ipl,nz,iz,is,ir) &
    2101            0 : !$OMP             SHARED(nx,ny,np,pgrid,boin,sout,rbuf)
    2102              :       DO ixy = 1, nx*ny
    2103              :          DO ip = 0, np - 1
    2104              :             ipl = pgrid(ip, 2)
    2105              :             nz = boin(2, 3, ipl) - boin(1, 3, ipl) + 1
    2106              :             DO iz = 1, nz
    2107              :                is = boin(1, 3, ipl) + iz - 1
    2108              :                ir = iz + nz*(ixy - 1)
    2109              :                sout(is, ixy) = rbuf(ir, ip)
    2110              :             END DO
    2111              :          END DO
    2112              :       END DO
    2113              : !$OMP END PARALLEL DO
    2114              : 
    2115            0 :       CALL timestop(handle)
    2116              : 
    2117            0 :    END SUBROUTINE cube_transpose_1
    2118              : 
    2119              : ! **************************************************************************************************
    2120              : !> \brief ...
    2121              : !> \param cin ...
    2122              : !> \param boin ...
    2123              : !> \param boout ...
    2124              : !> \param sout ...
    2125              : !> \param fft_scratch ...
    2126              : ! **************************************************************************************************
    2127            0 :    SUBROUTINE cube_transpose_2(cin, boin, boout, sout, fft_scratch)
    2128              : 
    2129              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2130              :          INTENT(IN)                                      :: cin
    2131              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), &
    2132              :          INTENT(IN)                                      :: boin, boout
    2133              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2134              :          INTENT(OUT)                                     :: sout
    2135              :       TYPE(fft_scratch_type), INTENT(IN)                 :: fft_scratch
    2136              : 
    2137              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cube_transpose_2'
    2138              : 
    2139              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2140            0 :          POINTER                                         :: rbuf
    2141              :       INTEGER                                            :: handle, ip, ipl, ir, ixy, iz, mip, mz, &
    2142              :                                                             np, nx, ny, nz
    2143            0 :       INTEGER, CONTIGUOUS, DIMENSION(:), POINTER         :: rcount, rdispl, scount, sdispl
    2144            0 :       INTEGER, CONTIGUOUS, DIMENSION(:, :), POINTER      :: pgrid
    2145              :       INTEGER, DIMENSION(2)                              :: dim, pos
    2146              :       TYPE(mp_comm_type)                                 :: sub_group
    2147              : 
    2148            0 :       CALL timeset(routineN, handle)
    2149              : 
    2150            0 :       sub_group = fft_scratch%cart_sub_comm(2)
    2151            0 :       mip = fft_scratch%mip
    2152            0 :       dim = fft_scratch%dim
    2153            0 :       pos = fft_scratch%pos
    2154            0 :       scount => fft_scratch%scount
    2155            0 :       rcount => fft_scratch%rcount
    2156            0 :       sdispl => fft_scratch%sdispl
    2157            0 :       rdispl => fft_scratch%rdispl
    2158            0 :       pgrid => fft_scratch%pgcube
    2159            0 :       np = DIM(2)
    2160              : 
    2161            0 :       nx = boin(2, 1, mip) - boin(1, 1, mip) + 1
    2162            0 :       ny = boin(2, 2, mip) - boin(1, 2, mip) + 1
    2163            0 :       mz = MAXVAL(boout(2, 3, :) - boout(1, 3, :) + 1)
    2164              : 
    2165            0 :       rbuf => fft_scratch%rbuf2
    2166              : 
    2167              : !$OMP PARALLEL DEFAULT(NONE), &
    2168              : !$OMP          PRIVATE(ip,ipl,nz,iz,ir), &
    2169            0 : !$OMP          SHARED(nx,ny,np,pgrid,boout,rbuf,cin,scount,sdispl,mz)
    2170              : !$OMP DO COLLAPSE(2)
    2171              :       DO ixy = 1, nx*ny
    2172              :          DO ip = 0, np - 1
    2173              :             ipl = pgrid(ip, 2)
    2174              :             nz = boout(2, 3, ipl) - boout(1, 3, ipl) + 1
    2175              :             DO iz = boout(1, 3, ipl), boout(2, 3, ipl)
    2176              :                ir = iz - boout(1, 3, ipl) + 1 + (ixy - 1)*nz
    2177              :                rbuf(ir, ip) = cin(iz, ixy)
    2178              :             END DO
    2179              :          END DO
    2180              :       END DO
    2181              : !$OMP END DO
    2182              : !$OMP DO
    2183              :       DO ip = 0, np - 1
    2184              :          ipl = pgrid(ip, 2)
    2185              :          nz = boout(2, 3, ipl) - boout(1, 3, ipl) + 1
    2186              :          scount(ip) = nx*ny*nz
    2187              :          sdispl(ip) = nx*ny*mz*ip
    2188              :       END DO
    2189              : !$OMP END DO
    2190              : !$OMP END PARALLEL
    2191            0 :       nz = boout(2, 3, mip) - boout(1, 3, mip) + 1
    2192              : !$OMP PARALLEL DO DEFAULT(NONE), &
    2193              : !$OMP             PRIVATE(ipl,ny), &
    2194            0 : !$OMP             SHARED(np,pgrid,boin,nx,nz,rcount,rdispl)
    2195              :       DO ip = 0, np - 1
    2196              :          ipl = pgrid(ip, 2)
    2197              :          ny = boin(2, 2, ipl) - boin(1, 2, ipl) + 1
    2198              :          rcount(ip) = nx*ny*nz
    2199              :          rdispl(ip) = nx*nz*(boin(1, 2, ipl) - 1)
    2200              :       END DO
    2201              : !$OMP END PARALLEL DO
    2202              : 
    2203            0 :       CALL sub_group%alltoall(rbuf, scount, sdispl, sout, rcount, rdispl)
    2204              : 
    2205            0 :       CALL timestop(handle)
    2206              : 
    2207            0 :    END SUBROUTINE cube_transpose_2
    2208              : 
    2209              : ! **************************************************************************************************
    2210              : !> \brief ...
    2211              : !> \param cin ...
    2212              : !> \param boin ...
    2213              : !> \param boout ...
    2214              : !> \param sout ...
    2215              : !> \param fft_scratch ...
    2216              : ! **************************************************************************************************
    2217            0 :    SUBROUTINE cube_transpose_3(cin, boin, boout, sout, fft_scratch)
    2218              : 
    2219              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2220              :          INTENT(IN)                                      :: cin
    2221              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), &
    2222              :          INTENT(IN)                                      :: boin, boout
    2223              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2224              :          INTENT(OUT)                                     :: sout
    2225              :       TYPE(fft_scratch_type), INTENT(IN)                 :: fft_scratch
    2226              : 
    2227              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cube_transpose_3'
    2228              : 
    2229              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2230            0 :          POINTER                                         :: rbuf
    2231              :       INTEGER                                            :: handle, ip, ipl, ir, is, ixz, iy, lb, &
    2232              :                                                             mip, my, my_id, np, num_threads, nx, &
    2233              :                                                             ny, nz, ub
    2234            0 :       INTEGER, CONTIGUOUS, DIMENSION(:), POINTER         :: rcount, rdispl, scount, sdispl
    2235            0 :       INTEGER, CONTIGUOUS, DIMENSION(:, :), POINTER      :: pgrid
    2236              :       INTEGER, DIMENSION(2)                              :: dim, pos
    2237              :       TYPE(mp_comm_type)                                 :: sub_group
    2238              : 
    2239            0 :       CALL timeset(routineN, handle)
    2240              : 
    2241            0 :       sub_group = fft_scratch%cart_sub_comm(1)
    2242            0 :       mip = fft_scratch%mip
    2243            0 :       dim = fft_scratch%dim
    2244            0 :       pos = fft_scratch%pos
    2245            0 :       np = DIM(1)
    2246            0 :       scount => fft_scratch%scount
    2247            0 :       rcount => fft_scratch%rcount
    2248            0 :       sdispl => fft_scratch%sdispl
    2249            0 :       rdispl => fft_scratch%rdispl
    2250            0 :       pgrid => fft_scratch%pgcube
    2251              : 
    2252            0 :       ny = boin(2, 2, mip) - boin(1, 2, mip) + 1
    2253            0 :       nz = boin(2, 3, mip) - boin(1, 3, mip) + 1
    2254              : !$OMP PARALLEL DO DEFAULT(NONE), &
    2255              : !$OMP             PRIVATE(ipl, nx), &
    2256            0 : !$OMP             SHARED(np,pgrid,boout,ny,nz,scount,sdispl)
    2257              :       DO ip = 0, np - 1
    2258              :          ipl = pgrid(ip, 1)
    2259              :          nx = boout(2, 1, ipl) - boout(1, 1, ipl) + 1
    2260              :          scount(ip) = nx*nz*ny
    2261              :          sdispl(ip) = ny*nz*(boout(1, 1, ipl) - 1)
    2262              :       END DO
    2263              : !$OMP END PARALLEL DO
    2264            0 :       nx = boout(2, 1, mip) - boout(1, 1, mip) + 1
    2265            0 :       my = MAXVAL(boin(2, 2, :) - boin(1, 2, :) + 1)
    2266              : !$OMP PARALLEL DO DEFAULT(NONE), &
    2267              : !$OMP             PRIVATE(ipl, ny), &
    2268            0 : !$OMP             SHARED(np,pgrid,boin,nx,nz,my,rcount,rdispl)
    2269              :       DO ip = 0, np - 1
    2270              :          ipl = pgrid(ip, 1)
    2271              :          ny = boin(2, 2, ipl) - boin(1, 2, ipl) + 1
    2272              :          rcount(ip) = nx*nz*ny
    2273              :          rdispl(ip) = nx*my*nz*ip
    2274              :       END DO
    2275              : !$OMP END PARALLEL DO
    2276              : 
    2277            0 :       rbuf => fft_scratch%rbuf3
    2278            0 :       num_threads = 1
    2279            0 :       my_id = 0
    2280              : !$OMP PARALLEL DEFAULT(NONE), &
    2281              : !$OMP          PRIVATE(NUM_THREADS, my_id, lb, ub) &
    2282            0 : !$OMP          SHARED(rbuf)
    2283              : !$    num_threads = MIN(omp_get_max_threads(), SIZE(rbuf, 2))
    2284              : !$    my_id = omp_get_thread_num()
    2285              :       IF (my_id < num_threads) THEN
    2286              :          lb = (SIZE(rbuf, 2)*my_id)/num_threads
    2287              :          ub = (SIZE(rbuf, 2)*(my_id + 1))/num_threads - 1
    2288              :          rbuf(:, lb:ub) = 0.0_dp
    2289              :       END IF
    2290              : !$OMP END PARALLEL
    2291              : 
    2292            0 :       CALL sub_group%alltoall(cin, scount, sdispl, rbuf, rcount, rdispl)
    2293              : 
    2294              : !$OMP PARALLEL DO DEFAULT(NONE) COLLAPSE(2) &
    2295              : !$OMP             PRIVATE(ip,ipl,ny,iy,is,ir) &
    2296            0 : !$OMP             SHARED(nx,nz,np,pgrid,boin,rbuf,sout)
    2297              :       DO ixz = 1, nx*nz
    2298              :          DO ip = 0, np - 1
    2299              :             ipl = pgrid(ip, 1)
    2300              :             ny = boin(2, 2, ipl) - boin(1, 2, ipl) + 1
    2301              :             DO iy = 1, ny
    2302              :                is = boin(1, 2, ipl) + iy - 1
    2303              :                ir = iy + ny*(ixz - 1)
    2304              :                sout(is, ixz) = rbuf(ir, ip)
    2305              :             END DO
    2306              :          END DO
    2307              :       END DO
    2308              : !$OMP END PARALLEL DO
    2309              : 
    2310            0 :       CALL timestop(handle)
    2311              : 
    2312            0 :    END SUBROUTINE cube_transpose_3
    2313              : 
    2314              : ! **************************************************************************************************
    2315              : !> \brief ...
    2316              : !> \param cin ...
    2317              : !> \param boin ...
    2318              : !> \param boout ...
    2319              : !> \param sout ...
    2320              : !> \param fft_scratch ...
    2321              : ! **************************************************************************************************
    2322            0 :    SUBROUTINE cube_transpose_4(cin, boin, boout, sout, fft_scratch)
    2323              : 
    2324              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2325              :          INTENT(IN)                                      :: cin
    2326              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), &
    2327              :          INTENT(IN)                                      :: boin, boout
    2328              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2329              :          INTENT(OUT)                                     :: sout
    2330              :       TYPE(fft_scratch_type), INTENT(IN)                 :: fft_scratch
    2331              : 
    2332              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cube_transpose_4'
    2333              : 
    2334              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2335            0 :          POINTER                                         :: rbuf
    2336              :       INTEGER                                            :: handle, ip, ipl, ir, iy, izx, lb, mip, &
    2337              :                                                             my, my_id, np, num_threads, nx, ny, &
    2338              :                                                             nz, ub
    2339            0 :       INTEGER, CONTIGUOUS, DIMENSION(:), POINTER         :: rcount, rdispl, scount, sdispl
    2340            0 :       INTEGER, CONTIGUOUS, DIMENSION(:, :), POINTER      :: pgrid
    2341              :       INTEGER, DIMENSION(2)                              :: dim, pos
    2342              :       TYPE(mp_comm_type)                                 :: sub_group
    2343              : 
    2344            0 :       CALL timeset(routineN, handle)
    2345              : 
    2346            0 :       sub_group = fft_scratch%cart_sub_comm(1)
    2347            0 :       mip = fft_scratch%mip
    2348            0 :       dim = fft_scratch%dim
    2349            0 :       pos = fft_scratch%pos
    2350            0 :       np = DIM(1)
    2351            0 :       scount => fft_scratch%scount
    2352            0 :       rcount => fft_scratch%rcount
    2353            0 :       sdispl => fft_scratch%sdispl
    2354            0 :       rdispl => fft_scratch%rdispl
    2355            0 :       pgrid => fft_scratch%pgcube
    2356              : 
    2357            0 :       nx = boin(2, 1, mip) - boin(1, 1, mip) + 1
    2358            0 :       nz = boin(2, 3, mip) - boin(1, 3, mip) + 1
    2359            0 :       my = MAXVAL(boout(2, 2, :) - boout(1, 2, :) + 1)
    2360              : 
    2361            0 :       rbuf => fft_scratch%rbuf4
    2362            0 :       num_threads = 1
    2363            0 :       my_id = 0
    2364              : !$OMP PARALLEL DEFAULT(NONE), &
    2365              : !$OMP          PRIVATE(NUM_THREADS,my_id,lb,ub,ip,ipl,ny,iy,ir), &
    2366            0 : !$OMP          SHARED(rbuf,nz,nx,np,pgrid,boout,cin,my,scount,sdispl)
    2367              : !$    num_threads = MIN(omp_get_max_threads(), SIZE(rbuf, 2))
    2368              : !$    my_id = omp_get_thread_num()
    2369              :       IF (my_id < num_threads) THEN
    2370              :          lb = (SIZE(rbuf, 2)*my_id)/num_threads
    2371              :          ub = (SIZE(rbuf, 2)*(my_id + 1))/num_threads - 1
    2372              :          rbuf(:, lb:ub) = 0.0_dp
    2373              :       END IF
    2374              : !$OMP BARRIER
    2375              : 
    2376              : !$OMP DO COLLAPSE(2)
    2377              :       DO izx = 1, nz*nx
    2378              :          DO ip = 0, np - 1
    2379              :             ipl = pgrid(ip, 1)
    2380              :             ny = boout(2, 2, ipl) - boout(1, 2, ipl) + 1
    2381              :             DO iy = boout(1, 2, ipl), boout(2, 2, ipl)
    2382              :                ir = iy - boout(1, 2, ipl) + 1 + (izx - 1)*ny
    2383              :                rbuf(ir, ip) = cin(iy, izx)
    2384              :             END DO
    2385              :          END DO
    2386              :       END DO
    2387              : !$OMP END DO
    2388              : !$OMP DO
    2389              :       DO ip = 0, np - 1
    2390              :          ipl = pgrid(ip, 1)
    2391              :          ny = boout(2, 2, ipl) - boout(1, 2, ipl) + 1
    2392              :          scount(ip) = nx*ny*nz
    2393              :          sdispl(ip) = nx*nz*my*ip
    2394              :       END DO
    2395              : !$OMP END DO
    2396              : !$OMP END PARALLEL
    2397            0 :       ny = boout(2, 2, mip) - boout(1, 2, mip) + 1
    2398              : !$OMP PARALLEL DO DEFAULT(NONE), &
    2399              : !$OMP             PRIVATE(ipl,nx), &
    2400            0 : !$OMP             SHARED(np,pgrid,boin,rcount,rdispl,ny,nz)
    2401              :       DO ip = 0, np - 1
    2402              :          ipl = pgrid(ip, 1)
    2403              :          nx = boin(2, 1, ipl) - boin(1, 1, ipl) + 1
    2404              :          rcount(ip) = nx*ny*nz
    2405              :          rdispl(ip) = ny*nz*(boin(1, 1, ipl) - 1)
    2406              :       END DO
    2407              : !$OMP END PARALLEL DO
    2408              : 
    2409            0 :       CALL sub_group%alltoall(rbuf, scount, sdispl, sout, rcount, rdispl)
    2410              : 
    2411            0 :       CALL timestop(handle)
    2412              : 
    2413            0 :    END SUBROUTINE cube_transpose_4
    2414              : 
    2415              : ! **************************************************************************************************
    2416              : !> \brief ...
    2417              : !> \param cin ...
    2418              : !> \param group ...
    2419              : !> \param boin ...
    2420              : !> \param boout ...
    2421              : !> \param sout ...
    2422              : !> \param fft_scratch ...
    2423              : ! **************************************************************************************************
    2424          104 :    SUBROUTINE cube_transpose_5(cin, group, boin, boout, sout, fft_scratch)
    2425              : 
    2426              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2427              :          INTENT(IN)                                      :: cin
    2428              : 
    2429              :       CLASS(mp_comm_type), INTENT(IN)                    :: group
    2430              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), INTENT(IN)           :: boin, boout
    2431              :       COMPLEX(KIND=dp), DIMENSION(:, :), INTENT(OUT), CONTIGUOUS     :: sout
    2432              :       TYPE(fft_scratch_type), INTENT(IN)                 :: fft_scratch
    2433              : 
    2434              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cube_transpose_5'
    2435              : 
    2436          104 :       COMPLEX(KIND=dp), DIMENSION(:, :), POINTER, CONTIGUOUS         :: rbuf
    2437              :       INTEGER                                            :: handle, ip, ir, is, ixz, iy, lb, mip, &
    2438              :                                                             my, my_id, np, num_threads, nx, ny, &
    2439              :                                                             nz, ub
    2440          104 :       INTEGER, DIMENSION(:), POINTER, CONTIGUOUS                     :: rcount, rdispl, scount, sdispl
    2441              : 
    2442          104 :       CALL timeset(routineN, handle)
    2443              : 
    2444          104 :       np = fft_scratch%sizes%numtask
    2445          104 :       mip = fft_scratch%mip
    2446          104 :       scount => fft_scratch%scount
    2447          104 :       rcount => fft_scratch%rcount
    2448          104 :       sdispl => fft_scratch%sdispl
    2449          104 :       rdispl => fft_scratch%rdispl
    2450              : 
    2451          104 :       ny = boin(2, 2, mip) - boin(1, 2, mip) + 1
    2452          104 :       nz = boin(2, 3, mip) - boin(1, 3, mip) + 1
    2453              : !$OMP PARALLEL DO DEFAULT(NONE), &
    2454              : !$OMP             PRIVATE(nx), &
    2455          104 : !$OMP             SHARED(np,boout,ny,nz,scount,sdispl)
    2456              :       DO ip = 0, np - 1
    2457              :          nx = boout(2, 1, ip) - boout(1, 1, ip) + 1
    2458              :          scount(ip) = nx*nz*ny
    2459              :          sdispl(ip) = ny*nz*(boout(1, 1, ip) - 1)
    2460              :       END DO
    2461              : !$OMP END PARALLEL DO
    2462          104 :       nx = boout(2, 1, mip) - boout(1, 1, mip) + 1
    2463          312 :       my = MAXVAL(boin(2, 2, :) - boin(1, 2, :) + 1)
    2464              : !$OMP PARALLEL DO DEFAULT(NONE), &
    2465              : !$OMP             PRIVATE(ny), &
    2466          104 : !$OMP             SHARED(np,boin,nx,nz,rcount,rdispl,my)
    2467              :       DO ip = 0, np - 1
    2468              :          ny = boin(2, 2, ip) - boin(1, 2, ip) + 1
    2469              :          rcount(ip) = nx*nz*ny
    2470              :          rdispl(ip) = nx*my*nz*ip
    2471              :       END DO
    2472              : !$OMP END PARALLEL DO
    2473              : 
    2474          104 :       rbuf => fft_scratch%rbuf5
    2475          104 :       num_threads = 1
    2476          104 :       my_id = 0
    2477              : !$OMP PARALLEL DEFAULT(NONE), &
    2478              : !$OMP          PRIVATE(NUM_THREADS, my_id, lb, ub), &
    2479          104 : !$OMP          SHARED(rbuf)
    2480              : !$    num_threads = MIN(omp_get_max_threads(), SIZE(rbuf, 2))
    2481              : !$    my_id = omp_get_thread_num()
    2482              :       IF (my_id < num_threads) THEN
    2483              :          lb = (SIZE(rbuf, 2)*my_id)/num_threads
    2484              :          ub = (SIZE(rbuf, 2)*(my_id + 1))/num_threads - 1
    2485              :          rbuf(:, lb:ub) = 0.0_dp
    2486              :       END IF
    2487              : !$OMP END PARALLEL
    2488              : 
    2489          104 :       CALL group%alltoall(cin, scount, sdispl, rbuf, rcount, rdispl)
    2490              : 
    2491              : !$OMP PARALLEL DO DEFAULT(NONE) COLLAPSE(2) &
    2492              : !$OMP             PRIVATE(ip,ny,iy,is,ir) &
    2493          104 : !$OMP             SHARED(nx,nz,np,boin,sout,rbuf)
    2494              :       DO ixz = 1, nx*nz
    2495              :          DO ip = 0, np - 1
    2496              :             ny = boin(2, 2, ip) - boin(1, 2, ip) + 1
    2497              :             DO iy = 1, ny
    2498              :                is = boin(1, 2, ip) + iy - 1
    2499              :                ir = iy + ny*(ixz - 1)
    2500              :                sout(is, ixz) = rbuf(ir, ip)
    2501              :             END DO
    2502              :          END DO
    2503              :       END DO
    2504              : !$OMP END PARALLEL DO
    2505              : 
    2506          104 :       CALL timestop(handle)
    2507              : 
    2508          104 :    END SUBROUTINE cube_transpose_5
    2509              : 
    2510              : ! **************************************************************************************************
    2511              : !> \brief ...
    2512              : !> \param cin ...
    2513              : !> \param group ...
    2514              : !> \param boin ...
    2515              : !> \param boout ...
    2516              : !> \param sout ...
    2517              : !> \param fft_scratch ...
    2518              : ! **************************************************************************************************
    2519          104 :    SUBROUTINE cube_transpose_6(cin, group, boin, boout, sout, fft_scratch)
    2520              : 
    2521              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2522              :          INTENT(IN)                                      :: cin
    2523              : 
    2524              :       CLASS(mp_comm_type), INTENT(IN)                    :: group
    2525              :       INTEGER, CONTIGUOUS, DIMENSION(:, :, 0:), INTENT(IN)           :: boin, boout
    2526              :       COMPLEX(KIND=dp), DIMENSION(:, :), INTENT(OUT), CONTIGUOUS     :: sout
    2527              :       TYPE(fft_scratch_type), INTENT(IN)                 :: fft_scratch
    2528              : 
    2529              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cube_transpose_6'
    2530              : 
    2531          104 :       COMPLEX(KIND=dp), DIMENSION(:, :), POINTER, CONTIGUOUS         :: rbuf
    2532              :       INTEGER                                            :: handle, ip, ir, iy, izx, lb, mip, my, &
    2533              :                                                             my_id, np, num_threads, nx, ny, nz, ub
    2534          104 :       INTEGER, DIMENSION(:), POINTER, CONTIGUOUS                     :: rcount, rdispl, scount, sdispl
    2535              : 
    2536          104 :       CALL timeset(routineN, handle)
    2537              : 
    2538          104 :       np = fft_scratch%sizes%numtask
    2539          104 :       mip = fft_scratch%mip
    2540          104 :       scount => fft_scratch%scount
    2541          104 :       rcount => fft_scratch%rcount
    2542          104 :       sdispl => fft_scratch%sdispl
    2543          104 :       rdispl => fft_scratch%rdispl
    2544              : 
    2545          104 :       nx = boin(2, 1, mip) - boin(1, 1, mip) + 1
    2546          104 :       nz = boin(2, 3, mip) - boin(1, 3, mip) + 1
    2547          312 :       my = MAXVAL(boout(2, 2, :) - boout(1, 2, :) + 1)
    2548              : 
    2549          104 :       rbuf => fft_scratch%rbuf5
    2550          104 :       num_threads = 1
    2551          104 :       my_id = 0
    2552              : !$OMP PARALLEL DEFAULT(NONE), &
    2553              : !$OMP          PRIVATE(NUM_THREADS,my_id,lb,ub,ip,ny,iy,ir), &
    2554          104 : !$OMP          SHARED(rbuf,nx,nz,np,boout,cin,my,scount,sdispl)
    2555              : !$    num_threads = MIN(omp_get_max_threads(), SIZE(rbuf, 2))
    2556              : !$    my_id = omp_get_thread_num()
    2557              :       IF (my_id < num_threads) THEN
    2558              :          lb = (SIZE(rbuf, 2)*my_id)/num_threads
    2559              :          ub = (SIZE(rbuf, 2)*(my_id + 1))/num_threads - 1
    2560              :          rbuf(:, lb:ub) = 0.0_dp
    2561              :       END IF
    2562              : !$OMP BARRIER
    2563              : 
    2564              : !$OMP DO COLLAPSE(2)
    2565              :       DO izx = 1, nz*nx
    2566              :          DO ip = 0, np - 1
    2567              :             ny = boout(2, 2, ip) - boout(1, 2, ip) + 1
    2568              :             DO iy = boout(1, 2, ip), boout(2, 2, ip)
    2569              :                ir = iy - boout(1, 2, ip) + 1 + (izx - 1)*ny
    2570              :                rbuf(ir, ip) = cin(iy, izx)
    2571              :             END DO
    2572              :          END DO
    2573              :       END DO
    2574              : !$OMP END DO
    2575              : !$OMP DO
    2576              :       DO ip = 0, np - 1
    2577              :          ny = boout(2, 2, ip) - boout(1, 2, ip) + 1
    2578              :          scount(ip) = nx*ny*nz
    2579              :          sdispl(ip) = nx*nz*my*ip
    2580              :       END DO
    2581              : !$OMP END DO
    2582              : !$OMP END PARALLEL
    2583          104 :       ny = boout(2, 2, mip) - boout(1, 2, mip) + 1
    2584              : !$OMP PARALLEL DO DEFAULT(NONE), &
    2585              : !$OMP             PRIVATE(nx), &
    2586          104 : !$OMP             SHARED(np,boin,rcount,rdispl,nz,ny)
    2587              :       DO ip = 0, np - 1
    2588              :          nx = boin(2, 1, ip) - boin(1, 1, ip) + 1
    2589              :          rcount(ip) = nx*ny*nz
    2590              :          rdispl(ip) = ny*nz*(boin(1, 1, ip) - 1)
    2591              :       END DO
    2592              : !$OMP END PARALLEL DO
    2593              : 
    2594          104 :       CALL group%alltoall(rbuf, scount, sdispl, sout, rcount, rdispl)
    2595              : 
    2596          104 :       CALL timestop(handle)
    2597              : 
    2598          104 :    END SUBROUTINE cube_transpose_6
    2599              : 
    2600              : ! **************************************************************************************************
    2601              : !> \brief ...
    2602              : ! **************************************************************************************************
    2603        25349 :    SUBROUTINE init_fft_scratch_pool()
    2604              : 
    2605        25349 :       CALL release_fft_scratch_pool()
    2606              : 
    2607              :       ! Allocate first scratch and mark it as used
    2608        25349 :       ALLOCATE (fft_scratch_first)
    2609       735121 :       ALLOCATE (fft_scratch_first%fft_scratch)
    2610              :       ! this is a very special scratch, it seems, we always keep it 'most - recent' so we will never delete it
    2611        25349 :       fft_scratch_first%fft_scratch%last_tick = HUGE(fft_scratch_first%fft_scratch%last_tick)
    2612              : 
    2613        25349 :       init_fft_pool = init_fft_pool + 1
    2614              : 
    2615        25349 :    END SUBROUTINE init_fft_scratch_pool
    2616              : 
    2617              : ! **************************************************************************************************
    2618              : !> \brief ...
    2619              : !> \param fft_scratch ...
    2620              : ! **************************************************************************************************
    2621        76605 :    SUBROUTINE deallocate_fft_scratch_type(fft_scratch)
    2622              :       TYPE(fft_scratch_type), INTENT(INOUT)    :: fft_scratch
    2623              : 
    2624              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    2625              :       INTEGER                   :: ierr
    2626              :       COMPLEX(KIND=dp), POINTER :: dummy_ptr_z
    2627              : #endif
    2628              : 
    2629              :       ! deallocate structures
    2630        76605 :       IF (ASSOCIATED(fft_scratch%ziptr)) THEN
    2631        15994 :          CALL fft_dealloc(fft_scratch%ziptr)
    2632              :       END IF
    2633        76605 :       IF (ASSOCIATED(fft_scratch%zoptr)) THEN
    2634        15994 :          CALL fft_dealloc(fft_scratch%zoptr)
    2635              :       END IF
    2636        76605 :       IF (ASSOCIATED(fft_scratch%p1buf)) THEN
    2637            0 :          CALL fft_dealloc(fft_scratch%p1buf)
    2638              :       END IF
    2639        76605 :       IF (ASSOCIATED(fft_scratch%p2buf)) THEN
    2640              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    2641              :          dummy_ptr_z => fft_scratch%p2buf(1, 1)
    2642              :          ierr = offload_free_pinned_mem(c_loc(dummy_ptr_z))
    2643              : #else
    2644            0 :          CALL fft_dealloc(fft_scratch%p2buf)
    2645              : #endif
    2646              :       END IF
    2647        76605 :       IF (ASSOCIATED(fft_scratch%p3buf)) THEN
    2648              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    2649              :          dummy_ptr_z => fft_scratch%p3buf(1, 1)
    2650              :          ierr = offload_free_pinned_mem(c_loc(dummy_ptr_z))
    2651              : #else
    2652            0 :          CALL fft_dealloc(fft_scratch%p3buf)
    2653              : #endif
    2654              :       END IF
    2655        76605 :       IF (ASSOCIATED(fft_scratch%p4buf)) THEN
    2656              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    2657              :          dummy_ptr_z => fft_scratch%p4buf(1, 1)
    2658              :          ierr = offload_free_pinned_mem(c_loc(dummy_ptr_z))
    2659              : #else
    2660            0 :          CALL fft_dealloc(fft_scratch%p4buf)
    2661              : #endif
    2662              :       END IF
    2663        76605 :       IF (ASSOCIATED(fft_scratch%p5buf)) THEN
    2664              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    2665              :          dummy_ptr_z => fft_scratch%p5buf(1, 1)
    2666              :          ierr = offload_free_pinned_mem(c_loc(dummy_ptr_z))
    2667              : #else
    2668            0 :          CALL fft_dealloc(fft_scratch%p5buf)
    2669              : #endif
    2670              :       END IF
    2671        76605 :       IF (ASSOCIATED(fft_scratch%p6buf)) THEN
    2672            0 :          CALL fft_dealloc(fft_scratch%p6buf)
    2673              :       END IF
    2674        76605 :       IF (ASSOCIATED(fft_scratch%p7buf)) THEN
    2675              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    2676              :          dummy_ptr_z => fft_scratch%p7buf(1, 1)
    2677              :          ierr = offload_free_pinned_mem(c_loc(dummy_ptr_z))
    2678              : #else
    2679            0 :          CALL fft_dealloc(fft_scratch%p7buf)
    2680              : #endif
    2681              :       END IF
    2682        76605 :       IF (ASSOCIATED(fft_scratch%r1buf)) THEN
    2683              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    2684              :          dummy_ptr_z => fft_scratch%r1buf(1, 1)
    2685              :          ierr = offload_free_pinned_mem(c_loc(dummy_ptr_z))
    2686              : #else
    2687        35255 :          CALL fft_dealloc(fft_scratch%r1buf)
    2688              : #endif
    2689              :       END IF
    2690        76605 :       IF (ASSOCIATED(fft_scratch%r2buf)) THEN
    2691        35255 :          CALL fft_dealloc(fft_scratch%r2buf)
    2692              :       END IF
    2693        76605 :       IF (ASSOCIATED(fft_scratch%tbuf)) THEN
    2694              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    2695              :          dummy_ptr_z => fft_scratch%tbuf(1, 1, 1)
    2696              :          ierr = offload_free_pinned_mem(c_loc(dummy_ptr_z))
    2697              : #else
    2698        35255 :          CALL fft_dealloc(fft_scratch%tbuf)
    2699              : #endif
    2700              :       END IF
    2701        76605 :       IF (ASSOCIATED(fft_scratch%a1buf)) THEN
    2702            8 :          CALL fft_dealloc(fft_scratch%a1buf)
    2703              :       END IF
    2704        76605 :       IF (ASSOCIATED(fft_scratch%a2buf)) THEN
    2705            8 :          CALL fft_dealloc(fft_scratch%a2buf)
    2706              :       END IF
    2707        76605 :       IF (ASSOCIATED(fft_scratch%a3buf)) THEN
    2708            8 :          CALL fft_dealloc(fft_scratch%a3buf)
    2709              :       END IF
    2710        76605 :       IF (ASSOCIATED(fft_scratch%a4buf)) THEN
    2711            8 :          CALL fft_dealloc(fft_scratch%a4buf)
    2712              :       END IF
    2713        76605 :       IF (ASSOCIATED(fft_scratch%a5buf)) THEN
    2714            8 :          CALL fft_dealloc(fft_scratch%a5buf)
    2715              :       END IF
    2716        76605 :       IF (ASSOCIATED(fft_scratch%a6buf)) THEN
    2717            8 :          CALL fft_dealloc(fft_scratch%a6buf)
    2718              :       END IF
    2719        76605 :       IF (ASSOCIATED(fft_scratch%scount)) THEN
    2720            0 :          DEALLOCATE (fft_scratch%scount, fft_scratch%rcount, &
    2721        35263 :                      fft_scratch%sdispl, fft_scratch%rdispl)
    2722              :       END IF
    2723        76605 :       IF (ASSOCIATED(fft_scratch%rr)) THEN
    2724        35247 :          DEALLOCATE (fft_scratch%rr)
    2725              :       END IF
    2726        76605 :       IF (ASSOCIATED(fft_scratch%xzbuf)) THEN
    2727            0 :          DEALLOCATE (fft_scratch%xzbuf)
    2728              :       END IF
    2729        76605 :       IF (ASSOCIATED(fft_scratch%yzbuf)) THEN
    2730            0 :          DEALLOCATE (fft_scratch%yzbuf)
    2731              :       END IF
    2732        76605 :       IF (ASSOCIATED(fft_scratch%xzbuf_sgl)) THEN
    2733            0 :          DEALLOCATE (fft_scratch%xzbuf_sgl)
    2734              :       END IF
    2735        76605 :       IF (ASSOCIATED(fft_scratch%yzbuf_sgl)) THEN
    2736            0 :          DEALLOCATE (fft_scratch%yzbuf_sgl)
    2737              :       END IF
    2738        76605 :       IF (ASSOCIATED(fft_scratch%ss)) THEN
    2739            8 :          DEALLOCATE (fft_scratch%ss)
    2740              :       END IF
    2741        76605 :       IF (ASSOCIATED(fft_scratch%tt)) THEN
    2742            8 :          DEALLOCATE (fft_scratch%tt)
    2743              :       END IF
    2744        76605 :       IF (ASSOCIATED(fft_scratch%pgrid)) THEN
    2745            0 :          DEALLOCATE (fft_scratch%pgrid)
    2746              :       END IF
    2747        76605 :       IF (ASSOCIATED(fft_scratch%pgcube)) THEN
    2748        35263 :          DEALLOCATE (fft_scratch%pgcube)
    2749              :       END IF
    2750        76605 :       IF (ASSOCIATED(fft_scratch%xcor)) THEN
    2751            0 :          DEALLOCATE (fft_scratch%xcor, fft_scratch%zcor)
    2752              :       END IF
    2753        76605 :       IF (ASSOCIATED(fft_scratch%pzcoord)) THEN
    2754            0 :          DEALLOCATE (fft_scratch%pzcoord)
    2755              :       END IF
    2756        76605 :       IF (ASSOCIATED(fft_scratch%xzcount)) THEN
    2757            0 :          DEALLOCATE (fft_scratch%xzcount, fft_scratch%yzcount)
    2758            0 :          DEALLOCATE (fft_scratch%xzdispl, fft_scratch%yzdispl)
    2759            0 :          fft_scratch%in = 0
    2760            0 :          fft_scratch%rsratio = 1._dp
    2761              :       END IF
    2762        76605 :       IF (ASSOCIATED(fft_scratch%rbuf1)) THEN
    2763            0 :          DEALLOCATE (fft_scratch%rbuf1)
    2764              :       END IF
    2765        76605 :       IF (ASSOCIATED(fft_scratch%rbuf2)) THEN
    2766            0 :          DEALLOCATE (fft_scratch%rbuf2)
    2767              :       END IF
    2768        76605 :       IF (ASSOCIATED(fft_scratch%rbuf3)) THEN
    2769            0 :          DEALLOCATE (fft_scratch%rbuf3)
    2770              :       END IF
    2771        76605 :       IF (ASSOCIATED(fft_scratch%rbuf4)) THEN
    2772            0 :          DEALLOCATE (fft_scratch%rbuf4)
    2773              :       END IF
    2774        76605 :       IF (ASSOCIATED(fft_scratch%rbuf5)) THEN
    2775            8 :          DEALLOCATE (fft_scratch%rbuf5)
    2776              :       END IF
    2777        76605 :       IF (ASSOCIATED(fft_scratch%rbuf6)) THEN
    2778            8 :          DEALLOCATE (fft_scratch%rbuf6)
    2779              :       END IF
    2780              : 
    2781        76605 :       IF (fft_scratch%cart_sub_comm(1) /= mp_comm_null) THEN
    2782            0 :          CALL fft_scratch%cart_sub_comm(1)%free()
    2783              :       END IF
    2784        76605 :       IF (fft_scratch%cart_sub_comm(2) /= mp_comm_null) THEN
    2785            0 :          CALL fft_scratch%cart_sub_comm(2)%free()
    2786              :       END IF
    2787              : 
    2788        76605 :       CALL fft_destroy_plan(fft_scratch%fft_plan(1))
    2789        76605 :       CALL fft_destroy_plan(fft_scratch%fft_plan(2))
    2790        76605 :       CALL fft_destroy_plan(fft_scratch%fft_plan(3))
    2791        76605 :       CALL fft_destroy_plan(fft_scratch%fft_plan(4))
    2792        76605 :       CALL fft_destroy_plan(fft_scratch%fft_plan(5))
    2793        76605 :       CALL fft_destroy_plan(fft_scratch%fft_plan(6))
    2794              : 
    2795        76605 :    END SUBROUTINE deallocate_fft_scratch_type
    2796              : 
    2797              : ! **************************************************************************************************
    2798              : !> \brief ...
    2799              : ! **************************************************************************************************
    2800        48602 :    SUBROUTINE release_fft_scratch_pool()
    2801              :       TYPE(fft_scratch_pool_type), POINTER               :: fft_scratch, fft_scratch_current
    2802              : 
    2803        48602 : !$    CPASSERT(.NOT. omp_in_parallel() .OR. 0 == omp_get_thread_num())
    2804              : 
    2805        48602 :       IF (init_fft_pool == 0) NULLIFY (fft_scratch_first)
    2806              : 
    2807        48602 :       fft_scratch => fft_scratch_first
    2808        76470 :       DO
    2809       125072 :          IF (ASSOCIATED(fft_scratch)) THEN
    2810        76470 :             fft_scratch_current => fft_scratch
    2811        76470 :             fft_scratch => fft_scratch_current%fft_scratch_next
    2812        76470 :             NULLIFY (fft_scratch_current%fft_scratch_next)
    2813              : 
    2814        76470 :             CALL deallocate_fft_scratch_type(fft_scratch_current%fft_scratch)
    2815              : 
    2816       305880 :             DEALLOCATE (fft_scratch_current%fft_scratch)
    2817        76470 :             DEALLOCATE (fft_scratch_current)
    2818              :          ELSE
    2819              :             EXIT
    2820              :          END IF
    2821              :       END DO
    2822              : 
    2823        48602 :       init_fft_pool = 0
    2824              : 
    2825        48602 :    END SUBROUTINE release_fft_scratch_pool
    2826              : 
    2827              : ! **************************************************************************************************
    2828              : !> \brief ...
    2829              : ! **************************************************************************************************
    2830      4357691 :    SUBROUTINE resize_fft_scratch_pool()
    2831              : 
    2832              :       INTEGER                                            :: last_tick, nscratch
    2833              :       TYPE(fft_scratch_pool_type), POINTER               :: fft_scratch_current, fft_scratch_old
    2834              : 
    2835      4357691 :       nscratch = 0
    2836              : 
    2837      4357691 :       last_tick = HUGE(last_tick)
    2838      4357691 :       NULLIFY (fft_scratch_old)
    2839              : 
    2840              :       ! start at the global pool, count, and find a deletion candidate
    2841      4357691 :       fft_scratch_current => fft_scratch_first
    2842     23387376 :       DO
    2843     27745067 :          IF (ASSOCIATED(fft_scratch_current)) THEN
    2844     23387376 :             nscratch = nscratch + 1
    2845              :             ! is this a candidate for deletion (i.e. least recently used, and not in use)
    2846     23387376 :             IF (.NOT. fft_scratch_current%fft_scratch%in_use) THEN
    2847     19029685 :                IF (fft_scratch_current%fft_scratch%last_tick < last_tick) THEN
    2848      9020444 :                   last_tick = fft_scratch_current%fft_scratch%last_tick
    2849      9020444 :                   fft_scratch_old => fft_scratch_current
    2850              :                END IF
    2851              :             END IF
    2852     23387376 :             fft_scratch_current => fft_scratch_current%fft_scratch_next
    2853              :          ELSE
    2854              :             EXIT
    2855              :          END IF
    2856              :       END DO
    2857              : 
    2858              :       ! we should delete a scratch
    2859      4357691 :       IF (nscratch > fft_pool_scratch_limit) THEN
    2860              :          ! note that we never deallocate the first (special) element of the list
    2861          135 :          IF (ASSOCIATED(fft_scratch_old)) THEN
    2862              :             fft_scratch_current => fft_scratch_first
    2863              :             DO
    2864         2273 :                IF (ASSOCIATED(fft_scratch_current)) THEN
    2865              :                   ! should we delete the next in the list?
    2866         2138 :                   IF (ASSOCIATED(fft_scratch_current%fft_scratch_next, fft_scratch_old)) THEN
    2867              :                      ! fix the linked list
    2868          135 :                      fft_scratch_current%fft_scratch_next => fft_scratch_old%fft_scratch_next
    2869              : 
    2870              :                      ! deallocate the element
    2871          135 :                      CALL deallocate_fft_scratch_type(fft_scratch_old%fft_scratch)
    2872          540 :                      DEALLOCATE (fft_scratch_old%fft_scratch)
    2873          135 :                      DEALLOCATE (fft_scratch_old)
    2874              : 
    2875              :                   ELSE
    2876              :                      fft_scratch_current => fft_scratch_current%fft_scratch_next
    2877              :                   END IF
    2878              :                ELSE
    2879              :                   EXIT
    2880              :                END IF
    2881              :             END DO
    2882              : 
    2883              :          ELSE
    2884            0 :             CPWARN("The number of the scratches exceeded the limit, but none could be deallocated")
    2885              :          END IF
    2886              :       END IF
    2887              : 
    2888      4357691 :    END SUBROUTINE resize_fft_scratch_pool
    2889              : 
    2890              : ! **************************************************************************************************
    2891              : !> \brief ...
    2892              : !> \param fft_scratch ...
    2893              : !> \param tf_type ...
    2894              : !> \param n ...
    2895              : !> \param fft_sizes ...
    2896              : ! **************************************************************************************************
    2897      4357691 :    SUBROUTINE get_fft_scratch(fft_scratch, tf_type, n, fft_sizes)
    2898              :       TYPE(fft_scratch_type), POINTER          :: fft_scratch
    2899              :       INTEGER, INTENT(IN)                      :: tf_type
    2900              :       INTEGER, DIMENSION(:), INTENT(IN)        :: n
    2901              :       TYPE(fft_scratch_sizes), INTENT(IN), &
    2902              :          OPTIONAL                              :: fft_sizes
    2903              : 
    2904              :       CHARACTER(len=*), PARAMETER :: routineN = 'get_fft_scratch'
    2905              : 
    2906              :       INTEGER :: coord(2), DIM(2), handle, i, ix, iz, lg, lmax, m1, m2, &
    2907              :                  mcx2, mcy3, mcz1, mcz2, mg, mmax, mx1, mx2, my1, my3, mz1, mz2, mz3, &
    2908              :                  nbx, nbz, nm, nmax, nmray, np, nx, ny, nyzray, nz, pos(2)
    2909              :       INTEGER, DIMENSION(3)                    :: pcoord
    2910              :       LOGICAL                                  :: equal
    2911              :       LOGICAL, DIMENSION(2)                    :: dims
    2912              :       TYPE(fft_scratch_pool_type), POINTER     :: fft_scratch_current, &
    2913              :                                                   fft_scratch_last, &
    2914              :                                                   fft_scratch_new
    2915              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    2916              :       INTEGER                   :: ierr
    2917              :       INTEGER(KIND=C_SIZE_T)    :: length
    2918              :       TYPE(C_PTR)               :: cptr_r1buf, cptr_tbuf, &
    2919              :                                    cptr_p2buf, cptr_p3buf, cptr_p4buf, cptr_p5buf, cptr_p7buf
    2920              : #endif
    2921      4357691 :       CALL timeset(routineN, handle)
    2922              : 
    2923              :       ! this is the place to check that the scratch_pool does not grow without limits
    2924              :       ! before we add a new scratch check the size of the pool and release some of the list if needed
    2925      4357691 :       CALL resize_fft_scratch_pool()
    2926              : 
    2927              :       ! get the required scratch
    2928      4357691 : !$OMP ATOMIC
    2929              :       tick_fft_pool = tick_fft_pool + 1
    2930      4357691 :       fft_scratch_current => fft_scratch_first
    2931              :       DO
    2932     13591105 :          IF (ASSOCIATED(fft_scratch_current)) THEN
    2933     13539843 :             IF (fft_scratch_current%fft_scratch%in_use) THEN
    2934      4357691 :                fft_scratch_last => fft_scratch_current
    2935      4357691 :                fft_scratch_current => fft_scratch_current%fft_scratch_next
    2936      4357691 :                CYCLE
    2937              :             END IF
    2938      9182152 :             IF (tf_type /= fft_scratch_current%fft_scratch%tf_type) THEN
    2939       536322 :                fft_scratch_last => fft_scratch_current
    2940       536322 :                fft_scratch_current => fft_scratch_current%fft_scratch_next
    2941       536322 :                CYCLE
    2942              :             END IF
    2943     21928682 :             IF (.NOT. ALL(n == fft_scratch_current%fft_scratch%nfft)) THEN
    2944      4219734 :                fft_scratch_last => fft_scratch_current
    2945      4219734 :                fft_scratch_current => fft_scratch_current%fft_scratch_next
    2946      4219734 :                CYCLE
    2947              :             END IF
    2948      4426096 :             IF (PRESENT(fft_sizes)) THEN
    2949      3743516 :                IF (fft_sizes%rs_group /= fft_scratch_current%fft_scratch%group) THEN
    2950       119347 :                   fft_scratch_last => fft_scratch_current
    2951       119347 :                   fft_scratch_current => fft_scratch_current%fft_scratch_next
    2952       119347 :                   CYCLE
    2953              :                END IF
    2954      3624169 :                CALL is_equal(fft_sizes, fft_scratch_current%fft_scratch%sizes, equal)
    2955      3624169 :                IF (.NOT. equal) THEN
    2956          320 :                   fft_scratch_last => fft_scratch_current
    2957          320 :                   fft_scratch_current => fft_scratch_current%fft_scratch_next
    2958          320 :                   CYCLE
    2959              :                END IF
    2960              :             END IF
    2961              :             ! Success
    2962      4306429 :             fft_scratch => fft_scratch_current%fft_scratch
    2963      4306429 :             fft_scratch_current%fft_scratch%in_use = .TRUE.
    2964      4306429 :             EXIT
    2965              :          ELSE
    2966              :             ! We cannot find the scratch type in this pool
    2967              :             ! Generate a new scratch set
    2968        51262 :             ALLOCATE (fft_scratch_new)
    2969      1332812 :             ALLOCATE (fft_scratch_new%fft_scratch)
    2970              : 
    2971        51262 :             IF (tf_type /= 400) THEN
    2972        35268 :                fft_scratch_new%fft_scratch%sizes = fft_sizes
    2973        35268 :                np = fft_sizes%numtask
    2974              :                ALLOCATE (fft_scratch_new%fft_scratch%scount(0:np - 1), fft_scratch_new%fft_scratch%rcount(0:np - 1), &
    2975              :                          fft_scratch_new%fft_scratch%sdispl(0:np - 1), fft_scratch_new%fft_scratch%rdispl(0:np - 1), &
    2976       317412 :                          fft_scratch_new%fft_scratch%pgcube(0:np - 1, 2))
    2977              :             END IF
    2978              : 
    2979            0 :             SELECT CASE (tf_type)
    2980              :             CASE DEFAULT
    2981            0 :                CPABORT("Invalid scratch type.")
    2982              :             CASE (100) ! fft3d_pb: full cube distribution
    2983            0 :                CPASSERT(PRESENT(fft_sizes))
    2984            0 :                mx1 = fft_sizes%mx1
    2985            0 :                my1 = fft_sizes%my1
    2986            0 :                mx2 = fft_sizes%mx2
    2987            0 :                mz2 = fft_sizes%mz2
    2988            0 :                my3 = fft_sizes%my3
    2989            0 :                mz3 = fft_sizes%mz3
    2990            0 :                CALL fft_alloc(fft_scratch_new%fft_scratch%a1buf, [mx1*my1, n(3)])
    2991            0 :                CALL fft_alloc(fft_scratch_new%fft_scratch%a2buf, [n(3), mx1*my1])
    2992            0 :                CALL fft_alloc(fft_scratch_new%fft_scratch%a3buf, [mx2*mz2, n(2)])
    2993            0 :                CALL fft_alloc(fft_scratch_new%fft_scratch%a4buf, [n(2), mx2*mz2])
    2994            0 :                CALL fft_alloc(fft_scratch_new%fft_scratch%a5buf, [my3*mz3, n(1)])
    2995            0 :                CALL fft_alloc(fft_scratch_new%fft_scratch%a6buf, [n(1), my3*mz3])
    2996            0 :                fft_scratch_new%fft_scratch%group = fft_sizes%rs_group
    2997              : 
    2998            0 :                dim = fft_sizes%rs_group%num_pe_cart
    2999            0 :                pos = fft_sizes%rs_group%mepos_cart
    3000            0 :                fft_scratch_new%fft_scratch%mip = fft_sizes%rs_group%mepos
    3001            0 :                fft_scratch_new%fft_scratch%dim = dim
    3002            0 :                fft_scratch_new%fft_scratch%pos = pos
    3003            0 :                mcz1 = fft_sizes%mcz1
    3004            0 :                mcx2 = fft_sizes%mcx2
    3005            0 :                mcz2 = fft_sizes%mcz2
    3006            0 :                mcy3 = fft_sizes%mcy3
    3007            0 :                ALLOCATE (fft_scratch_new%fft_scratch%rbuf1(mx2*my1*mcz2, 0:DIM(2) - 1))
    3008            0 :                ALLOCATE (fft_scratch_new%fft_scratch%rbuf2(mx1*my1*mcz2, 0:DIM(2) - 1))
    3009            0 :                ALLOCATE (fft_scratch_new%fft_scratch%rbuf3(mx2*mz3*mcy3, 0:DIM(1) - 1))
    3010            0 :                ALLOCATE (fft_scratch_new%fft_scratch%rbuf4(mx2*mz2*mcy3, 0:DIM(1) - 1))
    3011              : 
    3012            0 :                dims = [.TRUE., .FALSE.]
    3013            0 :                CALL fft_scratch_new%fft_scratch%cart_sub_comm(1)%from_sub(fft_sizes%rs_group, dims)
    3014            0 :                dims = [.FALSE., .TRUE.]
    3015            0 :                CALL fft_scratch_new%fft_scratch%cart_sub_comm(2)%from_sub(fft_sizes%rs_group, dims)
    3016              : 
    3017              :                !initialise pgcube
    3018            0 :                DO i = 0, DIM(1) - 1
    3019            0 :                   coord = [i, pos(2)]
    3020            0 :                   CALL fft_sizes%rs_group%rank_cart(coord, fft_scratch_new%fft_scratch%pgcube(i, 1))
    3021              :                END DO
    3022            0 :                DO i = 0, DIM(2) - 1
    3023            0 :                   coord = [pos(1), i]
    3024            0 :                   CALL fft_sizes%rs_group%rank_cart(coord, fft_scratch_new%fft_scratch%pgcube(i, 2))
    3025              :                END DO
    3026              : 
    3027              :                !set up fft plans
    3028              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(1), FWFFT, .TRUE., .FALSE., &
    3029              :                                        mx1*my1, n(3), n(3), mx1*my1, &
    3030            0 :                                        fft_scratch_new%fft_scratch%a1buf, fft_scratch_new%fft_scratch%a2buf)
    3031              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(2), FWFFT, .TRUE., .FALSE., &
    3032              :                                        mx2*mz2, n(2), n(2), mx2*mz2, &
    3033            0 :                                        fft_scratch_new%fft_scratch%a3buf, fft_scratch_new%fft_scratch%a4buf)
    3034              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(3), FWFFT, .TRUE., .FALSE., &
    3035              :                                        my3*mz3, n(1), n(1), my3*mz3, &
    3036            0 :                                        fft_scratch_new%fft_scratch%a5buf, fft_scratch_new%fft_scratch%a6buf)
    3037              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(4), BWFFT, .FALSE., .TRUE., &
    3038              :                                        n(1), my3*mz3, n(1), my3*mz3, &
    3039            0 :                                        fft_scratch_new%fft_scratch%a6buf, fft_scratch_new%fft_scratch%a5buf)
    3040              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(5), BWFFT, .FALSE., .TRUE., &
    3041              :                                        n(2), mx2*mz2, n(2), mx2*mz2, &
    3042            0 :                                        fft_scratch_new%fft_scratch%a4buf, fft_scratch_new%fft_scratch%a3buf)
    3043              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(6), BWFFT, .FALSE., .TRUE., &
    3044              :                                        n(3), mx1*my1, n(3), mx1*my1, &
    3045            0 :                                        fft_scratch_new%fft_scratch%a2buf, fft_scratch_new%fft_scratch%a1buf)
    3046              : 
    3047              :             CASE (101) ! fft3d_pb: full cube distribution (dim 1)
    3048            8 :                CPASSERT(PRESENT(fft_sizes))
    3049            8 :                mx1 = fft_sizes%mx1
    3050            8 :                my1 = fft_sizes%my1
    3051            8 :                mz1 = fft_sizes%mz1
    3052            8 :                my3 = fft_sizes%my3
    3053            8 :                mz3 = fft_sizes%mz3
    3054           24 :                CALL fft_alloc(fft_scratch_new%fft_scratch%a1buf, [mx1*my1, n(3)])
    3055           24 :                CALL fft_alloc(fft_scratch_new%fft_scratch%a2buf, [n(3), mx1*my1])
    3056            8 :                fft_scratch_new%fft_scratch%group = fft_sizes%rs_group
    3057           24 :                CALL fft_alloc(fft_scratch_new%fft_scratch%a3buf, [mx1*mz1, n(2)])
    3058           24 :                CALL fft_alloc(fft_scratch_new%fft_scratch%a4buf, [n(2), mx1*mz1])
    3059           24 :                CALL fft_alloc(fft_scratch_new%fft_scratch%a5buf, [my3*mz3, n(1)])
    3060           24 :                CALL fft_alloc(fft_scratch_new%fft_scratch%a6buf, [n(1), my3*mz3])
    3061              : 
    3062           24 :                dim = fft_sizes%rs_group%num_pe_cart
    3063           24 :                pos = fft_sizes%rs_group%mepos_cart
    3064            8 :                fft_scratch_new%fft_scratch%mip = fft_sizes%rs_group%mepos
    3065           24 :                fft_scratch_new%fft_scratch%dim = dim
    3066           24 :                fft_scratch_new%fft_scratch%pos = pos
    3067            8 :                mcy3 = fft_sizes%mcy3
    3068           32 :                ALLOCATE (fft_scratch_new%fft_scratch%rbuf5(mx1*mz3*mcy3, 0:DIM(1) - 1))
    3069           32 :                ALLOCATE (fft_scratch_new%fft_scratch%rbuf6(mx1*mz1*mcy3, 0:DIM(1) - 1))
    3070              : 
    3071              :                !set up fft plans
    3072              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(1), FWFFT, .TRUE., .FALSE., &
    3073              :                                        mx1*my1, n(3), n(3), mx1*my1, &
    3074            8 :                                        fft_scratch_new%fft_scratch%a1buf, fft_scratch_new%fft_scratch%a3buf)
    3075              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(2), FWFFT, .TRUE., .FALSE., &
    3076              :                                        mx1*mz1, n(2), n(2), mx1*mz1, &
    3077            8 :                                        fft_scratch_new%fft_scratch%a3buf, fft_scratch_new%fft_scratch%a4buf)
    3078              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(3), FWFFT, .TRUE., .FALSE., &
    3079              :                                        my3*mz3, n(1), n(1), my3*mz3, &
    3080            8 :                                        fft_scratch_new%fft_scratch%a5buf, fft_scratch_new%fft_scratch%a6buf)
    3081              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(4), BWFFT, .FALSE., .TRUE., &
    3082              :                                        n(1), my3*mz3, n(1), my3*mz3, &
    3083            8 :                                        fft_scratch_new%fft_scratch%a6buf, fft_scratch_new%fft_scratch%a5buf)
    3084              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(5), BWFFT, .FALSE., .TRUE., &
    3085              :                                        n(2), mx1*mz1, n(2), mx1*mz1, &
    3086            8 :                                        fft_scratch_new%fft_scratch%a4buf, fft_scratch_new%fft_scratch%a3buf)
    3087              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(6), BWFFT, .FALSE., .TRUE., &
    3088              :                                        n(3), mx1*my1, n(3), mx1*my1, &
    3089            8 :                                        fft_scratch_new%fft_scratch%a3buf, fft_scratch_new%fft_scratch%a1buf)
    3090              : 
    3091              :             CASE (200) ! fft3d_ps: plane distribution
    3092        35260 :                CPASSERT(PRESENT(fft_sizes))
    3093        35260 :                nx = fft_sizes%nx
    3094        35260 :                ny = fft_sizes%ny
    3095        35260 :                nz = fft_sizes%nz
    3096        35260 :                mx2 = fft_sizes%mx2
    3097        35260 :                lmax = fft_sizes%lmax
    3098        35260 :                mmax = fft_sizes%mmax
    3099        35260 :                lg = fft_sizes%lg
    3100        35260 :                mg = fft_sizes%mg
    3101        35260 :                np = fft_sizes%numtask
    3102        35260 :                nmray = fft_sizes%nmray
    3103        35260 :                nyzray = fft_sizes%nyzray
    3104              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    3105              :                length = INT(2*dp_size*MAX(mmax, 1)*MAX(lmax, 1), KIND=C_SIZE_T)
    3106              :                ierr = offload_malloc_pinned_mem(cptr_r1buf, length)
    3107              :                CPASSERT(ierr == 0)
    3108              :                CALL c_f_pointer(cptr_r1buf, fft_scratch_new%fft_scratch%r1buf, [MAX(mmax, 1), MAX(lmax, 1)])
    3109              :                length = INT(2*dp_size*MAX(ny, 1)*MAX(nz, 1)*MAX(nx, 1), KIND=C_SIZE_T)
    3110              :                ierr = offload_malloc_pinned_mem(cptr_tbuf, length)
    3111              :                CPASSERT(ierr == 0)
    3112              :                CALL c_f_pointer(cptr_tbuf, fft_scratch_new%fft_scratch%tbuf, [MAX(ny, 1), MAX(nz, 1), MAX(nx, 1)])
    3113              : #else
    3114       105780 :                CALL fft_alloc(fft_scratch_new%fft_scratch%r1buf, [mmax, lmax])
    3115       141040 :                CALL fft_alloc(fft_scratch_new%fft_scratch%tbuf, [ny, nz, nx])
    3116              : #endif
    3117        35260 :                fft_scratch_new%fft_scratch%group = fft_sizes%rs_group
    3118       105780 :                CALL fft_alloc(fft_scratch_new%fft_scratch%r2buf, [lg, mg])
    3119        35260 :                nm = nmray*mx2
    3120        35260 :                IF (alltoall_sgl) THEN
    3121           32 :                   ALLOCATE (fft_scratch_new%fft_scratch%ss(mmax, lmax))
    3122           32 :                   ALLOCATE (fft_scratch_new%fft_scratch%tt(nm, 0:np - 1))
    3123              :                ELSE
    3124       141008 :                   ALLOCATE (fft_scratch_new%fft_scratch%rr(nm, 0:np - 1))
    3125              :                END IF
    3126              : 
    3127              :                !set up fft plans
    3128              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(1), FWFFT, .TRUE., .FALSE., &
    3129              :                                        nx*ny, nz, nz, nx*ny, &
    3130        35260 :                                        fft_scratch_new%fft_scratch%tbuf, fft_scratch_new%fft_scratch%r1buf)
    3131              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(2), FWFFT, .TRUE., .FALSE., &
    3132              :                                        nx*nz, ny, ny, nx*nz, &
    3133        35260 :                                        fft_scratch_new%fft_scratch%r1buf, fft_scratch_new%fft_scratch%tbuf)
    3134              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(3), FWFFT, .TRUE., .FALSE., &
    3135              :                                        nyzray, n(1), n(1), nyzray, &
    3136        35260 :                                        fft_scratch_new%fft_scratch%r1buf, fft_scratch_new%fft_scratch%r2buf)
    3137              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(4), BWFFT, .FALSE., .TRUE., &
    3138              :                                        n(1), nyzray, n(1), nyzray, &
    3139        35260 :                                        fft_scratch_new%fft_scratch%r2buf, fft_scratch_new%fft_scratch%r1buf)
    3140              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(5), BWFFT, .FALSE., .TRUE., &
    3141              :                                        ny, nx*nz, ny, nx*nz, &
    3142        35260 :                                        fft_scratch_new%fft_scratch%tbuf, fft_scratch_new%fft_scratch%r1buf)
    3143              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(6), BWFFT, .FALSE., .TRUE., &
    3144              :                                        nz, nx*ny, nz, nx*ny, &
    3145        35260 :                                        fft_scratch_new%fft_scratch%r1buf, fft_scratch_new%fft_scratch%tbuf)
    3146              : 
    3147              :             CASE (300) ! fft3d_ps: block distribution
    3148            0 :                CPASSERT(PRESENT(fft_sizes))
    3149            0 :                mx1 = fft_sizes%mx1
    3150            0 :                mx2 = fft_sizes%mx2
    3151            0 :                my1 = fft_sizes%my1
    3152            0 :                mz2 = fft_sizes%mz2
    3153            0 :                mcx2 = fft_sizes%mcx2
    3154            0 :                lg = fft_sizes%lg
    3155            0 :                mg = fft_sizes%mg
    3156            0 :                nmax = fft_sizes%nmax
    3157            0 :                nmray = fft_sizes%nmray
    3158            0 :                nyzray = fft_sizes%nyzray
    3159            0 :                m1 = fft_sizes%r_dim(1)
    3160            0 :                m2 = fft_sizes%r_dim(2)
    3161            0 :                nbx = fft_sizes%nbx
    3162            0 :                nbz = fft_sizes%nbz
    3163            0 :                CALL fft_alloc(fft_scratch_new%fft_scratch%p1buf, [mx1*my1, n(3)])
    3164            0 :                CALL fft_alloc(fft_scratch_new%fft_scratch%p6buf, [lg, mg])
    3165              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    3166              :                length = INT(2*dp_size*MAX(n(3), 1)*MAX(mx1*my1, 1), KIND=C_SIZE_T)
    3167              :                ierr = offload_malloc_pinned_mem(cptr_p2buf, length)
    3168              :                CPASSERT(ierr == 0)
    3169              :                CALL c_f_pointer(cptr_p2buf, fft_scratch_new%fft_scratch%p2buf, [MAX(n(3), 1), MAX(mx1*my1, 1)])
    3170              :                length = INT(2*dp_size*MAX(mx2*mz2, 1)*MAX(n(2), 1), KIND=C_SIZE_T)
    3171              :                ierr = offload_malloc_pinned_mem(cptr_p3buf, length)
    3172              :                CPASSERT(ierr == 0)
    3173              :                CALL c_f_pointer(cptr_p3buf, fft_scratch_new%fft_scratch%p3buf, [MAX(mx2*mz2, 1), MAX(n(2), 1)])
    3174              :                length = INT(2*dp_size*MAX(n(2), 1)*MAX(mx2*mz2, 1), KIND=C_SIZE_T)
    3175              :                ierr = offload_malloc_pinned_mem(cptr_p4buf, length)
    3176              :                CPASSERT(ierr == 0)
    3177              :                CALL c_f_pointer(cptr_p4buf, fft_scratch_new%fft_scratch%p4buf, [MAX(n(2), 1), MAX(mx2*mz2, 1)])
    3178              :                length = INT(2*dp_size*MAX(nyzray, 1)*MAX(n(1), 1), KIND=C_SIZE_T)
    3179              :                ierr = offload_malloc_pinned_mem(cptr_p5buf, length)
    3180              :                CPASSERT(ierr == 0)
    3181              :                CALL c_f_pointer(cptr_p5buf, fft_scratch_new%fft_scratch%p5buf, [MAX(nyzray, 1), MAX(n(1), 1)])
    3182              :                length = INT(2*dp_size*MAX(mg, 1)*MAX(lg, 1), KIND=C_SIZE_T)
    3183              :                ierr = offload_malloc_pinned_mem(cptr_p7buf, length)
    3184              :                CPASSERT(ierr == 0)
    3185              :                CALL c_f_pointer(cptr_p7buf, fft_scratch_new%fft_scratch%p7buf, [MAX(mg, 1), MAX(lg, 1)])
    3186              : #else
    3187            0 :                CALL fft_alloc(fft_scratch_new%fft_scratch%p2buf, [n(3), mx1*my1])
    3188            0 :                CALL fft_alloc(fft_scratch_new%fft_scratch%p3buf, [mx2*mz2, n(2)])
    3189            0 :                CALL fft_alloc(fft_scratch_new%fft_scratch%p4buf, [n(2), mx2*mz2])
    3190            0 :                CALL fft_alloc(fft_scratch_new%fft_scratch%p5buf, [nyzray, n(1)])
    3191            0 :                CALL fft_alloc(fft_scratch_new%fft_scratch%p7buf, [mg, lg])
    3192              : #endif
    3193            0 :                IF (alltoall_sgl) THEN
    3194            0 :                   ALLOCATE (fft_scratch_new%fft_scratch%yzbuf_sgl(mg*lg))
    3195            0 :                   ALLOCATE (fft_scratch_new%fft_scratch%xzbuf_sgl(n(2)*mx2*mz2))
    3196              :                ELSE
    3197            0 :                   ALLOCATE (fft_scratch_new%fft_scratch%yzbuf(mg*lg))
    3198            0 :                   ALLOCATE (fft_scratch_new%fft_scratch%xzbuf(n(2)*mx2*mz2))
    3199              :                END IF
    3200            0 :                ALLOCATE (fft_scratch_new%fft_scratch%pgrid(0:m1 - 1, 0:m2 - 1))
    3201            0 :                ALLOCATE (fft_scratch_new%fft_scratch%xcor(nbx))
    3202            0 :                ALLOCATE (fft_scratch_new%fft_scratch%zcor(nbz))
    3203            0 :                ALLOCATE (fft_scratch_new%fft_scratch%pzcoord(0:np - 1))
    3204              :                ALLOCATE (fft_scratch_new%fft_scratch%xzcount(0:np - 1), &
    3205            0 :                          fft_scratch_new%fft_scratch%yzcount(0:np - 1))
    3206              :                ALLOCATE (fft_scratch_new%fft_scratch%xzdispl(0:np - 1), &
    3207            0 :                          fft_scratch_new%fft_scratch%yzdispl(0:np - 1))
    3208            0 :                fft_scratch_new%fft_scratch%group = fft_sizes%rs_group
    3209              : 
    3210            0 :                dim = fft_sizes%rs_group%num_pe_cart
    3211            0 :                pos = fft_sizes%rs_group%mepos_cart
    3212            0 :                fft_scratch_new%fft_scratch%mip = fft_sizes%rs_group%mepos
    3213            0 :                fft_scratch_new%fft_scratch%dim = dim
    3214            0 :                fft_scratch_new%fft_scratch%pos = pos
    3215            0 :                mcz1 = fft_sizes%mcz1
    3216            0 :                mcz2 = fft_sizes%mcz2
    3217            0 :                ALLOCATE (fft_scratch_new%fft_scratch%rbuf1(mx2*my1*mcz2, 0:DIM(2) - 1))
    3218            0 :                ALLOCATE (fft_scratch_new%fft_scratch%rbuf2(mx1*my1*mcz2, 0:DIM(2) - 1))
    3219              : 
    3220            0 :                dims = [.FALSE., .TRUE.]
    3221            0 :                CALL fft_scratch_new%fft_scratch%cart_sub_comm(2)%from_sub(fft_sizes%rs_group, dims)
    3222              : 
    3223              :                !initialise pgcube
    3224            0 :                DO i = 0, DIM(2) - 1
    3225            0 :                   coord = [pos(1), i]
    3226            0 :                   CALL fft_sizes%rs_group%rank_cart(coord, fft_scratch_new%fft_scratch%pgcube(i, 2))
    3227              :                END DO
    3228              : 
    3229              :                !initialise pgrid
    3230            0 :                DO ix = 0, m1 - 1
    3231            0 :                   DO iz = 0, m2 - 1
    3232            0 :                      coord = [ix, iz]
    3233            0 :                      CALL fft_sizes%rs_group%rank_cart(coord, fft_scratch_new%fft_scratch%pgrid(ix, iz))
    3234              :                   END DO
    3235              :                END DO
    3236              : 
    3237              :                !initialise pzcoord
    3238            0 :                DO i = 0, np - 1
    3239            0 :                   CALL fft_sizes%rs_group%coords(i, pcoord)
    3240            0 :                   fft_scratch_new%fft_scratch%pzcoord(i) = pcoord(2)
    3241              :                END DO
    3242              : 
    3243              :                !set up fft plans
    3244              :                ! The scratch buffers must cover the geometry declared in each call
    3245              :                ! below, because the FFTW planner may write the buffers during
    3246              :                ! planning. The plans pair the buffers such that each of p1-p6 is
    3247              :                ! checked once; p7 shares the size of p6.
    3248            0 :                CPASSERT(SIZE(fft_scratch_new%fft_scratch%p1buf) >= mx1*my1*n(3))
    3249              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(1), FWFFT, .TRUE., .FALSE., &
    3250              :                                        mx1*my1, n(3), n(3), mx1*my1, &
    3251            0 :                                        fft_scratch_new%fft_scratch%p1buf, fft_scratch_new%fft_scratch%p2buf)
    3252            0 :                CPASSERT(SIZE(fft_scratch_new%fft_scratch%p3buf) >= mx2*mz2*n(2))
    3253              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(2), FWFFT, .TRUE., .FALSE., &
    3254              :                                        mx2*mz2, n(2), n(2), mx2*mz2, &
    3255            0 :                                        fft_scratch_new%fft_scratch%p3buf, fft_scratch_new%fft_scratch%p4buf)
    3256            0 :                CPASSERT(SIZE(fft_scratch_new%fft_scratch%p5buf) >= nyzray*n(1))
    3257              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(3), FWFFT, .TRUE., .FALSE., &
    3258              :                                        nyzray, n(1), n(1), nyzray, &
    3259            0 :                                        fft_scratch_new%fft_scratch%p5buf, fft_scratch_new%fft_scratch%p6buf)
    3260            0 :                CPASSERT(SIZE(fft_scratch_new%fft_scratch%p6buf) >= n(1)*nyzray)
    3261              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(4), BWFFT, .FALSE., .TRUE., &
    3262              :                                        n(1), nyzray, n(1), nyzray, &
    3263            0 :                                        fft_scratch_new%fft_scratch%p6buf, fft_scratch_new%fft_scratch%p7buf)
    3264            0 :                CPASSERT(SIZE(fft_scratch_new%fft_scratch%p4buf) >= n(2)*mx2*mz2)
    3265              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(5), BWFFT, .FALSE., .TRUE., &
    3266              :                                        n(2), mx2*mz2, n(2), mx2*mz2, &
    3267            0 :                                        fft_scratch_new%fft_scratch%p4buf, fft_scratch_new%fft_scratch%p3buf)
    3268            0 :                CPASSERT(SIZE(fft_scratch_new%fft_scratch%p2buf) >= n(3)*mx1*my1)
    3269              :                CALL fft_create_plan_1d(fft_scratch_new%fft_scratch%fft_plan(6), BWFFT, .FALSE., .TRUE., &
    3270              :                                        n(3), mx1*my1, n(3), mx1*my1, &
    3271            0 :                                        fft_scratch_new%fft_scratch%p2buf, fft_scratch_new%fft_scratch%p1buf)
    3272              : 
    3273              :             CASE (400) ! serial FFT
    3274        15994 :                np = 0
    3275        15994 :                CALL fft_alloc(fft_scratch_new%fft_scratch%ziptr, n)
    3276        15994 :                CALL fft_alloc(fft_scratch_new%fft_scratch%zoptr, n)
    3277              : 
    3278              :                !in place plans
    3279              :                CALL fft_create_plan_3d(fft_scratch_new%fft_scratch%fft_plan(1), .TRUE., FWFFT, n, &
    3280        15994 :                                        fft_scratch_new%fft_scratch%ziptr, fft_scratch_new%fft_scratch%ziptr)
    3281              :                CALL fft_create_plan_3d(fft_scratch_new%fft_scratch%fft_plan(2), .TRUE., BWFFT, n, &
    3282        15994 :                                        fft_scratch_new%fft_scratch%ziptr, fft_scratch_new%fft_scratch%ziptr)
    3283              :                ! out of place plans
    3284              :                CALL fft_create_plan_3d(fft_scratch_new%fft_scratch%fft_plan(3), .FALSE., FWFFT, n, &
    3285        15994 :                                        fft_scratch_new%fft_scratch%ziptr, fft_scratch_new%fft_scratch%zoptr)
    3286              :                CALL fft_create_plan_3d(fft_scratch_new%fft_scratch%fft_plan(4), .FALSE., BWFFT, n, &
    3287        67256 :                                        fft_scratch_new%fft_scratch%ziptr, fft_scratch_new%fft_scratch%zoptr)
    3288              : 
    3289              :             END SELECT
    3290              : 
    3291        51262 :             NULLIFY (fft_scratch_new%fft_scratch_next)
    3292              :             fft_scratch_new%fft_scratch%fft_scratch_id = &
    3293        51262 :                fft_scratch_last%fft_scratch%fft_scratch_id + 1
    3294        51262 :             fft_scratch_new%fft_scratch%in_use = .TRUE.
    3295       205048 :             fft_scratch_new%fft_scratch%nfft = n
    3296        51262 :             fft_scratch_last%fft_scratch_next => fft_scratch_new
    3297        51262 :             fft_scratch_new%fft_scratch%tf_type = tf_type
    3298        51262 :             fft_scratch => fft_scratch_new%fft_scratch
    3299        51262 :             EXIT
    3300              : 
    3301              :          END IF
    3302              :       END DO
    3303              : 
    3304      4357691 : !$OMP ATOMIC READ
    3305              :       fft_scratch%last_tick = tick_fft_pool
    3306              : 
    3307      4357691 :       CALL timestop(handle)
    3308              : 
    3309      4357691 :    END SUBROUTINE get_fft_scratch
    3310              : 
    3311              : ! **************************************************************************************************
    3312              : !> \brief ...
    3313              : !> \param fft_scratch ...
    3314              : ! **************************************************************************************************
    3315      4357691 :    SUBROUTINE release_fft_scratch(fft_scratch)
    3316              : 
    3317              :       TYPE(fft_scratch_type), POINTER                    :: fft_scratch
    3318              : 
    3319              :       INTEGER                                            :: scratch_id
    3320              :       TYPE(fft_scratch_pool_type), POINTER               :: fft_scratch_current
    3321              : 
    3322      4357691 :       scratch_id = fft_scratch%fft_scratch_id
    3323              : 
    3324      4357691 :       fft_scratch_current => fft_scratch_first
    3325      9233414 :       DO
    3326     13591105 :          IF (ASSOCIATED(fft_scratch_current)) THEN
    3327     13591105 :             IF (scratch_id == fft_scratch_current%fft_scratch%fft_scratch_id) THEN
    3328      4357691 :                fft_scratch%in_use = .FALSE.
    3329      4357691 :                NULLIFY (fft_scratch)
    3330      4357691 :                EXIT
    3331              :             END IF
    3332      9233414 :             fft_scratch_current => fft_scratch_current%fft_scratch_next
    3333              :          ELSE
    3334              :             ! We cannot find the scratch type in this pool
    3335            0 :             CPABORT("Invalid scratch type.")
    3336            0 :             EXIT
    3337              :          END IF
    3338              :       END DO
    3339              : 
    3340      4357691 :    END SUBROUTINE release_fft_scratch
    3341              : 
    3342              : ! **************************************************************************************************
    3343              : !> \brief ...
    3344              : !> \param rs ...
    3345              : !> \param scount ...
    3346              : !> \param sdispl ...
    3347              : !> \param rq ...
    3348              : !> \param rcount ...
    3349              : !> \param rdispl ...
    3350              : !> \param group ...
    3351              : ! **************************************************************************************************
    3352            0 :    SUBROUTINE sparse_alltoall(rs, scount, sdispl, rq, rcount, rdispl, group)
    3353              :       COMPLEX(KIND=dp), DIMENSION(:), POINTER            :: rs
    3354              :       INTEGER, DIMENSION(:), POINTER                     :: scount, sdispl
    3355              :       COMPLEX(KIND=dp), DIMENSION(:), POINTER            :: rq
    3356              :       INTEGER, DIMENSION(:), POINTER                     :: rcount, rdispl
    3357              : 
    3358              :       CLASS(mp_comm_type), INTENT(IN)                    :: group
    3359              : 
    3360            0 :       COMPLEX(KIND=dp), DIMENSION(:), POINTER            :: msgin, msgout
    3361              :       INTEGER                                            :: ip, n, nr, ns, pos
    3362            0 :       TYPE(mp_request_type), ALLOCATABLE, DIMENSION(:)   :: rreq, sreq
    3363              : 
    3364            0 :       CALL group%sync()
    3365            0 :       n = group%num_pe
    3366            0 :       pos = group%mepos
    3367            0 :       ALLOCATE (sreq(0:n - 1))
    3368            0 :       ALLOCATE (rreq(0:n - 1))
    3369            0 :       nr = 0
    3370            0 :       DO ip = 0, n - 1
    3371            0 :          IF (rcount(ip) == 0) CYCLE
    3372            0 :          IF (ip == pos) CYCLE
    3373            0 :          msgout => rq(rdispl(ip) + 1:rdispl(ip) + rcount(ip))
    3374            0 :          CALL group%irecv(msgout, ip, rreq(nr))
    3375            0 :          nr = nr + 1
    3376              :       END DO
    3377            0 :       ns = 0
    3378            0 :       DO ip = 0, n - 1
    3379            0 :          IF (scount(ip) == 0) CYCLE
    3380            0 :          IF (ip == pos) CYCLE
    3381            0 :          msgin => rs(sdispl(ip) + 1:sdispl(ip) + scount(ip))
    3382            0 :          CALL group%isend(msgin, ip, sreq(ns))
    3383            0 :          ns = ns + 1
    3384              :       END DO
    3385            0 :       IF (rcount(pos) /= 0) THEN
    3386            0 :          IF (rcount(pos) /= scount(pos)) CPABORT("Invalid count.")
    3387            0 :          rq(rdispl(pos) + 1:rdispl(pos) + rcount(pos)) = rs(sdispl(pos) + 1:sdispl(pos) + scount(pos))
    3388              :       END IF
    3389            0 :       CALL mp_waitall(sreq(0:ns - 1))
    3390            0 :       CALL mp_waitall(rreq(0:nr - 1))
    3391            0 :       DEALLOCATE (sreq)
    3392            0 :       DEALLOCATE (rreq)
    3393            0 :       CALL group%sync()
    3394              : 
    3395            0 :    END SUBROUTINE sparse_alltoall
    3396              : 
    3397              : ! **************************************************************************************************
    3398              : !> \brief  test data structures for equality. It is assumed that if they are
    3399              : !>         different for one mpi task they are different for all (??)
    3400              : !> \param fft_size_1 ...
    3401              : !> \param fft_size_2 ...
    3402              : !> \param equal ...
    3403              : ! **************************************************************************************************
    3404      3624169 :    SUBROUTINE is_equal(fft_size_1, fft_size_2, equal)
    3405              :       TYPE(fft_scratch_sizes)                            :: fft_size_1, fft_size_2
    3406              :       LOGICAL                                            :: equal
    3407              : 
    3408              :       equal = .TRUE.
    3409              : 
    3410      3624169 :       equal = equal .AND. fft_size_1%nx == fft_size_2%nx
    3411      3624169 :       equal = equal .AND. fft_size_1%ny == fft_size_2%ny
    3412      3624169 :       equal = equal .AND. fft_size_1%nz == fft_size_2%nz
    3413              : 
    3414      3624169 :       equal = equal .AND. fft_size_1%lmax == fft_size_2%lmax
    3415      3624169 :       equal = equal .AND. fft_size_1%mmax == fft_size_2%mmax
    3416      3624169 :       equal = equal .AND. fft_size_1%nmax == fft_size_2%nmax
    3417              : 
    3418      3624169 :       equal = equal .AND. fft_size_1%mx1 == fft_size_2%mx1
    3419      3624169 :       equal = equal .AND. fft_size_1%mx2 == fft_size_2%mx2
    3420      3624169 :       equal = equal .AND. fft_size_1%mx3 == fft_size_2%mx3
    3421              : 
    3422      3624169 :       equal = equal .AND. fft_size_1%my1 == fft_size_2%my1
    3423      3624169 :       equal = equal .AND. fft_size_1%my2 == fft_size_2%my2
    3424      3624169 :       equal = equal .AND. fft_size_1%my3 == fft_size_2%my3
    3425              : 
    3426      3624169 :       equal = equal .AND. fft_size_1%mcz1 == fft_size_2%mcz1
    3427      3624169 :       equal = equal .AND. fft_size_1%mcx2 == fft_size_2%mcx2
    3428      3624169 :       equal = equal .AND. fft_size_1%mcz2 == fft_size_2%mcz2
    3429      3624169 :       equal = equal .AND. fft_size_1%mcy3 == fft_size_2%mcy3
    3430              : 
    3431      3624169 :       equal = equal .AND. fft_size_1%lg == fft_size_2%lg
    3432      3624169 :       equal = equal .AND. fft_size_1%mg == fft_size_2%mg
    3433              : 
    3434      3624169 :       equal = equal .AND. fft_size_1%nbx == fft_size_2%nbx
    3435      3624169 :       equal = equal .AND. fft_size_1%nbz == fft_size_2%nbz
    3436              : 
    3437      3624169 :       equal = equal .AND. fft_size_1%nmray == fft_size_2%nmray
    3438      3624169 :       equal = equal .AND. fft_size_1%nyzray == fft_size_2%nyzray
    3439              : 
    3440      3624169 :       equal = equal .AND. fft_size_1%rs_group == fft_size_2%rs_group
    3441              : 
    3442     10872507 :       equal = equal .AND. ALL(fft_size_1%g_pos == fft_size_2%g_pos)
    3443     10872507 :       equal = equal .AND. ALL(fft_size_1%r_pos == fft_size_2%r_pos)
    3444     10872507 :       equal = equal .AND. ALL(fft_size_1%r_dim == fft_size_2%r_dim)
    3445              : 
    3446      3624169 :       equal = equal .AND. fft_size_1%numtask == fft_size_2%numtask
    3447              : 
    3448      3624169 :    END SUBROUTINE is_equal
    3449              : 
    3450            0 : END MODULE fft_tools
        

Generated by: LCOV version 2.0-1