LCOV - code coverage report
Current view: top level - src/pw - pw_grids.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:e08e82d) Lines: 94.2 % 981 924
Test Date: 2026-10-16 00:55:08 Functions: 100.0 % 25 25

            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              : !> \brief This module defines the grid data type and some basic operations on it
      10              : !> \note
      11              : !>      pw_grid_create : set the defaults
      12              : !>      pw_grid_release : release all memory connected to type
      13              : !>      pw_grid_setup  : main routine to set up a grid
      14              : !>           input: cell (the box for the grid)
      15              : !>                  pw_grid (the grid; pw_grid%grid_span has to be set)
      16              : !>                  cutoff (optional, if not given pw_grid%bounds has to be set)
      17              : !>                  pe_group (optional, if not given we have a local grid)
      18              : !>
      19              : !>                  if no cutoff or a negative cutoff is given, all g-vectors
      20              : !>                  in the box are included (no spherical cutoff)
      21              : !>
      22              : !>                  for a distributed setup the array in para rs_dims has to
      23              : !>                  be initialized
      24              : !>           output: pw_grid
      25              : !>
      26              : !>      pw_grid_change : updates g-vectors after a change of the box
      27              : !> \par History
      28              : !>      JGH (20-12-2000) : Adapted for parallel use
      29              : !>      JGH (07-02-2001) : Added constructor and destructor routines
      30              : !>      JGH (21-02-2003) : Generalized reference grid concept
      31              : !>      JGH (19-11-2007) : Refactoring and modularization
      32              : !>      JGH (21-12-2007) : pw_grid_setup refactoring
      33              : !> \author apsi
      34              : !>      CJM
      35              : ! **************************************************************************************************
      36              : MODULE pw_grids
      37              :    USE ISO_C_BINDING,                   ONLY: C_F_POINTER,&
      38              :                                               C_LOC,&
      39              :                                               C_PTR,&
      40              :                                               C_SIZE_T
      41              :    USE kinds,                           ONLY: dp,&
      42              :                                               int_8,&
      43              :                                               int_size
      44              :    USE mathconstants,                   ONLY: twopi
      45              :    USE mathlib,                         ONLY: det_3x3,&
      46              :                                               inv_3x3
      47              :    USE message_passing,                 ONLY: mp_comm_self,&
      48              :                                               mp_comm_type,&
      49              :                                               mp_dims_create
      50              :    USE offload_api,                     ONLY: offload_activate_chosen_device,&
      51              :                                               offload_free_pinned_mem,&
      52              :                                               offload_malloc_pinned_mem
      53              :    USE pw_grid_info,                    ONLY: pw_find_cutoff,&
      54              :                                               pw_grid_bounds_from_n,&
      55              :                                               pw_grid_init_setup
      56              :    USE pw_grid_types,                   ONLY: FULLSPACE,&
      57              :                                               HALFSPACE,&
      58              :                                               PW_MODE_DISTRIBUTED,&
      59              :                                               PW_MODE_LOCAL,&
      60              :                                               map_pn,&
      61              :                                               pw_grid_type
      62              :    USE util,                            ONLY: get_limit,&
      63              :                                               sort
      64              : #include "../base/base_uses.f90"
      65              : 
      66              :    IMPLICIT NONE
      67              : 
      68              :    PRIVATE
      69              :    PUBLIC :: pw_grid_create, pw_grid_retain, pw_grid_release
      70              :    PUBLIC :: get_pw_grid_info, pw_grid_compare
      71              :    PUBLIC :: pw_grid_change
      72              : 
      73              :    INTEGER :: grid_tag = 0
      74              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pw_grids'
      75              : 
      76              :    ! Distribution in g-space can be
      77              :    INTEGER, PARAMETER, PUBLIC               :: do_pw_grid_blocked_false = 0, &
      78              :                                                do_pw_grid_blocked_true = 1, &
      79              :                                                do_pw_grid_blocked_free = 2
      80              : 
      81              :    INTERFACE pw_grid_create
      82              :       MODULE PROCEDURE pw_grid_create_local
      83              :       MODULE PROCEDURE pw_grid_create_extended
      84              :    END INTERFACE
      85              : 
      86              : CONTAINS
      87              : 
      88              : ! **************************************************************************************************
      89              : !> \brief Initialize a PW grid with bounds only (used by some routines)
      90              : !> \param pw_grid ...
      91              : !> \param bounds ...
      92              : !> \par History
      93              : !>      JGH (21-Feb-2003) : initialize pw_grid%reference
      94              : !> \author JGH (7-Feb-2001) & fawzi
      95              : ! **************************************************************************************************
      96        92762 :    SUBROUTINE pw_grid_create_local(pw_grid, bounds)
      97              : 
      98              :       TYPE(pw_grid_type), POINTER                        :: pw_grid
      99              :       INTEGER, DIMENSION(2, 3), INTENT(IN)               :: bounds
     100              : 
     101              :       INTEGER, DIMENSION(2)                              :: rs_dims
     102              : 
     103        92762 :       CPASSERT(.NOT. ASSOCIATED(pw_grid))
     104      5472958 :       ALLOCATE (pw_grid)
     105       927620 :       pw_grid%bounds = bounds
     106       927620 :       pw_grid%bounds_local = bounds
     107       371048 :       pw_grid%npts = bounds(2, :) - bounds(1, :) + 1
     108       371048 :       pw_grid%npts_local = pw_grid%npts
     109       371048 :       pw_grid%ngpts = PRODUCT(INT(pw_grid%npts, KIND=int_8))
     110        92762 :       pw_grid%ngpts_cut = pw_grid%ngpts
     111       371048 :       pw_grid%ngpts_local = PRODUCT(pw_grid%npts)
     112        92762 :       pw_grid%ngpts_cut_local = pw_grid%ngpts_local
     113        92762 :       pw_grid%grid_span = FULLSPACE
     114        92762 :       pw_grid%para%mode = PW_MODE_LOCAL
     115        92762 :       pw_grid%reference = 0
     116        92762 :       pw_grid%ref_count = 1
     117        92762 :       NULLIFY (pw_grid%g)
     118        92762 :       NULLIFY (pw_grid%gsq)
     119        92762 :       NULLIFY (pw_grid%g_hatmap)
     120        92762 :       NULLIFY (pw_grid%gidx)
     121        92762 :       NULLIFY (pw_grid%grays)
     122              : 
     123              :       ! assign a unique tag to this grid
     124        92762 :       grid_tag = grid_tag + 1
     125        92762 :       pw_grid%id_nr = grid_tag
     126              : 
     127              :       ! parallel info
     128       278286 :       rs_dims = 1
     129        92762 :       CALL pw_grid%para%group%create(mp_comm_self, 2, rs_dims)
     130        92762 :       IF (pw_grid%para%group%num_pe > 1) THEN
     131            0 :          pw_grid%para%mode = PW_MODE_DISTRIBUTED
     132              :       ELSE
     133        92762 :          pw_grid%para%mode = PW_MODE_LOCAL
     134              :       END IF
     135              : 
     136        92762 :    END SUBROUTINE pw_grid_create_local
     137              : 
     138              : ! **************************************************************************************************
     139              : !> \brief Check if two pw_grids are equal
     140              : !> \param grida ...
     141              : !> \param gridb ...
     142              : !> \return ...
     143              : !> \par History
     144              : !>      none
     145              : !> \author JGH (14-Feb-2001)
     146              : ! **************************************************************************************************
     147      9388880 :    FUNCTION pw_grid_compare(grida, gridb) RESULT(equal)
     148              : 
     149              :       TYPE(pw_grid_type), INTENT(IN)                     :: grida, gridb
     150              :       LOGICAL                                            :: equal
     151              : 
     152              : !------------------------------------------------------------------------------
     153              : 
     154      9388880 :       IF (grida%id_nr == gridb%id_nr) THEN
     155              :          equal = .TRUE.
     156              :       ELSE
     157              :          ! for the moment all grids with different identifiers are considered as not equal
     158              :          ! later we can get this more relaxed
     159         1368 :          equal = .FALSE.
     160              :       END IF
     161              : 
     162      9388880 :    END FUNCTION pw_grid_compare
     163              : 
     164              : ! **************************************************************************************************
     165              : !> \brief Access to information stored in the pw_grid_type
     166              : !> \param pw_grid ...
     167              : !> \param id_nr ...
     168              : !> \param mode ...
     169              : !> \param vol ...
     170              : !> \param dvol ...
     171              : !> \param npts ...
     172              : !> \param ngpts ...
     173              : !> \param ngpts_cut ...
     174              : !> \param dr ...
     175              : !> \param cutoff ...
     176              : !> \param orthorhombic ...
     177              : !> \param gvectors ...
     178              : !> \param gsquare ...
     179              : !> \par History
     180              : !>      none
     181              : !> \author JGH (17-Nov-2007)
     182              : ! **************************************************************************************************
     183        78730 :    SUBROUTINE get_pw_grid_info(pw_grid, id_nr, mode, vol, dvol, npts, ngpts, &
     184              :                                ngpts_cut, dr, cutoff, orthorhombic, gvectors, gsquare)
     185              : 
     186              :       TYPE(pw_grid_type), INTENT(IN)                     :: pw_grid
     187              :       INTEGER, INTENT(OUT), OPTIONAL                     :: id_nr, mode
     188              :       REAL(dp), INTENT(OUT), OPTIONAL                    :: vol, dvol
     189              :       INTEGER, DIMENSION(3), INTENT(OUT), OPTIONAL       :: npts
     190              :       INTEGER(int_8), INTENT(OUT), OPTIONAL              :: ngpts, ngpts_cut
     191              :       REAL(dp), DIMENSION(3), INTENT(OUT), OPTIONAL      :: dr
     192              :       REAL(dp), INTENT(OUT), OPTIONAL                    :: cutoff
     193              :       LOGICAL, INTENT(OUT), OPTIONAL                     :: orthorhombic
     194              :       REAL(dp), DIMENSION(:, :), OPTIONAL, POINTER       :: gvectors
     195              :       REAL(dp), DIMENSION(:), OPTIONAL, POINTER          :: gsquare
     196              : 
     197        78730 :       CPASSERT(pw_grid%ref_count > 0)
     198              : 
     199        78730 :       IF (PRESENT(id_nr)) id_nr = pw_grid%id_nr
     200        78730 :       IF (PRESENT(mode)) mode = pw_grid%para%mode
     201        78730 :       IF (PRESENT(vol)) vol = pw_grid%vol
     202        78730 :       IF (PRESENT(dvol)) dvol = pw_grid%dvol
     203       393362 :       IF (PRESENT(npts)) npts(1:3) = pw_grid%npts(1:3)
     204        78730 :       IF (PRESENT(ngpts)) ngpts = pw_grid%ngpts
     205        78730 :       IF (PRESENT(ngpts_cut)) ngpts_cut = pw_grid%ngpts_cut
     206        78882 :       IF (PRESENT(dr)) dr = pw_grid%dr
     207        78730 :       IF (PRESENT(cutoff)) cutoff = pw_grid%cutoff
     208        78730 :       IF (PRESENT(orthorhombic)) orthorhombic = pw_grid%orthorhombic
     209        78730 :       IF (PRESENT(gvectors)) gvectors => pw_grid%g
     210        78730 :       IF (PRESENT(gsquare)) gsquare => pw_grid%gsq
     211              : 
     212        78730 :    END SUBROUTINE get_pw_grid_info
     213              : 
     214              : ! **************************************************************************************************
     215              : !> \brief Set some information stored in the pw_grid_type
     216              : !> \param pw_grid ...
     217              : !> \param grid_span ...
     218              : !> \param npts ...
     219              : !> \param bounds ...
     220              : !> \param cutoff ...
     221              : !> \param spherical ...
     222              : !> \par History
     223              : !>      none
     224              : !> \author JGH (19-Nov-2007)
     225              : ! **************************************************************************************************
     226        87540 :    SUBROUTINE set_pw_grid_info(pw_grid, grid_span, npts, bounds, cutoff, spherical)
     227              : 
     228              :       TYPE(pw_grid_type), INTENT(INOUT)                  :: pw_grid
     229              :       INTEGER, INTENT(in), OPTIONAL                      :: grid_span
     230              :       INTEGER, DIMENSION(3), INTENT(IN), OPTIONAL        :: npts
     231              :       INTEGER, DIMENSION(2, 3), INTENT(IN), OPTIONAL     :: bounds
     232              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: cutoff
     233              :       LOGICAL, INTENT(IN), OPTIONAL                      :: spherical
     234              : 
     235        87540 :       CPASSERT(pw_grid%ref_count > 0)
     236              : 
     237        87540 :       IF (PRESENT(grid_span)) THEN
     238        42946 :          pw_grid%grid_span = grid_span
     239              :       END IF
     240        87540 :       IF (PRESENT(bounds) .AND. PRESENT(npts)) THEN
     241            0 :          pw_grid%bounds = bounds
     242            0 :          pw_grid%npts = npts
     243            0 :          CPASSERT(ALL(npts == bounds(2, :) - bounds(1, :) + 1))
     244        87540 :       ELSE IF (PRESENT(bounds)) THEN
     245        11750 :          pw_grid%bounds = bounds
     246         4700 :          pw_grid%npts = bounds(2, :) - bounds(1, :) + 1
     247        86365 :       ELSE IF (PRESENT(npts)) THEN
     248       173676 :          pw_grid%npts = npts
     249       434190 :          pw_grid%bounds = pw_grid_bounds_from_n(npts)
     250              :       END IF
     251        87540 :       IF (PRESENT(cutoff)) THEN
     252        44594 :          pw_grid%cutoff = cutoff
     253        44594 :          IF (PRESENT(spherical)) THEN
     254        44594 :             pw_grid%spherical = spherical
     255              :          ELSE
     256            0 :             pw_grid%spherical = .FALSE.
     257              :          END IF
     258              :       END IF
     259              : 
     260        87540 :    END SUBROUTINE set_pw_grid_info
     261              : 
     262              : ! **************************************************************************************************
     263              : !> \brief sets up a pw_grid
     264              : !> \param pw_grid ...
     265              : !> \param mp_comm ...
     266              : !> \param cell_hmat ...
     267              : !> \param grid_span ...
     268              : !> \param cutoff ...
     269              : !> \param bounds ...
     270              : !> \param bounds_local ...
     271              : !> \param npts ...
     272              : !> \param spherical ...
     273              : !> \param odd ...
     274              : !> \param fft_usage ...
     275              : !> \param ncommensurate ...
     276              : !> \param icommensurate ...
     277              : !> \param blocked ...
     278              : !> \param ref_grid ...
     279              : !> \param rs_dims ...
     280              : !> \param iounit ...
     281              : !> \author JGH (21-Dec-2007)
     282              : !> \note
     283              : !>      this is the function that should be used in the future
     284              : ! **************************************************************************************************
     285        44594 :    SUBROUTINE pw_grid_create_extended(pw_grid, mp_comm, cell_hmat, grid_span, cutoff, bounds, bounds_local, npts, &
     286              :                                       spherical, odd, fft_usage, ncommensurate, icommensurate, blocked, ref_grid, &
     287              :                                       rs_dims, iounit)
     288              : 
     289              :       TYPE(pw_grid_type), POINTER                        :: pw_grid
     290              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN)         :: cell_hmat
     291              : 
     292              :       CLASS(mp_comm_type), INTENT(IN) :: mp_comm
     293              :       INTEGER, INTENT(in), OPTIONAL                      :: grid_span
     294              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: cutoff
     295              :       INTEGER, DIMENSION(2, 3), INTENT(IN), OPTIONAL     :: bounds, bounds_local
     296              :       INTEGER, DIMENSION(3), INTENT(IN), OPTIONAL        :: npts
     297              :       LOGICAL, INTENT(in), OPTIONAL                      :: spherical, odd, fft_usage
     298              :       INTEGER, INTENT(in), OPTIONAL                      :: ncommensurate, icommensurate, blocked
     299              :       TYPE(pw_grid_type), INTENT(IN), OPTIONAL           :: ref_grid
     300              :       INTEGER, DIMENSION(2), INTENT(in), OPTIONAL        :: rs_dims
     301              :       INTEGER, INTENT(in), OPTIONAL                      :: iounit
     302              : 
     303              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_grid_setup'
     304              : 
     305              :       INTEGER                                            :: handle, my_icommensurate, &
     306              :                                                             my_ncommensurate
     307              :       INTEGER, DIMENSION(3)                              :: n
     308              :       LOGICAL                                            :: my_fft_usage, my_odd, my_spherical
     309              :       REAL(KIND=dp)                                      :: cell_deth, my_cutoff
     310              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: cell_h_inv
     311              : 
     312        44594 :       CALL timeset(routineN, handle)
     313              : 
     314        44594 :       CPASSERT(.NOT. ASSOCIATED(pw_grid))
     315      2318888 :       ALLOCATE (pw_grid)
     316       445940 :       pw_grid%bounds = 0
     317        44594 :       pw_grid%cutoff = 0.0_dp
     318        44594 :       pw_grid%grid_span = FULLSPACE
     319              :       pw_grid%para%mode = PW_MODE_LOCAL
     320              :       pw_grid%reference = 0
     321        44594 :       pw_grid%ref_count = 1
     322        44594 :       NULLIFY (pw_grid%g)
     323        44594 :       NULLIFY (pw_grid%gsq)
     324        44594 :       NULLIFY (pw_grid%g_hatmap)
     325        44594 :       NULLIFY (pw_grid%gidx)
     326        44594 :       NULLIFY (pw_grid%grays)
     327              : 
     328              :       ! assign a unique tag to this grid
     329        44594 :       grid_tag = grid_tag + 1
     330        44594 :       pw_grid%id_nr = grid_tag
     331              : 
     332              :       ! parallel info
     333        44594 :       IF (mp_comm%num_pe > 1) THEN
     334        39291 :          pw_grid%para%mode = PW_MODE_DISTRIBUTED
     335              :       ELSE
     336              :          pw_grid%para%mode = PW_MODE_LOCAL
     337              :       END IF
     338              : 
     339        44594 :       cell_deth = ABS(det_3x3(cell_hmat))
     340        44594 :       IF (cell_deth < 1.0E-10_dp) THEN
     341              :          CALL cp_abort(__LOCATION__, &
     342              :                        "An invalid set of cell vectors was specified. "// &
     343            0 :                        "The determinant det(h) is too small")
     344              :       END IF
     345        44594 :       cell_h_inv = inv_3x3(cell_hmat)
     346              : 
     347        44594 :       IF (PRESENT(grid_span)) THEN
     348        42946 :          CALL set_pw_grid_info(pw_grid, grid_span=grid_span)
     349              :       END IF
     350              : 
     351        44594 :       IF (PRESENT(spherical)) THEN
     352        44332 :          my_spherical = spherical
     353              :       ELSE
     354          262 :          my_spherical = .FALSE.
     355              :       END IF
     356              : 
     357        44594 :       IF (PRESENT(odd)) THEN
     358        39235 :          my_odd = odd
     359              :       ELSE
     360         5359 :          my_odd = .FALSE.
     361              :       END IF
     362              : 
     363        44594 :       IF (PRESENT(fft_usage)) THEN
     364        44428 :          my_fft_usage = fft_usage
     365              :       ELSE
     366          166 :          my_fft_usage = .FALSE.
     367              :       END IF
     368              : 
     369        44594 :       IF (PRESENT(ncommensurate)) THEN
     370        39171 :          my_ncommensurate = ncommensurate
     371        39171 :          IF (PRESENT(icommensurate)) THEN
     372        39171 :             my_icommensurate = icommensurate
     373              :          ELSE
     374            0 :             my_icommensurate = MIN(1, ncommensurate)
     375              :          END IF
     376              :       ELSE
     377         5423 :          my_ncommensurate = 0
     378         5423 :          my_icommensurate = 1
     379              :       END IF
     380              : 
     381        44594 :       IF (PRESENT(bounds)) THEN
     382         1175 :          IF (PRESENT(cutoff)) THEN
     383              :             CALL set_pw_grid_info(pw_grid, bounds=bounds, cutoff=cutoff, &
     384          180 :                                   spherical=my_spherical)
     385              :          ELSE
     386         3980 :             n = bounds(2, :) - bounds(1, :) + 1
     387          995 :             my_cutoff = pw_find_cutoff(n, cell_h_inv)
     388          995 :             my_cutoff = 0.5_dp*my_cutoff*my_cutoff
     389              :             CALL set_pw_grid_info(pw_grid, bounds=bounds, cutoff=my_cutoff, &
     390          995 :                                   spherical=my_spherical)
     391              :          END IF
     392        43419 :       ELSE IF (PRESENT(npts)) THEN
     393         2646 :          n = npts
     394         2646 :          IF (PRESENT(cutoff)) THEN
     395           24 :             my_cutoff = cutoff
     396              :          ELSE
     397         2622 :             my_cutoff = pw_find_cutoff(npts, cell_h_inv)
     398         2622 :             my_cutoff = 0.5_dp*my_cutoff*my_cutoff
     399              :          END IF
     400         2646 :          IF (my_fft_usage) THEN
     401              :             n = pw_grid_init_setup(cell_hmat, cutoff=my_cutoff, &
     402              :                                    spherical=my_spherical, odd=my_odd, fft_usage=my_fft_usage, &
     403              :                                    ncommensurate=my_ncommensurate, icommensurate=my_icommensurate, &
     404        10568 :                                    ref_grid=ref_grid, n_orig=n)
     405              :          END IF
     406              :          CALL set_pw_grid_info(pw_grid, npts=n, cutoff=my_cutoff, &
     407         2646 :                                spherical=my_spherical)
     408        40773 :       ELSE IF (PRESENT(cutoff)) THEN
     409              :          n = pw_grid_init_setup(cell_hmat, cutoff=cutoff, &
     410              :                                 spherical=my_spherical, odd=my_odd, fft_usage=my_fft_usage, &
     411              :                                 ncommensurate=my_ncommensurate, icommensurate=my_icommensurate, &
     412        40773 :                                 ref_grid=ref_grid)
     413              :          CALL set_pw_grid_info(pw_grid, npts=n, cutoff=cutoff, &
     414        40773 :                                spherical=my_spherical)
     415              :       ELSE
     416            0 :          CPABORT("BOUNDS, NPTS or CUTOFF have to be specified")
     417              :       END IF
     418              : 
     419              :       CALL pw_grid_setup_internal(cell_hmat, cell_h_inv, cell_deth, pw_grid, mp_comm, bounds_local=bounds_local, &
     420        44594 :                                   blocked=blocked, ref_grid=ref_grid, rs_dims=rs_dims, iounit=iounit)
     421              : 
     422        44594 :       CALL pw_grid_create_ghatmap(pw_grid)
     423              : 
     424        44594 :       CALL timestop(handle)
     425              : 
     426        44594 :    END SUBROUTINE pw_grid_create_extended
     427              : 
     428              : ! **************************************************************************************************
     429              : !> \brief sets up a combined index for gather and scatter
     430              : !> \param pw_grid ...
     431              : !> \author Gloess Andreas (xx-Dec-2012)
     432              : ! **************************************************************************************************
     433        44594 :    SUBROUTINE pw_grid_create_ghatmap(pw_grid)
     434              : 
     435              :       TYPE(pw_grid_type), INTENT(INOUT)                  :: pw_grid
     436              : 
     437              :       CHARACTER(len=*), PARAMETER :: routineN = 'pw_grid_create_ghatmap'
     438              : 
     439              :       INTEGER                                            :: gpt, handle, l, m, mn, n
     440              : 
     441        44594 :       CALL timeset(routineN, handle)
     442              : 
     443              :       ! some checks
     444        44594 :       CPASSERT(pw_grid%ref_count > 0)
     445              : 
     446              :       ! mapping of map_x( g_hat(i,j)) to g_hatmap
     447              :       ! the second index is for switching from gather(1) to scatter(2)
     448              :       ASSOCIATE (g_hat => pw_grid%g_hat, g_hatmap => pw_grid%g_hatmap, pmapl => pw_grid%mapl%pos, &
     449              :                  pmapm => pw_grid%mapm%pos, pmapn => pw_grid%mapn%pos, nmapl => pw_grid%mapl%neg, &
     450              :                  nmapm => pw_grid%mapm%neg, nmapn => pw_grid%mapn%neg, ngpts => SIZE(pw_grid%gsq), &
     451              :                  npts => pw_grid%npts, yzq => pw_grid%para%yzq)
     452              :          ! initialize map array to minus one, to guarantee memory
     453              :          ! range checking errors (just to be sure)
     454   1162961034 :          g_hatmap(:, :) = -1
     455        89188 :          IF (pw_grid%para%mode /= PW_MODE_DISTRIBUTED) THEN
     456        21212 :             CPASSERT(PRODUCT(INT(npts, KIND=int_8)) <= INT(HUGE(0), KIND=int_8))
     457     48663414 :             DO gpt = 1, ngpts
     458     48658111 :                l = pmapl(g_hat(1, gpt))
     459     48658111 :                m = pmapm(g_hat(2, gpt))
     460     48658111 :                n = pmapn(g_hat(3, gpt))
     461              :                !ATTENTION: C-mapping [start-index=0] !!!!
     462              :                !ATTENTION: potential integer overflow !!!!
     463     48663414 :                g_hatmap(gpt, 1) = l + npts(1)*(m + npts(2)*n)
     464              :             END DO
     465         5303 :             IF (pw_grid%grid_span == HALFSPACE) THEN
     466     12630608 :                DO gpt = 1, ngpts
     467     12629401 :                   l = nmapl(g_hat(1, gpt))
     468     12629401 :                   m = nmapm(g_hat(2, gpt))
     469     12629401 :                   n = nmapn(g_hat(3, gpt))
     470              :                   !ATTENTION: C-mapping [start-index=0] !!!!
     471              :                   !ATTENTION: potential integer overflow !!!!
     472     12630608 :                   g_hatmap(gpt, 2) = l + npts(1)*(m + npts(2)*n)
     473              :                END DO
     474              :             END IF
     475              :          ELSE
     476   1082905344 :             DO gpt = 1, ngpts
     477   1082866053 :                l = pmapl(g_hat(1, gpt))
     478   1082866053 :                m = pmapm(g_hat(2, gpt)) + 1
     479   1082866053 :                n = pmapn(g_hat(3, gpt)) + 1
     480              :                !ATTENTION: C-mapping [start-index=0] !!!!
     481              :                !ATTENTION: potential integer overflow !!!!
     482   1082866053 :                mn = yzq(m, n) - 1
     483   1082905344 :                g_hatmap(gpt, 1) = l + npts(1)*mn
     484              :             END DO
     485        39291 :             IF (pw_grid%grid_span == HALFSPACE) THEN
     486     18717074 :                DO gpt = 1, ngpts
     487     18714538 :                   l = nmapl(g_hat(1, gpt))
     488     18714538 :                   m = nmapm(g_hat(2, gpt)) + 1
     489     18714538 :                   n = nmapn(g_hat(3, gpt)) + 1
     490              :                   !ATTENTION: C-mapping [start-index=0] !!!!
     491              :                   !ATTENTION: potential integer overflow !!!!
     492     18714538 :                   mn = yzq(m, n) - 1
     493     18717074 :                   g_hatmap(gpt, 2) = l + npts(1)*mn
     494              :                END DO
     495              :             END IF
     496              :          END IF
     497              :       END ASSOCIATE
     498              : 
     499        44594 :       CALL timestop(handle)
     500              : 
     501        44594 :    END SUBROUTINE pw_grid_create_ghatmap
     502              : 
     503              : ! **************************************************************************************************
     504              : !> \brief sets up a pw_grid, needs valid bounds as input, it is up to you to
     505              : !>      make sure of it using pw_grid_bounds_from_n
     506              : !> \param cell_hmat ...
     507              : !> \param cell_h_inv ...
     508              : !> \param cell_deth ...
     509              : !> \param pw_grid ...
     510              : !> \param mp_comm ...
     511              : !> \param bounds_local ...
     512              : !> \param blocked ...
     513              : !> \param ref_grid ...
     514              : !> \param rs_dims ...
     515              : !> \param iounit ...
     516              : !> \par History
     517              : !>      JGH (20-Dec-2000) : Adapted for parallel use
     518              : !>      JGH (28-Feb-2001) : New optional argument fft_usage
     519              : !>      JGH (21-Mar-2001) : Reference grid code
     520              : !>      JGH (21-Mar-2001) : New optional argument symm_usage
     521              : !>      JGH (22-Mar-2001) : Simplify group assignment (mp_comm_dup)
     522              : !>      JGH (21-May-2002) : Remove orthorhombic keyword (code is fast enough)
     523              : !>      JGH (19-Feb-2003) : Negative cutoff can be used for non-spheric grids
     524              : !>      Joost VandeVondele (Feb-2004) : optionally generate pw grids that are commensurate in rs
     525              : !>      JGH (18-Dec-2007) : Refactoring
     526              : !> \author fawzi
     527              : !> \note
     528              : !>      this is the function that should be used in the future
     529              : ! **************************************************************************************************
     530        44594 :    SUBROUTINE pw_grid_setup_internal(cell_hmat, cell_h_inv, cell_deth, pw_grid, mp_comm, bounds_local, &
     531              :                                      blocked, ref_grid, rs_dims, iounit)
     532              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN)         :: cell_hmat, cell_h_inv
     533              :       REAL(KIND=dp), INTENT(IN)                          :: cell_deth
     534              :       TYPE(pw_grid_type), INTENT(INOUT)                  :: pw_grid
     535              : 
     536              :       CLASS(mp_comm_type), INTENT(IN) :: mp_comm
     537              :       INTEGER, DIMENSION(2, 3), INTENT(IN), OPTIONAL     :: bounds_local
     538              :       INTEGER, INTENT(in), OPTIONAL                      :: blocked
     539              :       TYPE(pw_grid_type), INTENT(in), OPTIONAL           :: ref_grid
     540              :       INTEGER, DIMENSION(2), INTENT(in), OPTIONAL        :: rs_dims
     541              :       INTEGER, INTENT(in), OPTIONAL                      :: iounit
     542              : 
     543              :       CHARACTER(len=*), PARAMETER :: routineN = 'pw_grid_setup_internal'
     544              : 
     545              :       INTEGER                                            :: handle, n(3)
     546        44594 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: yz_mask
     547              :       REAL(KIND=dp)                                      :: ecut
     548              : 
     549              : !------------------------------------------------------------------------------
     550              : 
     551        44594 :       CALL timeset(routineN, handle)
     552              : 
     553        44594 :       CPASSERT(pw_grid%ref_count > 0)
     554              : 
     555              :       ! set pointer to possible reference grid
     556        44594 :       IF (PRESENT(ref_grid)) THEN
     557        27156 :          pw_grid%reference = ref_grid%id_nr
     558              :       END IF
     559              : 
     560        44594 :       IF (pw_grid%spherical) THEN
     561         3491 :          ecut = pw_grid%cutoff
     562              :       ELSE
     563        41103 :          ecut = 1.e10_dp
     564              :       END IF
     565              : 
     566       178376 :       n(:) = pw_grid%npts(:)
     567              : 
     568              :       ! Find the number of grid points
     569              :       ! yz_mask counts the number of g-vectors orthogonal to the yz plane
     570              :       ! the indices in yz_mask are from -n/2 .. n/2 shifted by n/2 + 1
     571              :       ! these are not mapped indices !
     572       178376 :       ALLOCATE (yz_mask(n(2), n(3)))
     573        44594 :       CALL pw_grid_count(cell_h_inv, pw_grid, mp_comm, ecut, yz_mask)
     574              : 
     575              :       ! Check if reference grid is compatible
     576        44594 :       IF (PRESENT(ref_grid)) THEN
     577        27156 :          CPASSERT(pw_grid%para%mode == ref_grid%para%mode)
     578        27156 :          CPASSERT(pw_grid%grid_span == ref_grid%grid_span)
     579        27156 :          CPASSERT(pw_grid%spherical .EQV. ref_grid%spherical)
     580              :       END IF
     581              : 
     582              :       ! Distribute grid
     583              :       CALL pw_grid_distribute(pw_grid, mp_comm, yz_mask, bounds_local=bounds_local, ref_grid=ref_grid, blocked=blocked, &
     584        44594 :                               rs_dims=rs_dims)
     585              : 
     586              :       ! Allocate the grid fields
     587              :       CALL pw_grid_allocate(pw_grid, pw_grid%ngpts_cut_local, &
     588        44594 :                             pw_grid%bounds)
     589              : 
     590              :       ! Fill in the grid structure
     591        44594 :       CALL pw_grid_assign(cell_h_inv, pw_grid, ecut)
     592              : 
     593              :       ! Sort g vector wrt length (only local for each processor)
     594        44594 :       CALL pw_grid_sort(pw_grid, ref_grid)
     595              : 
     596        44594 :       CALL pw_grid_remap(pw_grid, yz_mask)
     597              : 
     598        44594 :       DEALLOCATE (yz_mask)
     599              : 
     600        44594 :       CALL cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
     601              :       !
     602              :       ! Output: All the information of this grid type
     603              :       !
     604              : 
     605        44594 :       IF (PRESENT(iounit)) THEN
     606        44568 :          CALL pw_grid_print(pw_grid, iounit)
     607              :       END IF
     608              : 
     609        44594 :       CALL timestop(handle)
     610              : 
     611        44594 :    END SUBROUTINE pw_grid_setup_internal
     612              : 
     613              : ! **************************************************************************************************
     614              : !> \brief Helper routine used by pw_grid_setup_internal and pw_grid_change
     615              : !> \param cell_hmat ...
     616              : !> \param cell_h_inv ...
     617              : !> \param cell_deth ...
     618              : !> \param pw_grid ...
     619              : !> \par History moved common code into new subroutine
     620              : !> \author Ole Schuett
     621              : ! **************************************************************************************************
     622        58474 :    SUBROUTINE cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
     623              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN)         :: cell_hmat, cell_h_inv
     624              :       REAL(KIND=dp), INTENT(IN)                          :: cell_deth
     625              :       TYPE(pw_grid_type), INTENT(INOUT)                  :: pw_grid
     626              : 
     627        58474 :       pw_grid%vol = ABS(cell_deth)
     628        58474 :       pw_grid%dvol = pw_grid%vol/REAL(pw_grid%ngpts, KIND=dp)
     629              :       pw_grid%dr(1) = SQRT(SUM(cell_hmat(:, 1)**2)) &
     630       233896 :                       /REAL(pw_grid%npts(1), KIND=dp)
     631              :       pw_grid%dr(2) = SQRT(SUM(cell_hmat(:, 2)**2)) &
     632       233896 :                       /REAL(pw_grid%npts(2), KIND=dp)
     633              :       pw_grid%dr(3) = SQRT(SUM(cell_hmat(:, 3)**2)) &
     634       233896 :                       /REAL(pw_grid%npts(3), KIND=dp)
     635       233896 :       pw_grid%dh(:, 1) = cell_hmat(:, 1)/REAL(pw_grid%npts(1), KIND=dp)
     636       233896 :       pw_grid%dh(:, 2) = cell_hmat(:, 2)/REAL(pw_grid%npts(2), KIND=dp)
     637       233896 :       pw_grid%dh(:, 3) = cell_hmat(:, 3)/REAL(pw_grid%npts(3), KIND=dp)
     638       233896 :       pw_grid%dh_inv(1, :) = cell_h_inv(1, :)*REAL(pw_grid%npts(1), KIND=dp)
     639       233896 :       pw_grid%dh_inv(2, :) = cell_h_inv(2, :)*REAL(pw_grid%npts(2), KIND=dp)
     640       233896 :       pw_grid%dh_inv(3, :) = cell_h_inv(3, :)*REAL(pw_grid%npts(3), KIND=dp)
     641              : 
     642              :       IF ((cell_hmat(1, 2) == 0.0_dp) .AND. (cell_hmat(1, 3) == 0.0_dp) .AND. &
     643              :           (cell_hmat(2, 1) == 0.0_dp) .AND. (cell_hmat(2, 3) == 0.0_dp) .AND. &
     644        58474 :           (cell_hmat(3, 1) == 0.0_dp) .AND. (cell_hmat(3, 2) == 0.0_dp)) THEN
     645        45904 :          pw_grid%orthorhombic = .TRUE.
     646              :       ELSE
     647        12570 :          pw_grid%orthorhombic = .FALSE.
     648              :       END IF
     649        58474 :    END SUBROUTINE cell2grid
     650              : 
     651              : ! **************************************************************************************************
     652              : !> \brief Output of information on pw_grid
     653              : !> \param pw_grid ...
     654              : !> \param info ...
     655              : !> \author JGH[18-05-2007] from earlier versions
     656              : ! **************************************************************************************************
     657        44568 :    SUBROUTINE pw_grid_print(pw_grid, info)
     658              : 
     659              :       TYPE(pw_grid_type), INTENT(IN)                     :: pw_grid
     660              :       INTEGER, INTENT(IN)                                :: info
     661              : 
     662              :       INTEGER                                            :: i
     663              :       INTEGER(KIND=int_8)                                :: n(3)
     664              :       REAL(KIND=dp)                                      :: rv(3, 3)
     665              : 
     666              : !------------------------------------------------------------------------------
     667              : !
     668              : ! Output: All the information of this grid type
     669              : !
     670              : 
     671        44568 :       IF (pw_grid%para%mode == PW_MODE_LOCAL) THEN
     672         5303 :          IF (info > 0) THEN
     673              :             WRITE (info, '(/,A,T71,I10)') &
     674          447 :                " PW_GRID| Information for grid number ", pw_grid%id_nr
     675          447 :             IF (pw_grid%reference > 0) THEN
     676              :                WRITE (info, '(A,T71,I10)') &
     677          114 :                   " PW_GRID| Number of the reference grid ", pw_grid%reference
     678              :             END IF
     679          447 :             WRITE (info, '(" PW_GRID| Cutoff [a.u.]",T71,f10.1)') pw_grid%cutoff
     680          447 :             IF (pw_grid%spherical) THEN
     681          201 :                WRITE (info, '(A,T78,A)') " PW_GRID| spherical cutoff: ", "YES"
     682          201 :                WRITE (info, '(A,T71,I10)') " PW_GRID| Grid points within cutoff", &
     683          402 :                   pw_grid%ngpts_cut
     684              :             ELSE
     685          246 :                WRITE (info, '(A,T78,A)') " PW_GRID| spherical cutoff: ", " NO"
     686              :             END IF
     687         1788 :             DO i = 1, 3
     688         1341 :                WRITE (info, '(A,I3,T30,2I8,T62,A,T71,I10)') " PW_GRID|   Bounds ", &
     689         1341 :                   i, pw_grid%bounds(1, I), pw_grid%bounds(2, I), &
     690         3129 :                   "Points:", pw_grid%npts(I)
     691              :             END DO
     692              :             WRITE (info, '(A,G12.4,T50,A,T67,F14.4)') &
     693          447 :                " PW_GRID| Volume element (a.u.^3)", &
     694          894 :                pw_grid%dvol, " Volume (a.u.^3) :", pw_grid%vol
     695          447 :             IF (pw_grid%grid_span == HALFSPACE) THEN
     696          299 :                WRITE (info, '(A,T72,A)') " PW_GRID| Grid span", "HALFSPACE"
     697              :             ELSE
     698          148 :                WRITE (info, '(A,T72,A)') " PW_GRID| Grid span", "FULLSPACE"
     699              :             END IF
     700              :          END IF
     701              :       ELSE
     702              : 
     703        39265 :          n(1) = pw_grid%ngpts_cut_local
     704        39265 :          n(2) = pw_grid%ngpts_local
     705        39265 :          CALL pw_grid%para%group%sum(n(1:2))
     706       117795 :          n(3) = SUM(pw_grid%para%nyzray)
     707       157060 :          rv(:, 1) = REAL(n, KIND=dp)/REAL(pw_grid%para%group%num_pe, KIND=dp)
     708        39265 :          n(1) = pw_grid%ngpts_cut_local
     709        39265 :          n(2) = pw_grid%ngpts_local
     710        39265 :          CALL pw_grid%para%group%max(n(1:2))
     711       117795 :          n(3) = MAXVAL(pw_grid%para%nyzray)
     712       157060 :          rv(:, 2) = REAL(n, KIND=dp)
     713        39265 :          n(1) = pw_grid%ngpts_cut_local
     714        39265 :          n(2) = pw_grid%ngpts_local
     715        39265 :          CALL pw_grid%para%group%min(n(1:2))
     716       117795 :          n(3) = MINVAL(pw_grid%para%nyzray)
     717       157060 :          rv(:, 3) = REAL(n, KIND=dp)
     718              : 
     719        39265 :          IF (info > 0) THEN
     720              :             WRITE (info, '(/,A,T71,I10)') &
     721         8015 :                " PW_GRID| Information for grid number ", pw_grid%id_nr
     722         8015 :             IF (pw_grid%reference > 0) THEN
     723              :                WRITE (info, '(A,T71,I10)') &
     724         4799 :                   " PW_GRID| Number of the reference grid ", pw_grid%reference
     725              :             END IF
     726              :             WRITE (info, '(A,T60,I10,A)') &
     727         8015 :                " PW_GRID| Grid distributed over ", pw_grid%para%group%num_pe, &
     728        16030 :                " processors"
     729              :             WRITE (info, '(A,T71,2I5)') &
     730         8015 :                " PW_GRID| Real space group dimensions ", pw_grid%para%group%num_pe_cart
     731         8015 :             IF (pw_grid%para%blocked) THEN
     732            6 :                WRITE (info, '(A,T78,A)') " PW_GRID| the grid is blocked: ", "YES"
     733              :             ELSE
     734         8009 :                WRITE (info, '(A,T78,A)') " PW_GRID| the grid is blocked: ", " NO"
     735              :             END IF
     736         8015 :             WRITE (info, '(" PW_GRID| Cutoff [a.u.]",T71,f10.1)') pw_grid%cutoff
     737         8015 :             IF (pw_grid%spherical) THEN
     738          408 :                WRITE (info, '(A,T78,A)') " PW_GRID| spherical cutoff: ", "YES"
     739          408 :                WRITE (info, '(A,T71,I10)') " PW_GRID| Grid points within cutoff", &
     740          816 :                   pw_grid%ngpts_cut
     741              :             ELSE
     742         7607 :                WRITE (info, '(A,T78,A)') " PW_GRID| spherical cutoff: ", " NO"
     743              :             END IF
     744        32060 :             DO i = 1, 3
     745        24045 :                WRITE (info, '(A,I3,T30,2I8,T62,A,T71,I10)') " PW_GRID|   Bounds ", &
     746        24045 :                   i, pw_grid%bounds(1, I), pw_grid%bounds(2, I), &
     747        56105 :                   "Points:", pw_grid%npts(I)
     748              :             END DO
     749              :             WRITE (info, '(A,G12.4,T50,A,T67,F14.4)') &
     750         8015 :                " PW_GRID| Volume element (a.u.^3)", &
     751        16030 :                pw_grid%dvol, " Volume (a.u.^3) :", pw_grid%vol
     752         8015 :             IF (pw_grid%grid_span == HALFSPACE) THEN
     753          416 :                WRITE (info, '(A,T72,A)') " PW_GRID| Grid span", "HALFSPACE"
     754              :             ELSE
     755         7599 :                WRITE (info, '(A,T72,A)') " PW_GRID| Grid span", "FULLSPACE"
     756              :             END IF
     757         8015 :             WRITE (info, '(A,T48,A)') " PW_GRID|   Distribution", &
     758        16030 :                "  Average         Max         Min"
     759         8015 :             WRITE (info, '(A,T45,F12.1,2I12)') " PW_GRID|   G-Vectors", &
     760        16030 :                rv(1, 1), NINT(rv(1, 2)), NINT(rv(1, 3))
     761         8015 :             WRITE (info, '(A,T45,F12.1,2I12)') " PW_GRID|   G-Rays   ", &
     762        16030 :                rv(3, 1), NINT(rv(3, 2)), NINT(rv(3, 3))
     763         8015 :             WRITE (info, '(A,T45,F12.1,2I12)') " PW_GRID|   Real Space Points", &
     764        16030 :                rv(2, 1), NINT(rv(2, 2)), NINT(rv(2, 3))
     765              :          END IF ! group head
     766              :       END IF ! local
     767              : 
     768        44568 :    END SUBROUTINE pw_grid_print
     769              : 
     770              : ! **************************************************************************************************
     771              : !> \brief Distribute grids in real and Fourier Space to the processors in group
     772              : !> \param pw_grid ...
     773              : !> \param mp_comm ...
     774              : !> \param yz_mask ...
     775              : !> \param bounds_local ...
     776              : !> \param ref_grid ...
     777              : !> \param blocked ...
     778              : !> \param rs_dims ...
     779              : !> \par History
     780              : !>      JGH (01-Mar-2001) optional reference grid
     781              : !>      JGH (22-May-2002) bug fix for pre_tag and HALFSPACE grids
     782              : !>      JGH (09-Sep-2003) reduce scaling for distribution
     783              : !> \author JGH (22-12-2000)
     784              : ! **************************************************************************************************
     785        44594 :    SUBROUTINE pw_grid_distribute(pw_grid, mp_comm, yz_mask, bounds_local, ref_grid, blocked, rs_dims)
     786              : 
     787              :       TYPE(pw_grid_type), INTENT(INOUT)                  :: pw_grid
     788              : 
     789              :       CLASS(mp_comm_type), INTENT(IN) :: mp_comm
     790              :       INTEGER, DIMENSION(:, :), INTENT(INOUT)            :: yz_mask
     791              :       INTEGER, DIMENSION(2, 3), INTENT(IN), OPTIONAL     :: bounds_local
     792              :       TYPE(pw_grid_type), INTENT(IN), OPTIONAL           :: ref_grid
     793              :       INTEGER, INTENT(IN), OPTIONAL                      :: blocked
     794              :       INTEGER, DIMENSION(2), INTENT(in), OPTIONAL        :: rs_dims
     795              : 
     796              :       CHARACTER(len=*), PARAMETER :: routineN = 'pw_grid_distribute'
     797              : 
     798              :       INTEGER                                            :: blocked_local, coor(2), gmax, handle, i, &
     799              :                                                             i1, i2, ip, ipl, ipp, itmp, j, l, lby, &
     800              :                                                             lbz, lo(2), m, n, np, ns, nx, ny, nz, &
     801              :                                                             rsd(2)
     802        44594 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: pemap
     803        44594 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: yz_index
     804        44594 :       INTEGER, ALLOCATABLE, DIMENSION(:, :, :)           :: axis_dist_all
     805              :       INTEGER, DIMENSION(2)                              :: my_rs_dims
     806              :       INTEGER, DIMENSION(2, 3)                           :: axis_dist
     807              :       LOGICAL                                            :: blocking
     808              : 
     809              : !------------------------------------------------------------------------------
     810              : 
     811        44594 :       CALL timeset(routineN, handle)
     812              : 
     813        44594 :       lby = pw_grid%bounds(1, 2)
     814        44594 :       lbz = pw_grid%bounds(1, 3)
     815              : 
     816       178376 :       pw_grid%ngpts = PRODUCT(INT(pw_grid%npts, KIND=int_8))
     817              : 
     818        44594 :       my_rs_dims = 0
     819        44594 :       IF (PRESENT(rs_dims)) THEN
     820        43525 :          my_rs_dims = rs_dims
     821              :       END IF
     822              : 
     823        44594 :       IF (PRESENT(blocked)) THEN
     824        40879 :          blocked_local = blocked
     825              :       ELSE
     826              :          blocked_local = do_pw_grid_blocked_free
     827              :       END IF
     828              : 
     829        44594 :       pw_grid%para%blocked = .FALSE.
     830              : 
     831        44594 :       IF (pw_grid%para%mode == PW_MODE_LOCAL) THEN
     832              : 
     833         5303 :          pw_grid%para%ray_distribution = .FALSE.
     834              : 
     835        53030 :          pw_grid%bounds_local = pw_grid%bounds
     836        21212 :          pw_grid%npts_local = pw_grid%npts
     837         5303 :          CPASSERT(pw_grid%ngpts_cut < HUGE(pw_grid%ngpts_cut_local))
     838         5303 :          pw_grid%ngpts_cut_local = INT(pw_grid%ngpts_cut)
     839         5303 :          CPASSERT(pw_grid%ngpts < HUGE(pw_grid%ngpts_local))
     840         5303 :          pw_grid%ngpts_local = INT(pw_grid%ngpts)
     841        15909 :          my_rs_dims = 1
     842         5303 :          CALL pw_grid%para%group%create(mp_comm, 2, my_rs_dims)
     843              : 
     844         5303 :          ALLOCATE (pw_grid%para%bo(2, 3, 0:0, 3))
     845        21212 :          DO i = 1, 3
     846        63636 :             pw_grid%para%bo(1, 1:3, 0, i) = 1
     847        68939 :             pw_grid%para%bo(2, 1:3, 0, i) = pw_grid%npts(1:3)
     848              :          END DO
     849              : 
     850              :       ELSE
     851              : 
     852              :          !..find the real space distribution
     853        39291 :          nx = pw_grid%npts(1)
     854        39291 :          ny = pw_grid%npts(2)
     855        39291 :          nz = pw_grid%npts(3)
     856        39291 :          np = mp_comm%num_pe
     857              : 
     858              :          ! The user can specify 2 strictly positive indices => specific layout
     859              :          !                      1 strictly positive index   => the other is fixed by the number of CPUs
     860              :          !                      0 strictly positive indices => fully free distribution
     861              :          ! if fully free or the user request can not be fulfilled, we optimize heuristically ourselves by:
     862              :          !                      1) nx>np -> taking a plane distribution (/np,1/)
     863              :          !                      2) nx<np -> taking the most square distribution
     864              :          ! if blocking is free:
     865              :          !                      1) blocked=.FALSE. for plane distributions
     866              :          !                      2) blocked=.TRUE.  for non-plane distributions
     867        53131 :          IF (ANY(my_rs_dims <= 0)) THEN
     868        97089 :             IF (ALL(my_rs_dims <= 0)) THEN
     869        32347 :                my_rs_dims = [0, 0]
     870              :             ELSE
     871           24 :                IF (my_rs_dims(1) > 0) THEN
     872            0 :                   my_rs_dims(2) = np/my_rs_dims(1)
     873              :                ELSE
     874           24 :                   my_rs_dims(1) = np/my_rs_dims(2)
     875              :                END IF
     876              :             END IF
     877              :          END IF
     878              :          ! reset if the distribution can not be fulfilled
     879       117873 :          IF (PRODUCT(my_rs_dims) /= np) my_rs_dims = [0, 0]
     880              :          ! reset if the distribution can not be dealt with [1,np]
     881        39339 :          IF (ALL(my_rs_dims == [1, np])) my_rs_dims = [0, 0]
     882              : 
     883              :          ! if [0,0] now, we can optimize it ourselves
     884       104041 :          IF (ALL(my_rs_dims == [0, 0])) THEN
     885              :             ! only small grids have a chance to be 2d distributed
     886        32375 :             IF (nx < np) THEN
     887              :                ! gives the most square looking distribution
     888            0 :                CALL mp_dims_create(np, my_rs_dims)
     889              :                ! we tend to like the first index being smaller than the second
     890            0 :                IF (my_rs_dims(1) > my_rs_dims(2)) THEN
     891            0 :                   itmp = my_rs_dims(1)
     892            0 :                   my_rs_dims(1) = my_rs_dims(2)
     893            0 :                   my_rs_dims(2) = itmp
     894              :                END IF
     895              :                ! but should avoid having the first index 1 in all cases
     896            0 :                IF (my_rs_dims(1) == 1) THEN
     897            0 :                   itmp = my_rs_dims(1)
     898            0 :                   my_rs_dims(1) = my_rs_dims(2)
     899            0 :                   my_rs_dims(2) = itmp
     900              :                END IF
     901              :             ELSE
     902        97125 :                my_rs_dims = [np, 1]
     903              :             END IF
     904              :          END IF
     905              : 
     906              :          ! now fix the blocking if we have a choice
     907              :          SELECT CASE (blocked_local)
     908              :          CASE (do_pw_grid_blocked_false)
     909           28 :             blocking = .FALSE.
     910              :          CASE (do_pw_grid_blocked_true)
     911           28 :             blocking = .TRUE.
     912              :          CASE (do_pw_grid_blocked_free)
     913        40137 :             IF (ALL(my_rs_dims == [np, 1])) THEN
     914              :                blocking = .FALSE.
     915              :             ELSE
     916            0 :                blocking = .TRUE.
     917              :             END IF
     918              :          CASE DEFAULT
     919        39291 :             CPABORT("Unknown PW grid blocking")
     920              :          END SELECT
     921              : 
     922              :          !..create group for real space distribution
     923        39291 :          CALL pw_grid%para%group%create(mp_comm, 2, my_rs_dims)
     924              : 
     925        39291 :          IF (PRESENT(bounds_local)) THEN
     926          220 :             pw_grid%bounds_local = bounds_local
     927              :          ELSE
     928              :             lo = get_limit(nx, pw_grid%para%group%num_pe_cart(1), &
     929        39269 :                            pw_grid%para%group%mepos_cart(1))
     930       117807 :             pw_grid%bounds_local(:, 1) = lo + pw_grid%bounds(1, 1) - 1
     931              :             lo = get_limit(ny, pw_grid%para%group%num_pe_cart(2), &
     932        39269 :                            pw_grid%para%group%mepos_cart(2))
     933       117807 :             pw_grid%bounds_local(:, 2) = lo + pw_grid%bounds(1, 2) - 1
     934       117807 :             pw_grid%bounds_local(:, 3) = pw_grid%bounds(:, 3)
     935              :          END IF
     936              : 
     937              :          pw_grid%npts_local(:) = pw_grid%bounds_local(2, :) &
     938       157164 :                                  - pw_grid%bounds_local(1, :) + 1
     939              : 
     940              :          !..the third distribution is needed for the second step in the FFT
     941       157164 :          ALLOCATE (pw_grid%para%bo(2, 3, 0:np - 1, 3))
     942       117873 :          rsd = pw_grid%para%group%num_pe_cart
     943              : 
     944        39291 :          IF (PRESENT(bounds_local)) THEN
     945              :             ! axis_dist tells what portion of 1 .. nx , 1 .. ny , 1 .. nz are in the current process
     946           88 :             DO i = 1, 3
     947          220 :                axis_dist(:, i) = bounds_local(:, i) - pw_grid%bounds(1, i) + 1
     948              :             END DO
     949           66 :             ALLOCATE (axis_dist_all(2, 3, np))
     950           22 :             CALL pw_grid%para%group%allgather(axis_dist, axis_dist_all)
     951           66 :             DO ip = 0, np - 1
     952           44 :                CALL pw_grid%para%group%coords(ip, coor)
     953              :                ! distribution xyZ
     954          132 :                pw_grid%para%bo(1:2, 1, ip, 1) = axis_dist_all(1:2, 1, ip + 1)
     955          132 :                pw_grid%para%bo(1:2, 2, ip, 1) = axis_dist_all(1:2, 2, ip + 1)
     956           44 :                pw_grid%para%bo(1, 3, ip, 1) = 1
     957           44 :                pw_grid%para%bo(2, 3, ip, 1) = nz
     958              :                ! distribution xYz
     959          132 :                pw_grid%para%bo(1:2, 1, ip, 2) = axis_dist_all(1:2, 1, ip + 1)
     960           44 :                pw_grid%para%bo(1, 2, ip, 2) = 1
     961           44 :                pw_grid%para%bo(2, 2, ip, 2) = ny
     962          132 :                pw_grid%para%bo(1:2, 3, ip, 2) = get_limit(nz, rsd(2), coor(2))
     963              :                ! distribution Xyz
     964           44 :                pw_grid%para%bo(1, 1, ip, 3) = 1
     965           44 :                pw_grid%para%bo(2, 1, ip, 3) = nx
     966          132 :                pw_grid%para%bo(1:2, 2, ip, 3) = get_limit(ny, rsd(1), coor(1))
     967          154 :                pw_grid%para%bo(1:2, 3, ip, 3) = get_limit(nz, rsd(2), coor(2))
     968              :             END DO
     969           22 :             DEALLOCATE (axis_dist_all)
     970              :          ELSE
     971       117807 :             DO ip = 0, np - 1
     972        78538 :                CALL pw_grid%para%group%coords(ip, coor)
     973              :                ! distribution xyZ
     974       235614 :                pw_grid%para%bo(1:2, 1, ip, 1) = get_limit(nx, rsd(1), coor(1))
     975       235614 :                pw_grid%para%bo(1:2, 2, ip, 1) = get_limit(ny, rsd(2), coor(2))
     976        78538 :                pw_grid%para%bo(1, 3, ip, 1) = 1
     977        78538 :                pw_grid%para%bo(2, 3, ip, 1) = nz
     978              :                ! distribution xYz
     979       235614 :                pw_grid%para%bo(1:2, 1, ip, 2) = get_limit(nx, rsd(1), coor(1))
     980        78538 :                pw_grid%para%bo(1, 2, ip, 2) = 1
     981        78538 :                pw_grid%para%bo(2, 2, ip, 2) = ny
     982       235614 :                pw_grid%para%bo(1:2, 3, ip, 2) = get_limit(nz, rsd(2), coor(2))
     983              :                ! distribution Xyz
     984        78538 :                pw_grid%para%bo(1, 1, ip, 3) = 1
     985        78538 :                pw_grid%para%bo(2, 1, ip, 3) = nx
     986       235614 :                pw_grid%para%bo(1:2, 2, ip, 3) = get_limit(ny, rsd(1), coor(1))
     987       274883 :                pw_grid%para%bo(1:2, 3, ip, 3) = get_limit(nz, rsd(2), coor(2))
     988              :             END DO
     989              :          END IF
     990              :          !..find the g space distribution
     991        39291 :          pw_grid%ngpts_cut_local = 0
     992              : 
     993       117873 :          ALLOCATE (pw_grid%para%nyzray(0:np - 1))
     994              : 
     995       157164 :          ALLOCATE (pw_grid%para%yzq(ny, nz))
     996              : 
     997              :          IF (pw_grid%spherical .OR. pw_grid%grid_span == HALFSPACE &
     998        39291 :              .OR. .NOT. blocking) THEN
     999              : 
    1000        39279 :             pw_grid%para%ray_distribution = .TRUE.
    1001              : 
    1002              :             ! the mirror tags below only handle lower-skewed or symmetric
    1003              :             ! frequency windows (the only ones the grid setup produces today)
    1004        39279 :             IF (pw_grid%grid_span == HALFSPACE) THEN
    1005         2536 :                CPASSERT(pw_grid%bounds(2, 2) <= -pw_grid%bounds(1, 2))
    1006         2536 :                CPASSERT(pw_grid%bounds(2, 3) <= -pw_grid%bounds(1, 3))
    1007              :             END IF
    1008              : 
    1009     42025753 :             pw_grid%para%yzq = -1
    1010        39279 :             IF (PRESENT(ref_grid)) THEN
    1011              :                ! tag all vectors from the reference grid
    1012        24084 :                CALL pre_tag(pw_grid, yz_mask, ref_grid)
    1013              :             END IF
    1014              : 
    1015              :             ! Round Robin distribution
    1016              :             ! Processors 0 .. NP-1, NP-1 .. 0  get the largest remaining batch
    1017              :             ! of g vectors in turn
    1018              : 
    1019        39279 :             i1 = SIZE(yz_mask, 1)
    1020        39279 :             i2 = SIZE(yz_mask, 2)
    1021       117837 :             ALLOCATE (yz_index(2, i1*i2))
    1022        39279 :             CALL order_mask(yz_mask, yz_index)
    1023     41005840 :             DO i = 1, i1*i2
    1024     40966561 :                lo(1) = yz_index(1, i)
    1025     40966561 :                lo(2) = yz_index(2, i)
    1026     40966561 :                IF (lo(1)*lo(2) == 0) CYCLE
    1027     25534984 :                gmax = yz_mask(lo(1), lo(2))
    1028     25534984 :                IF (gmax == 0) CYCLE
    1029     25534984 :                yz_mask(lo(1), lo(2)) = 0
    1030     25534984 :                ip = MOD(i - 1, 2*np)
    1031     25534984 :                IF (ip > np - 1) ip = 2*np - ip - 1
    1032     25534984 :                IF (ip == pw_grid%para%group%mepos) THEN
    1033     12767492 :                   pw_grid%ngpts_cut_local = pw_grid%ngpts_cut_local + gmax
    1034              :                END IF
    1035     25534984 :                pw_grid%para%yzq(lo(1), lo(2)) = ip
    1036     25574263 :                IF (pw_grid%grid_span == HALFSPACE) THEN
    1037      1166728 :                   m = -lo(1) - 2*lby + 2
    1038      1166728 :                   n = -lo(2) - 2*lbz + 2
    1039      1166728 :                   pw_grid%para%yzq(m, n) = ip
    1040      1166728 :                   yz_mask(m, n) = 0
    1041              :                END IF
    1042              :             END DO
    1043              : 
    1044        39279 :             DEALLOCATE (yz_index)
    1045              : 
    1046              :             ! Count the total number of rays on each processor
    1047       117837 :             pw_grid%para%nyzray = 0
    1048      1059192 :             DO i = 1, nz
    1049     42025753 :                DO j = 1, ny
    1050     40966561 :                   ip = pw_grid%para%yzq(j, i)
    1051     40966561 :                   IF (ip >= 0) pw_grid%para%nyzray(ip) = &
    1052     40812496 :                      pw_grid%para%nyzray(ip) + 1
    1053              :                END DO
    1054              :             END DO
    1055              : 
    1056              :             ! Allocate mapping array (y:z, nray, nproc)
    1057       117837 :             ns = MAXVAL(pw_grid%para%nyzray(0:np - 1))
    1058       157116 :             ALLOCATE (pw_grid%para%yzp(2, ns, 0:np - 1))
    1059              : 
    1060              :             ! Fill mapping array, recalculate nyzray for convenience
    1061       117837 :             pw_grid%para%nyzray = 0
    1062      1059192 :             DO i = 1, nz
    1063     42025753 :                DO j = 1, ny
    1064     40966561 :                   ip = pw_grid%para%yzq(j, i)
    1065     41986474 :                   IF (ip >= 0) THEN
    1066              :                      pw_grid%para%nyzray(ip) = &
    1067     39792583 :                         pw_grid%para%nyzray(ip) + 1
    1068     39792583 :                      ns = pw_grid%para%nyzray(ip)
    1069     39792583 :                      pw_grid%para%yzp(1, ns, ip) = j
    1070     39792583 :                      pw_grid%para%yzp(2, ns, ip) = i
    1071     39792583 :                      IF (ip == pw_grid%para%group%mepos) THEN
    1072     19896304 :                         pw_grid%para%yzq(j, i) = ns
    1073              :                      ELSE
    1074     19896279 :                         pw_grid%para%yzq(j, i) = -1
    1075              :                      END IF
    1076              :                   ELSE
    1077      1173978 :                      pw_grid%para%yzq(j, i) = -2
    1078              :                   END IF
    1079              :                END DO
    1080              :             END DO
    1081              : 
    1082       157116 :             pw_grid%ngpts_local = PRODUCT(pw_grid%npts_local)
    1083              : 
    1084              :          ELSE
    1085              :             !
    1086              :             !  block distribution of g vectors, we do not have a spherical cutoff
    1087              :             !
    1088              : 
    1089           12 :             pw_grid%para%blocked = .TRUE.
    1090           12 :             pw_grid%para%ray_distribution = .FALSE.
    1091              : 
    1092           36 :             DO ip = 0, np - 1
    1093              :                m = pw_grid%para%bo(2, 2, ip, 3) - &
    1094           24 :                    pw_grid%para%bo(1, 2, ip, 3) + 1
    1095              :                n = pw_grid%para%bo(2, 3, ip, 3) - &
    1096           24 :                    pw_grid%para%bo(1, 3, ip, 3) + 1
    1097           36 :                pw_grid%para%nyzray(ip) = n*m
    1098              :             END DO
    1099              : 
    1100           12 :             ipl = pw_grid%para%group%mepos
    1101              :             l = pw_grid%para%bo(2, 1, ipl, 3) - &
    1102           12 :                 pw_grid%para%bo(1, 1, ipl, 3) + 1
    1103              :             m = pw_grid%para%bo(2, 2, ipl, 3) - &
    1104           12 :                 pw_grid%para%bo(1, 2, ipl, 3) + 1
    1105              :             n = pw_grid%para%bo(2, 3, ipl, 3) - &
    1106           12 :                 pw_grid%para%bo(1, 3, ipl, 3) + 1
    1107           12 :             pw_grid%ngpts_cut_local = l*m*n
    1108           12 :             pw_grid%ngpts_local = pw_grid%ngpts_cut_local
    1109              : 
    1110         4816 :             pw_grid%para%yzq = 0
    1111              :             ny = pw_grid%para%bo(2, 2, ipl, 3) - &
    1112           12 :                  pw_grid%para%bo(1, 2, ipl, 3) + 1
    1113          254 :             DO n = pw_grid%para%bo(1, 3, ipl, 3), &
    1114           12 :                pw_grid%para%bo(2, 3, ipl, 3)
    1115          242 :                i = n - pw_grid%para%bo(1, 3, ipl, 3)
    1116         2523 :                DO m = pw_grid%para%bo(1, 2, ipl, 3), &
    1117          254 :                   pw_grid%para%bo(2, 2, ipl, 3)
    1118         2281 :                   j = m - pw_grid%para%bo(1, 2, ipl, 3) + 1
    1119         2523 :                   pw_grid%para%yzq(m, n) = j + i*ny
    1120              :                END DO
    1121              :             END DO
    1122              : 
    1123              :             ! Allocate mapping array (y:z, nray, nproc)
    1124           36 :             ns = MAXVAL(pw_grid%para%nyzray(0:np - 1))
    1125           48 :             ALLOCATE (pw_grid%para%yzp(2, ns, 0:np - 1))
    1126        14112 :             pw_grid%para%yzp = 0
    1127              : 
    1128           24 :             ALLOCATE (pemap(0:np - 1))
    1129           12 :             pemap = 0
    1130           12 :             pemap(pw_grid%para%group%mepos) = pw_grid%para%group%mepos
    1131           12 :             CALL pw_grid%para%group%sum(pemap)
    1132              : 
    1133           36 :             DO ip = 0, np - 1
    1134           24 :                ipp = pemap(ip)
    1135           24 :                ns = 0
    1136          508 :                DO n = pw_grid%para%bo(1, 3, ipp, 3), &
    1137           24 :                   pw_grid%para%bo(2, 3, ipp, 3)
    1138          484 :                   i = n - pw_grid%bounds(1, 3) + 1
    1139         5046 :                   DO m = pw_grid%para%bo(1, 2, ipp, 3), &
    1140          508 :                      pw_grid%para%bo(2, 2, ipp, 3)
    1141         4562 :                      j = m - pw_grid%bounds(1, 2) + 1
    1142         4562 :                      ns = ns + 1
    1143         4562 :                      pw_grid%para%yzp(1, ns, ip) = j
    1144         5046 :                      pw_grid%para%yzp(2, ns, ip) = i
    1145              :                   END DO
    1146              :                END DO
    1147           36 :                CPASSERT(ns == pw_grid%para%nyzray(ip))
    1148              :             END DO
    1149              : 
    1150           12 :             DEALLOCATE (pemap)
    1151              : 
    1152              :          END IF
    1153              : 
    1154              :       END IF
    1155              : 
    1156              :       ! pos_of_x(i) tells on which cpu pw%array(i,:,:) is located
    1157              :       ! should be computable in principle, without the need for communication
    1158        44594 :       IF (pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
    1159       117873 :          ALLOCATE (pw_grid%para%pos_of_x(pw_grid%bounds(1, 1):pw_grid%bounds(2, 1)))
    1160      1027678 :          pw_grid%para%pos_of_x = 0
    1161       533487 :          pw_grid%para%pos_of_x(pw_grid%bounds_local(1, 1):pw_grid%bounds_local(2, 1)) = pw_grid%para%group%mepos
    1162        39291 :          CALL pw_grid%para%group%sum(pw_grid%para%pos_of_x)
    1163              :       ELSE
    1164              :          ! this should not be needed
    1165        15909 :          ALLOCATE (pw_grid%para%pos_of_x(pw_grid%bounds(1, 1):pw_grid%bounds(2, 1)))
    1166        91704 :          pw_grid%para%pos_of_x = 0
    1167              :       END IF
    1168              : 
    1169        44594 :       CALL timestop(handle)
    1170              : 
    1171        44594 :    END SUBROUTINE pw_grid_distribute
    1172              : 
    1173              : ! **************************************************************************************************
    1174              : !> \brief ...
    1175              : !> \param pw_grid ...
    1176              : !> \param yz_mask ...
    1177              : !> \param ref_grid ...
    1178              : !> \par History
    1179              : !>      - Fix mapping bug for pw_grid eqv to ref_grid (21.11.2019, MK)
    1180              : ! **************************************************************************************************
    1181        24084 :    SUBROUTINE pre_tag(pw_grid, yz_mask, ref_grid)
    1182              : 
    1183              :       TYPE(pw_grid_type), INTENT(INOUT)                  :: pw_grid
    1184              :       INTEGER, DIMENSION(:, :), INTENT(INOUT)            :: yz_mask
    1185              :       TYPE(pw_grid_type), INTENT(IN)                     :: ref_grid
    1186              : 
    1187              :       INTEGER                                            :: gmax, ig, ip, lby, lbz, my, mz, ny, nz, &
    1188              :                                                             uby, ubz, y, yp, z, zp
    1189              : 
    1190        24084 :       ny = ref_grid%npts(2)
    1191        24084 :       nz = ref_grid%npts(3)
    1192        24084 :       lby = pw_grid%bounds(1, 2)
    1193        24084 :       lbz = pw_grid%bounds(1, 3)
    1194        24084 :       uby = pw_grid%bounds(2, 2)
    1195        24084 :       ubz = pw_grid%bounds(2, 3)
    1196        24084 :       my = SIZE(yz_mask, 1)
    1197        24084 :       mz = SIZE(yz_mask, 2)
    1198              : 
    1199              :       ! loop over all processors and all g vectors yz lines on this processor
    1200        72252 :       DO ip = 0, ref_grid%para%group%num_pe - 1
    1201     64604246 :          DO ig = 1, ref_grid%para%nyzray(ip)
    1202              :             ! go from mapped coordinates to original coordinates
    1203              :             ! 1, 2, ..., n-1, n -> 0, 1, ..., (n/2)-1, -(n/2), -(n/2)+1, ..., -2, -1
    1204     64531994 :             y = ref_grid%para%yzp(1, ig, ip) - 1
    1205     64531994 :             IF (y >= ny/2) y = y - ny
    1206     64531994 :             z = ref_grid%para%yzp(2, ig, ip) - 1
    1207     64531994 :             IF (z >= nz/2) z = z - nz
    1208              :             ! check if this is inside the realm of the new grid
    1209     64531994 :             IF (y < lby .OR. y > uby .OR. z < lbz .OR. z > ubz) CYCLE
    1210              :             ! go to shifted coordinates
    1211     13093407 :             y = y - lby + 1
    1212     13093407 :             z = z - lbz + 1
    1213              :             ! this tag is outside the cutoff range of the new grid
    1214     13093407 :             IF (pw_grid%grid_span == HALFSPACE) THEN
    1215            0 :                yp = -y - 2*lby + 2
    1216            0 :                zp = -z - 2*lbz + 2
    1217              :                ! if the reference grid is larger than the mirror point may be
    1218              :                ! outside the new grid even if the original point is inside
    1219            0 :                IF (yp < 1 .OR. yp > my .OR. zp < 1 .OR. zp > mz) CYCLE
    1220            0 :                gmax = MAX(yz_mask(y, z), yz_mask(yp, zp))
    1221            0 :                IF (gmax == 0) CYCLE
    1222            0 :                yz_mask(y, z) = 0
    1223            0 :                yz_mask(yp, zp) = 0
    1224            0 :                pw_grid%para%yzq(y, z) = ip
    1225            0 :                pw_grid%para%yzq(yp, zp) = ip
    1226              :             ELSE
    1227     13093407 :                gmax = yz_mask(y, z)
    1228     13093407 :                IF (gmax == 0) CYCLE
    1229     13093407 :                yz_mask(y, z) = 0
    1230     13093407 :                pw_grid%para%yzq(y, z) = ip
    1231              :             END IF
    1232     13141575 :             IF (ip == pw_grid%para%group%mepos) THEN
    1233      6546716 :                pw_grid%ngpts_cut_local = pw_grid%ngpts_cut_local + gmax
    1234              :             END IF
    1235              :          END DO
    1236              :       END DO
    1237              : 
    1238        24084 :    END SUBROUTINE pre_tag
    1239              : 
    1240              : ! **************************************************************************************************
    1241              : !> \brief ...
    1242              : !> \param yz_mask ...
    1243              : !> \param yz_index ...
    1244              : ! **************************************************************************************************
    1245        39279 :    PURE SUBROUTINE order_mask(yz_mask, yz_index)
    1246              : 
    1247              :       INTEGER, DIMENSION(:, :), INTENT(IN)               :: yz_mask
    1248              :       INTEGER, DIMENSION(:, :), INTENT(OUT)              :: yz_index
    1249              : 
    1250              :       INTEGER                                            :: i1, i2, ic, icount, ii, im, jc, jj
    1251              : 
    1252              : !NB load balance
    1253              : !------------------------------------------------------------------------------
    1254              : !NB spiral out from origin, so that even if overall grid is full and
    1255              : !NB block distributed, spherical cutoff still leads to good load
    1256              : !NB balance in cp_ddapc_apply_CD
    1257              : 
    1258        39279 :       i1 = SIZE(yz_mask, 1)
    1259        39279 :       i2 = SIZE(yz_mask, 2)
    1260    122938962 :       yz_index = 0
    1261              : 
    1262        39279 :       icount = 1
    1263        39279 :       ic = i1/2
    1264        39279 :       jc = i2/2
    1265        39279 :       ii = ic
    1266        39279 :       jj = jc
    1267        39279 :       IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2) THEN
    1268        39279 :          IF (yz_mask(ii, jj) /= 0) THEN
    1269        15195 :             yz_index(1, icount) = ii
    1270        15195 :             yz_index(2, icount) = jj
    1271        15195 :             icount = icount + 1
    1272              :          END IF
    1273              :       END IF
    1274       584860 :       DO im = 1, MAX(ic + 1, jc + 1)
    1275       545581 :          ii = ic - im
    1276     14091920 :          DO jj = jc - im, jc + im
    1277     14091920 :             IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2) THEN
    1278      9728019 :                IF (yz_mask(ii, jj) /= 0) THEN
    1279      6127407 :                   yz_index(1, icount) = ii
    1280      6127407 :                   yz_index(2, icount) = jj
    1281      6127407 :                   icount = icount + 1
    1282              :                END IF
    1283              :             END IF
    1284              :          END DO
    1285       545581 :          ii = ic + im
    1286     14091920 :          DO jj = jc - im, jc + im
    1287     14091920 :             IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2) THEN
    1288     10984934 :                IF (yz_mask(ii, jj) /= 0) THEN
    1289      6682807 :                   yz_index(1, icount) = ii
    1290      6682807 :                   yz_index(2, icount) = jj
    1291      6682807 :                   icount = icount + 1
    1292              :                END IF
    1293              :             END IF
    1294              :          END DO
    1295       545581 :          jj = jc - im
    1296     13000758 :          DO ii = ic - im + 1, ic + im - 1
    1297     13000758 :             IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2) THEN
    1298      9504917 :                IF (yz_mask(ii, jj) /= 0) THEN
    1299      6349681 :                   yz_index(1, icount) = ii
    1300      6349681 :                   yz_index(2, icount) = jj
    1301      6349681 :                   icount = icount + 1
    1302              :                END IF
    1303              :             END IF
    1304              :          END DO
    1305     13000758 :          jj = jc + im
    1306     13040037 :          DO ii = ic - im + 1, ic + im - 1
    1307     13000758 :             IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2) THEN
    1308     10709412 :                IF (yz_mask(ii, jj) /= 0) THEN
    1309      6359894 :                   yz_index(1, icount) = ii
    1310      6359894 :                   yz_index(2, icount) = jj
    1311      6359894 :                   icount = icount + 1
    1312              :                END IF
    1313              :             END IF
    1314              :          END DO
    1315              :       END DO
    1316              : 
    1317        39279 :    END SUBROUTINE order_mask
    1318              : ! **************************************************************************************************
    1319              : !> \brief compute the length of g vectors
    1320              : !> \param h_inv ...
    1321              : !> \param length_x ...
    1322              : !> \param length_y ...
    1323              : !> \param length_z ...
    1324              : !> \param length ...
    1325              : !> \param l ...
    1326              : !> \param m ...
    1327              : !> \param n ...
    1328              : ! **************************************************************************************************
    1329   2324628995 :    PURE SUBROUTINE pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
    1330              : 
    1331              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN)         :: h_inv
    1332              :       REAL(KIND=dp), INTENT(OUT)                         :: length_x, length_y, length_z, length
    1333              :       INTEGER, INTENT(IN)                                :: l, m, n
    1334              : 
    1335              :       length_x &
    1336              :          = REAL(l, dp)*h_inv(1, 1) &
    1337              :            + REAL(m, dp)*h_inv(2, 1) &
    1338   2324628995 :            + REAL(n, dp)*h_inv(3, 1)
    1339              :       length_y &
    1340              :          = REAL(l, dp)*h_inv(1, 2) &
    1341              :            + REAL(m, dp)*h_inv(2, 2) &
    1342   2324628995 :            + REAL(n, dp)*h_inv(3, 2)
    1343              :       length_z &
    1344              :          = REAL(l, dp)*h_inv(1, 3) &
    1345              :            + REAL(m, dp)*h_inv(2, 3) &
    1346   2324628995 :            + REAL(n, dp)*h_inv(3, 3)
    1347              : 
    1348              :       ! enforce strict zero-ness in this case (compiler optimization)
    1349   2324628995 :       IF (l == 0 .AND. m == 0 .AND. n == 0) THEN
    1350        49877 :          length_x = 0
    1351        49877 :          length_y = 0
    1352        49877 :          length_z = 0
    1353              :       END IF
    1354              : 
    1355   2324628995 :       length_x = length_x*twopi
    1356   2324628995 :       length_y = length_y*twopi
    1357   2324628995 :       length_z = length_z*twopi
    1358              : 
    1359   2324628995 :       length = length_x**2 + length_y**2 + length_z**2
    1360              : 
    1361   2324628995 :    END SUBROUTINE pw_vec_length
    1362              : 
    1363              : ! **************************************************************************************************
    1364              : !> \brief True for rays that must stay out of the stored half-space: on an
    1365              : !>        asymmetric (even) frequency window the -g mirror of a ray on the
    1366              : !>        lower extreme plane falls outside the grid, while the ray
    1367              : !>        distribution and the negation maps both require the stored
    1368              : !>        half-space to be closed under negation (the z = 0 plane cut in
    1369              : !>        pw_grid_count and the tally check in pw_grid_remap serve the same
    1370              : !>        contract). Symmetric (odd) windows are never affected.
    1371              : !> \param grid_span ...
    1372              : !> \param m ray frequency in direction 2
    1373              : !> \param n ray frequency in direction 3
    1374              : !> \param bounds global frequency bounds of the grid
    1375              : !> \return whether the -g mirror of the ray falls outside the grid
    1376              : ! **************************************************************************************************
    1377   1251745019 :    PURE FUNCTION mirror_outside_bounds(grid_span, m, n, bounds) RESULT(outside)
    1378              : 
    1379              :       INTEGER, INTENT(IN)                                :: grid_span, m, n
    1380              :       INTEGER, DIMENSION(2, 3), INTENT(IN)               :: bounds
    1381              :       LOGICAL                                            :: outside
    1382              : 
    1383              :       outside = grid_span == HALFSPACE .AND. &
    1384              :                 ((m == bounds(1, 2) .AND. bounds(2, 2) < -bounds(1, 2)) .OR. &
    1385   1251745019 :                  (n == bounds(1, 3) .AND. bounds(2, 3) < -bounds(1, 3)))
    1386              : 
    1387   1251745019 :    END FUNCTION mirror_outside_bounds
    1388              : 
    1389              : ! **************************************************************************************************
    1390              : !> \brief Count total number of g vectors
    1391              : !> \param h_inv ...
    1392              : !> \param pw_grid ...
    1393              : !> \param mp_comm ...
    1394              : !> \param cutoff ...
    1395              : !> \param yz_mask ...
    1396              : !> \par History
    1397              : !>      JGH (22-12-2000) : Adapted for parallel use
    1398              : !> \author apsi
    1399              : !>      Christopher Mundy
    1400              : ! **************************************************************************************************
    1401        44594 :    SUBROUTINE pw_grid_count(h_inv, pw_grid, mp_comm, cutoff, yz_mask)
    1402              : 
    1403              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: h_inv
    1404              :       TYPE(pw_grid_type), INTENT(INOUT)                  :: pw_grid
    1405              : 
    1406              :       CLASS(mp_comm_type), INTENT(IN) :: mp_comm
    1407              :       REAL(KIND=dp), INTENT(IN)                          :: cutoff
    1408              :       INTEGER, DIMENSION(:, :), INTENT(OUT)              :: yz_mask
    1409              : 
    1410              :       INTEGER                                            :: l, m, mm, n, n_upperlimit, nlim(2), nn
    1411              :       INTEGER(KIND=int_8)                                :: gpt
    1412              :       REAL(KIND=dp)                                      :: length, length_x, length_y, length_z
    1413              : 
    1414              :       ASSOCIATE (bounds => pw_grid%bounds)
    1415              : 
    1416        44594 :          IF (pw_grid%grid_span == HALFSPACE) THEN
    1417              :             n_upperlimit = 0
    1418        40851 :          ELSE IF (pw_grid%grid_span == FULLSPACE) THEN
    1419        40851 :             n_upperlimit = bounds(2, 3)
    1420              :          ELSE
    1421            0 :             CPABORT("No type set for the grid")
    1422              :          END IF
    1423              : 
    1424              :          ! finds valid g-points within grid
    1425        44594 :          gpt = 0
    1426        44594 :          IF (pw_grid%para%mode == PW_MODE_LOCAL) THEN
    1427         5303 :             nlim(1) = bounds(1, 3)
    1428         5303 :             nlim(2) = n_upperlimit
    1429        39291 :          ELSE IF (pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
    1430        39291 :             n = n_upperlimit - bounds(1, 3) + 1
    1431        39291 :             nlim = get_limit(n, mp_comm%num_pe, mp_comm%mepos)
    1432       117873 :             nlim = nlim + bounds(1, 3) - 1
    1433              :          ELSE
    1434            0 :             CPABORT("para % mode not specified")
    1435              :          END IF
    1436              : 
    1437     44529362 :          yz_mask = 0
    1438       646931 :          DO n = nlim(1), nlim(2)
    1439       557743 :             nn = n - bounds(1, 3) + 1
    1440     21857187 :             DO m = bounds(1, 2), bounds(2, 2)
    1441     21254850 :                mm = m - bounds(1, 2) + 1
    1442   1193597221 :                DO l = bounds(1, 1), bounds(2, 1)
    1443   1171784628 :                   IF (pw_grid%grid_span == HALFSPACE .AND. n == 0) THEN
    1444      3003142 :                      IF ((m == 0 .AND. l > 0) .OR. (m > 0)) CYCLE
    1445              :                   END IF
    1446              :                   ! keep the stored half-space closed under negation: the ray
    1447              :                   ! distribution and the negation maps rely on it (see also the
    1448              :                   ! z = 0 plane cut above and mirror_outside_bounds)
    1449   1170121149 :                   IF (mirror_outside_bounds(pw_grid%grid_span, m, n, bounds)) CYCLE
    1450              : 
    1451   1168715295 :                   CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
    1452              : 
    1453   1189970145 :                   IF (0.5_dp*length <= cutoff) THEN
    1454   1131524529 :                      gpt = gpt + 1
    1455   1131524529 :                      yz_mask(mm, nn) = yz_mask(mm, nn) + 1
    1456              :                   END IF
    1457              : 
    1458              :                END DO
    1459              :             END DO
    1460              :          END DO
    1461              :       END ASSOCIATE
    1462              : 
    1463              :       ! number of g-vectors for grid
    1464        44594 :       IF (pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
    1465        39291 :          CALL mp_comm%sum(gpt)
    1466     84021847 :          CALL mp_comm%sum(yz_mask)
    1467              :       END IF
    1468        44594 :       pw_grid%ngpts_cut = gpt
    1469              : 
    1470        44594 :    END SUBROUTINE pw_grid_count
    1471              : 
    1472              : ! **************************************************************************************************
    1473              : !> \brief Setup maps from 1d to 3d space
    1474              : !> \param h_inv ...
    1475              : !> \param pw_grid ...
    1476              : !> \param cutoff ...
    1477              : !> \par History
    1478              : !>      JGH (29-12-2000) : Adapted for parallel use
    1479              : !> \author apsi
    1480              : !>      Christopher Mundy
    1481              : ! **************************************************************************************************
    1482        44594 :    SUBROUTINE pw_grid_assign(h_inv, pw_grid, cutoff)
    1483              : 
    1484              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: h_inv
    1485              :       TYPE(pw_grid_type), INTENT(INOUT)                  :: pw_grid
    1486              :       REAL(KIND=dp), INTENT(IN)                          :: cutoff
    1487              : 
    1488              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_grid_assign'
    1489              : 
    1490              :       INTEGER                                            :: gpt, handle, i, ip, l, lby, lbz, ll, m, &
    1491              :                                                             mm, n, n_upperlimit, nn
    1492              :       INTEGER(KIND=int_8)                                :: gpt_global
    1493              :       INTEGER, DIMENSION(2, 3)                           :: bol, bounds
    1494              :       REAL(KIND=dp)                                      :: length, length_x, length_y, length_z
    1495              : 
    1496        44594 :       CALL timeset(routineN, handle)
    1497              : 
    1498       445940 :       bounds = pw_grid%bounds
    1499        44594 :       lby = pw_grid%bounds(1, 2)
    1500        44594 :       lbz = pw_grid%bounds(1, 3)
    1501              : 
    1502        44594 :       IF (pw_grid%grid_span == HALFSPACE) THEN
    1503              :          n_upperlimit = 0
    1504        40851 :       ELSE IF (pw_grid%grid_span == FULLSPACE) THEN
    1505        40851 :          n_upperlimit = bounds(2, 3)
    1506              :       ELSE
    1507            0 :          CPABORT("No type set for the grid")
    1508              :       END IF
    1509              : 
    1510              :       ! finds valid g-points within grid
    1511        44594 :       IF (pw_grid%para%mode == PW_MODE_LOCAL) THEN
    1512         5303 :          gpt = 0
    1513        73233 :          DO n = bounds(1, 3), n_upperlimit
    1514      1686879 :             DO m = bounds(1, 2), bounds(2, 2)
    1515     64782208 :                DO l = bounds(1, 1), bounds(2, 1)
    1516     63100632 :                   IF (pw_grid%grid_span == HALFSPACE .AND. n == 0) THEN
    1517      1270369 :                      IF ((m == 0 .AND. l > 0) .OR. (m > 0)) CYCLE
    1518              :                   END IF
    1519              :                   ! keep the stored half-space closed under negation (see pw_grid_count)
    1520     62291818 :                   IF (mirror_outside_bounds(pw_grid%grid_span, m, n, bounds)) CYCLE
    1521              : 
    1522     62167234 :                   CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
    1523              : 
    1524     63780880 :                   IF (0.5_dp*length <= cutoff) THEN
    1525     48658111 :                      gpt = gpt + 1
    1526     48658111 :                      pw_grid%g(1, gpt) = length_x
    1527     48658111 :                      pw_grid%g(2, gpt) = length_y
    1528     48658111 :                      pw_grid%g(3, gpt) = length_z
    1529     48658111 :                      pw_grid%gsq(gpt) = length
    1530     48658111 :                      pw_grid%g_hat(1, gpt) = l
    1531     48658111 :                      pw_grid%g_hat(2, gpt) = m
    1532     48658111 :                      pw_grid%g_hat(3, gpt) = n
    1533              :                   END IF
    1534              : 
    1535              :                END DO
    1536              :             END DO
    1537              :          END DO
    1538              : 
    1539              :       ELSE
    1540              : 
    1541        39291 :          IF (pw_grid%para%ray_distribution) THEN
    1542              : 
    1543        39279 :             gpt = 0
    1544        39279 :             ip = pw_grid%para%group%mepos
    1545     19935583 :             DO i = 1, pw_grid%para%nyzray(ip)
    1546     19896304 :                n = pw_grid%para%yzp(2, i, ip) + lbz - 1
    1547     19896304 :                m = pw_grid%para%yzp(1, i, ip) + lby - 1
    1548     19896304 :                IF (n > n_upperlimit) CYCLE
    1549              :                ! keep the stored half-space closed under negation (see pw_grid_count)
    1550     19332052 :                IF (mirror_outside_bounds(pw_grid%grid_span, m, n, bounds)) CYCLE
    1551   1113850363 :                DO l = bounds(1, 1), bounds(2, 1)
    1552   1094479032 :                   IF (pw_grid%grid_span == HALFSPACE .AND. n == 0) THEN
    1553      1552935 :                      IF ((m == 0 .AND. l > 0) .OR. (m > 0)) CYCLE
    1554              :                   END IF
    1555              : 
    1556   1093703545 :                   CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
    1557              : 
    1558   1113599849 :                   IF (0.5_dp*length <= cutoff) THEN
    1559   1082823132 :                      gpt = gpt + 1
    1560   1082823132 :                      pw_grid%g(1, gpt) = length_x
    1561   1082823132 :                      pw_grid%g(2, gpt) = length_y
    1562   1082823132 :                      pw_grid%g(3, gpt) = length_z
    1563   1082823132 :                      pw_grid%gsq(gpt) = length
    1564   1082823132 :                      pw_grid%g_hat(1, gpt) = l
    1565   1082823132 :                      pw_grid%g_hat(2, gpt) = m
    1566   1082823132 :                      pw_grid%g_hat(3, gpt) = n
    1567              :                   END IF
    1568              : 
    1569              :                END DO
    1570              :             END DO
    1571              : 
    1572              :          ELSE
    1573              : 
    1574          120 :             bol = pw_grid%para%bo(:, :, pw_grid%para%group%mepos, 3)
    1575           12 :             gpt = 0
    1576          254 :             DO n = bounds(1, 3), bounds(2, 3)
    1577          242 :                IF (n < 0) THEN
    1578          120 :                   nn = n + pw_grid%npts(3) + 1
    1579              :                ELSE
    1580          122 :                   nn = n + 1
    1581              :                END IF
    1582          242 :                IF (nn < bol(1, 3) .OR. nn > bol(2, 3)) CYCLE
    1583         4816 :                DO m = bounds(1, 2), bounds(2, 2)
    1584         4562 :                   IF (m < 0) THEN
    1585         2216 :                      mm = m + pw_grid%npts(2) + 1
    1586              :                   ELSE
    1587         2346 :                      mm = m + 1
    1588              :                   END IF
    1589         4562 :                   IF (mm < bol(1, 2) .OR. mm > bol(2, 2)) CYCLE
    1590        45444 :                   DO l = bounds(1, 1), bounds(2, 1)
    1591        42921 :                      IF (l < 0) THEN
    1592        21148 :                         ll = l + pw_grid%npts(1) + 1
    1593              :                      ELSE
    1594        21773 :                         ll = l + 1
    1595              :                      END IF
    1596        42921 :                      IF (ll < bol(1, 1) .OR. ll > bol(2, 1)) CYCLE
    1597              : 
    1598        42921 :                      CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
    1599              : 
    1600        42921 :                      gpt = gpt + 1
    1601        42921 :                      pw_grid%g(1, gpt) = length_x
    1602        42921 :                      pw_grid%g(2, gpt) = length_y
    1603        42921 :                      pw_grid%g(3, gpt) = length_z
    1604        42921 :                      pw_grid%gsq(gpt) = length
    1605        42921 :                      pw_grid%g_hat(1, gpt) = l
    1606        42921 :                      pw_grid%g_hat(2, gpt) = m
    1607        47483 :                      pw_grid%g_hat(3, gpt) = n
    1608              : 
    1609              :                   END DO
    1610              :                END DO
    1611              :             END DO
    1612              : 
    1613              :          END IF
    1614              : 
    1615              :       END IF
    1616              : 
    1617              :       ! Check the number of g-vectors for grid
    1618        44594 :       CPASSERT(pw_grid%ngpts_cut_local == gpt)
    1619        44594 :       IF (pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
    1620        39291 :          gpt_global = gpt
    1621        39291 :          CALL pw_grid%para%group%sum(gpt_global)
    1622        39291 :          CPASSERT(pw_grid%ngpts_cut == gpt_global)
    1623              :       END IF
    1624              : 
    1625        44594 :       pw_grid%have_g0 = .FALSE.
    1626        44594 :       pw_grid%first_gne0 = 1
    1627    851034970 :       DO gpt = 1, pw_grid%ngpts_cut_local
    1628    867125292 :          IF (ALL(pw_grid%g_hat(:, gpt) == 0)) THEN
    1629        24936 :             pw_grid%have_g0 = .TRUE.
    1630        24936 :             pw_grid%first_gne0 = 2
    1631        24936 :             EXIT
    1632              :          END IF
    1633              :       END DO
    1634              : 
    1635              :       CALL pw_grid_set_maps(pw_grid%grid_span, pw_grid%g_hat, &
    1636        44594 :                             pw_grid%mapl, pw_grid%mapm, pw_grid%mapn, pw_grid%npts)
    1637              : 
    1638        44594 :       CALL timestop(handle)
    1639              : 
    1640        44594 :    END SUBROUTINE pw_grid_assign
    1641              : 
    1642              : ! **************************************************************************************************
    1643              : !> \brief Setup maps from 1d to 3d space
    1644              : !> \param grid_span ...
    1645              : !> \param g_hat ...
    1646              : !> \param mapl ...
    1647              : !> \param mapm ...
    1648              : !> \param mapn ...
    1649              : !> \param npts ...
    1650              : !> \par History
    1651              : !>      JGH (21-12-2000) : Size of g_hat locally determined
    1652              : !> \author apsi
    1653              : !>      Christopher Mundy
    1654              : !> \note
    1655              : !>      Maps are to full 3D space (not distributed)
    1656              : ! **************************************************************************************************
    1657        44594 :    SUBROUTINE pw_grid_set_maps(grid_span, g_hat, mapl, mapm, mapn, npts)
    1658              : 
    1659              :       INTEGER, INTENT(IN)                                :: grid_span
    1660              :       INTEGER, DIMENSION(:, :), INTENT(IN)               :: g_hat
    1661              :       TYPE(map_pn), INTENT(INOUT)                        :: mapl, mapm, mapn
    1662              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: npts
    1663              : 
    1664              :       INTEGER                                            :: gpt, l, m, n, ng
    1665              : 
    1666        44594 :       ng = SIZE(g_hat, 2)
    1667              : 
    1668   1131568758 :       DO gpt = 1, ng
    1669   1131524164 :          l = g_hat(1, gpt)
    1670   1131524164 :          m = g_hat(2, gpt)
    1671   1131524164 :          n = g_hat(3, gpt)
    1672   1131524164 :          IF (l < 0) THEN
    1673    562665249 :             mapl%pos(l) = l + npts(1)
    1674              :          ELSE
    1675    568858915 :             mapl%pos(l) = l
    1676              :          END IF
    1677   1131524164 :          IF (m < 0) THEN
    1678    563150151 :             mapm%pos(m) = m + npts(2)
    1679              :          ELSE
    1680    568374013 :             mapm%pos(m) = m
    1681              :          END IF
    1682   1131524164 :          IF (n < 0) THEN
    1683    577983695 :             mapn%pos(n) = n + npts(3)
    1684              :          ELSE
    1685    553540469 :             mapn%pos(n) = n
    1686              :          END IF
    1687              : 
    1688              :          ! Generating the maps to the full 3-d space
    1689              : 
    1690   1131568758 :          IF (grid_span == HALFSPACE) THEN
    1691              : 
    1692     31343939 :             IF (l <= 0) THEN
    1693     16153597 :                mapl%neg(l) = -l
    1694              :             ELSE
    1695     15190342 :                mapl%neg(l) = npts(1) - l
    1696              :             END IF
    1697     31343939 :             IF (m <= 0) THEN
    1698     16575058 :                mapm%neg(m) = -m
    1699              :             ELSE
    1700     14768881 :                mapm%neg(m) = npts(2) - m
    1701              :             END IF
    1702     31343939 :             IF (n <= 0) THEN
    1703     31343939 :                mapn%neg(n) = -n
    1704              :             ELSE
    1705            0 :                mapn%neg(n) = npts(3) - n
    1706              :             END IF
    1707              : 
    1708              :          END IF
    1709              : 
    1710              :       END DO
    1711              : 
    1712        44594 :    END SUBROUTINE pw_grid_set_maps
    1713              : 
    1714              : ! **************************************************************************************************
    1715              : !> \brief Allocate all (Pointer) Arrays in pw_grid
    1716              : !> \param pw_grid ...
    1717              : !> \param ng ...
    1718              : !> \param bounds ...
    1719              : !> \par History
    1720              : !>      JGH (20-12-2000) : Added status variable
    1721              : !>                         Bounds of arrays now from calling routine, this
    1722              : !>                         makes it independent from parallel setup
    1723              : !> \author apsi
    1724              : !>      Christopher Mundy
    1725              : ! **************************************************************************************************
    1726        44594 :    SUBROUTINE pw_grid_allocate(pw_grid, ng, bounds)
    1727              : 
    1728              :       ! Argument
    1729              :       TYPE(pw_grid_type), INTENT(INOUT)        :: pw_grid
    1730              :       INTEGER, INTENT(IN)                      :: ng
    1731              :       INTEGER, DIMENSION(:, :), INTENT(IN)     :: bounds
    1732              : 
    1733              :       CHARACTER(len=*), PARAMETER :: routineN = 'pw_grid_allocate'
    1734              : 
    1735              :       INTEGER                                    :: nmaps
    1736              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    1737              :       INTEGER(KIND=C_SIZE_T)                     :: length
    1738              :       TYPE(C_PTR)                                :: cptr_g_hatmap
    1739              :       INTEGER                                    :: stat
    1740              : #endif
    1741              : 
    1742              :       INTEGER                                  :: handle
    1743              : 
    1744        44594 :       CALL timeset(routineN, handle)
    1745              : 
    1746       133782 :       ALLOCATE (pw_grid%g(3, ng))
    1747       133782 :       ALLOCATE (pw_grid%gsq(ng))
    1748       133782 :       ALLOCATE (pw_grid%g_hat(3, ng))
    1749              : 
    1750        44594 :       nmaps = 1
    1751        44594 :       IF (pw_grid%grid_span == HALFSPACE) nmaps = 2
    1752              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    1753              :       CALL offload_activate_chosen_device()
    1754              : 
    1755              :       length = INT(int_size*MAX(ng, 1)*MAX(nmaps, 1), KIND=C_SIZE_T)
    1756              :       stat = offload_malloc_pinned_mem(cptr_g_hatmap, length)
    1757              :       CPASSERT(stat == 0)
    1758              :       CALL c_f_pointer(cptr_g_hatmap, pw_grid%g_hatmap, [MAX(ng, 1), MAX(nmaps, 1)])
    1759              : #else
    1760       178376 :       ALLOCATE (pw_grid%g_hatmap(MAX(ng, 1), MAX(nmaps, 1)))
    1761              : #endif
    1762              : 
    1763        44594 :       IF (pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
    1764              :          ALLOCATE (pw_grid%grays(pw_grid%npts(1), &
    1765       157164 :                                  pw_grid%para%nyzray(pw_grid%para%group%mepos)))
    1766              :       END IF
    1767              : 
    1768       133782 :       ALLOCATE (pw_grid%mapl%pos(bounds(1, 1):bounds(2, 1)))
    1769        89188 :       ALLOCATE (pw_grid%mapl%neg(bounds(1, 1):bounds(2, 1)))
    1770       133782 :       ALLOCATE (pw_grid%mapm%pos(bounds(1, 2):bounds(2, 2)))
    1771        89188 :       ALLOCATE (pw_grid%mapm%neg(bounds(1, 2):bounds(2, 2)))
    1772       133782 :       ALLOCATE (pw_grid%mapn%pos(bounds(1, 3):bounds(2, 3)))
    1773        89188 :       ALLOCATE (pw_grid%mapn%neg(bounds(1, 3):bounds(2, 3)))
    1774              : 
    1775        44594 :       CALL timestop(handle)
    1776              : 
    1777        44594 :    END SUBROUTINE pw_grid_allocate
    1778              : 
    1779              : ! **************************************************************************************************
    1780              : !> \brief Sort g-vectors according to length
    1781              : !> \param pw_grid ...
    1782              : !> \param ref_grid ...
    1783              : !> \par History
    1784              : !>      JGH (20-12-2000) : allocate idx, ng = SIZE ( pw_grid % gsq ) the
    1785              : !>                         sorting is local and independent from parallelisation
    1786              : !>                         WARNING: Global ordering depends now on the number
    1787              : !>                                  of cpus.
    1788              : !>      JGH (28-02-2001) : check for ordering against reference grid
    1789              : !>      JGH (01-05-2001) : sort spherical cutoff grids also within shells
    1790              : !>                         reference grids for non-spherical cutoffs
    1791              : !>      JGH (20-06-2001) : do not sort non-spherical grids
    1792              : !>      JGH (19-02-2003) : Order all grids, this makes subgrids also for
    1793              : !>                         non-spherical cutoffs possible
    1794              : !>      JGH (21-02-2003) : Introduce gather array for general reference grids
    1795              : !> \author apsi
    1796              : !>      Christopher Mundy
    1797              : ! **************************************************************************************************
    1798        44594 :    SUBROUTINE pw_grid_sort(pw_grid, ref_grid)
    1799              : 
    1800              :       ! Argument
    1801              :       TYPE(pw_grid_type), INTENT(INOUT)                  :: pw_grid
    1802              :       TYPE(pw_grid_type), INTENT(IN), OPTIONAL           :: ref_grid
    1803              : 
    1804              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_grid_sort'
    1805              : 
    1806              :       INTEGER                                            :: handle, i, ig, ih, ip, is, it, ng, ngr
    1807              :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: idx
    1808        44594 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: int_tmp
    1809              :       LOGICAL                                            :: g_found
    1810              :       REAL(KIND=dp)                                      :: gig, gigr
    1811        44594 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: real_tmp
    1812              : 
    1813        44594 :       CALL timeset(routineN, handle)
    1814              : 
    1815        44594 :       ng = SIZE(pw_grid%gsq)
    1816       133782 :       ALLOCATE (idx(ng))
    1817              : 
    1818              :       ! grids are (locally) ordered by length of G-vectors
    1819        44594 :       CALL sort(pw_grid%gsq, ng, idx)
    1820              :       ! within shells order wrt x,y,z
    1821        44594 :       CALL sort_shells(pw_grid%gsq, pw_grid%g_hat, idx)
    1822              : 
    1823       133782 :       ALLOCATE (real_tmp(3, ng))
    1824   1131568758 :       DO i = 1, ng
    1825   1131524164 :          real_tmp(1, i) = pw_grid%g(1, idx(i))
    1826   1131524164 :          real_tmp(2, i) = pw_grid%g(2, idx(i))
    1827   1131568758 :          real_tmp(3, i) = pw_grid%g(3, idx(i))
    1828              :       END DO
    1829   1131568758 :       DO i = 1, ng
    1830   1131524164 :          pw_grid%g(1, i) = real_tmp(1, i)
    1831   1131524164 :          pw_grid%g(2, i) = real_tmp(2, i)
    1832   1131568758 :          pw_grid%g(3, i) = real_tmp(3, i)
    1833              :       END DO
    1834        44594 :       DEALLOCATE (real_tmp)
    1835              : 
    1836       133782 :       ALLOCATE (int_tmp(3, ng))
    1837   1131568758 :       DO i = 1, ng
    1838   1131524164 :          int_tmp(1, i) = pw_grid%g_hat(1, idx(i))
    1839   1131524164 :          int_tmp(2, i) = pw_grid%g_hat(2, idx(i))
    1840   1131568758 :          int_tmp(3, i) = pw_grid%g_hat(3, idx(i))
    1841              :       END DO
    1842   1131568758 :       DO i = 1, ng
    1843   1131524164 :          pw_grid%g_hat(1, i) = int_tmp(1, i)
    1844   1131524164 :          pw_grid%g_hat(2, i) = int_tmp(2, i)
    1845   1131568758 :          pw_grid%g_hat(3, i) = int_tmp(3, i)
    1846              :       END DO
    1847        44594 :       DEALLOCATE (int_tmp)
    1848              : 
    1849        44594 :       DEALLOCATE (idx)
    1850              : 
    1851              :       ! check if ordering is compatible to reference grid
    1852        44594 :       IF (PRESENT(ref_grid)) THEN
    1853        27156 :          ngr = SIZE(ref_grid%gsq)
    1854        27156 :          ngr = MIN(ng, ngr)
    1855        27156 :          IF (pw_grid%spherical) THEN
    1856            0 :             IF (.NOT. ALL(pw_grid%g_hat(1:3, 1:ngr) &
    1857              :                           == ref_grid%g_hat(1:3, 1:ngr))) THEN
    1858            0 :                CPABORT("G space sorting not compatible")
    1859              :             END IF
    1860              :          ELSE
    1861        81468 :             ALLOCATE (pw_grid%gidx(1:ngr))
    1862    257950330 :             pw_grid%gidx = 0
    1863              :             ! first try as many trivial associations as possible
    1864        27156 :             it = 0
    1865    137118780 :             DO ig = 1, ngr
    1866    548397222 :                IF (.NOT. ALL(pw_grid%g_hat(1:3, ig) &
    1867              :                              == ref_grid%g_hat(1:3, ig))) EXIT
    1868    137091624 :                pw_grid%gidx(ig) = ig
    1869    137118780 :                it = ig
    1870              :             END DO
    1871              :             ! now for the ones that could not be done
    1872        27156 :             IF (ng == ngr) THEN
    1873              :                ! for the case pw_grid <= ref_grid
    1874        27154 :                is = it
    1875    120843065 :                DO ig = it + 1, ngr
    1876    120815911 :                   gig = pw_grid%gsq(ig)
    1877    120815911 :                   gigr = MAX(1._dp, gig)
    1878    120815911 :                   g_found = .FALSE.
    1879    608284882 :                   DO ih = is + 1, SIZE(ref_grid%gsq)
    1880    608284882 :                      IF (ABS(gig - ref_grid%gsq(ih))/gigr > 1.e-12_dp) CYCLE
    1881              :                      g_found = .TRUE.
    1882    487468971 :                      EXIT
    1883              :                   END DO
    1884    120815911 :                   IF (.NOT. g_found) THEN
    1885            0 :                      WRITE (*, "(A,I10,F20.10)") "G-vector", ig, pw_grid%gsq(ig)
    1886            0 :                      CPABORT("G vector not found")
    1887              :                   END IF
    1888    120815911 :                   ip = ih - 1
    1889   8453566818 :                   DO ih = ip + 1, SIZE(ref_grid%gsq)
    1890   8453566818 :                      IF (ABS(gig - ref_grid%gsq(ih))/gigr > 1.e-12_dp) CYCLE
    1891   8453566818 :                      IF (pw_grid%g_hat(1, ig) /= ref_grid%g_hat(1, ih)) CYCLE
    1892    457451355 :                      IF (pw_grid%g_hat(2, ig) /= ref_grid%g_hat(2, ih)) CYCLE
    1893    149148648 :                      IF (pw_grid%g_hat(3, ig) /= ref_grid%g_hat(3, ih)) CYCLE
    1894    120815911 :                      pw_grid%gidx(ig) = ih
    1895   8453566818 :                      EXIT
    1896              :                   END DO
    1897    120815911 :                   IF (pw_grid%gidx(ig) == 0) THEN
    1898            0 :                      WRITE (*, "(A,2I10)") " G-Shell ", is + 1, ip + 1
    1899              :                      WRITE (*, "(A,I10,3I6,F20.10)") &
    1900            0 :                         " G-vector", ig, pw_grid%g_hat(1:3, ig), pw_grid%gsq(ig)
    1901            0 :                      DO ih = 1, SIZE(ref_grid%gsq)
    1902            0 :                         IF (pw_grid%g_hat(1, ig) /= ref_grid%g_hat(1, ih)) CYCLE
    1903            0 :                         IF (pw_grid%g_hat(2, ig) /= ref_grid%g_hat(2, ih)) CYCLE
    1904            0 :                         IF (pw_grid%g_hat(3, ig) /= ref_grid%g_hat(3, ih)) CYCLE
    1905              :                         WRITE (*, "(A,I10,3I6,F20.10)") &
    1906            0 :                            " G-vector", ih, ref_grid%g_hat(1:3, ih), ref_grid%gsq(ih)
    1907              :                      END DO
    1908            0 :                      CPABORT("G vector not found")
    1909              :                   END IF
    1910    120843065 :                   is = ip
    1911              :                END DO
    1912              :             ELSE
    1913              :                ! for the case pw_grid > ref_grid
    1914            2 :                is = it
    1915        15641 :                DO ig = it + 1, ngr
    1916        15639 :                   gig = ref_grid%gsq(ig)
    1917        15639 :                   gigr = MAX(1._dp, gig)
    1918        15639 :                   g_found = .FALSE.
    1919        44681 :                   DO ih = is + 1, ng
    1920        44681 :                      IF (ABS(pw_grid%gsq(ih) - gig)/gigr > 1.e-12_dp) CYCLE
    1921              :                      g_found = .TRUE.
    1922        29042 :                      EXIT
    1923              :                   END DO
    1924        15639 :                   IF (.NOT. g_found) THEN
    1925            0 :                      WRITE (*, "(A,I10,F20.10)") "G-vector", ig, ref_grid%gsq(ig)
    1926            0 :                      CPABORT("G vector not found")
    1927              :                   END IF
    1928        15639 :                   ip = ih - 1
    1929       534662 :                   DO ih = ip + 1, ng
    1930       534662 :                      IF (ABS(pw_grid%gsq(ih) - gig)/gigr > 1.e-12_dp) CYCLE
    1931       534662 :                      IF (pw_grid%g_hat(1, ih) /= ref_grid%g_hat(1, ig)) CYCLE
    1932        52928 :                      IF (pw_grid%g_hat(2, ih) /= ref_grid%g_hat(2, ig)) CYCLE
    1933        19626 :                      IF (pw_grid%g_hat(3, ih) /= ref_grid%g_hat(3, ig)) CYCLE
    1934        15639 :                      pw_grid%gidx(ig) = ih
    1935       534662 :                      EXIT
    1936              :                   END DO
    1937        15639 :                   IF (pw_grid%gidx(ig) == 0) THEN
    1938            0 :                      WRITE (*, "(A,2I10)") " G-Shell ", is + 1, ip + 1
    1939              :                      WRITE (*, "(A,I10,3I6,F20.10)") &
    1940            0 :                         " G-vector", ig, ref_grid%g_hat(1:3, ig), ref_grid%gsq(ig)
    1941            0 :                      DO ih = 1, ng
    1942            0 :                         IF (pw_grid%g_hat(1, ih) /= ref_grid%g_hat(1, ig)) CYCLE
    1943            0 :                         IF (pw_grid%g_hat(2, ih) /= ref_grid%g_hat(2, ig)) CYCLE
    1944            0 :                         IF (pw_grid%g_hat(3, ih) /= ref_grid%g_hat(3, ig)) CYCLE
    1945              :                         WRITE (*, "(A,I10,3I6,F20.10)") &
    1946            0 :                            " G-vector", ih, pw_grid%g_hat(1:3, ih), pw_grid%gsq(ih)
    1947              :                      END DO
    1948            0 :                      CPABORT("G vector not found")
    1949              :                   END IF
    1950        15641 :                   is = ip
    1951              :                END DO
    1952              :             END IF
    1953              :             ! test if all g-vectors are associated
    1954    257950330 :             IF (ANY(pw_grid%gidx == 0)) THEN
    1955            0 :                CPABORT("G space sorting not compatible")
    1956              :             END IF
    1957              :          END IF
    1958              :       END IF
    1959              : 
    1960              :       !check if G=0 is at first position
    1961        44594 :       IF (pw_grid%have_g0) THEN
    1962        24936 :          IF (pw_grid%gsq(1) /= 0.0_dp) THEN
    1963            0 :             CPABORT("G = 0 not in first position")
    1964              :          END IF
    1965              :       END IF
    1966              : 
    1967        44594 :       CALL timestop(handle)
    1968              : 
    1969        44594 :    END SUBROUTINE pw_grid_sort
    1970              : 
    1971              : ! **************************************************************************************************
    1972              : !> \brief ...
    1973              : !> \param gsq ...
    1974              : !> \param g_hat ...
    1975              : !> \param idx ...
    1976              : ! **************************************************************************************************
    1977        44594 :    SUBROUTINE sort_shells(gsq, g_hat, idx)
    1978              : 
    1979              :       ! Argument
    1980              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: gsq
    1981              :       INTEGER, DIMENSION(:, :), INTENT(IN)               :: g_hat
    1982              :       INTEGER, DIMENSION(:), INTENT(INOUT)               :: idx
    1983              : 
    1984              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'sort_shells'
    1985              :       REAL(KIND=dp), PARAMETER                           :: small = 5.e-16_dp
    1986              : 
    1987              :       INTEGER                                            :: handle, ig, ng, s1, s2
    1988              :       REAL(KIND=dp)                                      :: s_begin
    1989              : 
    1990        44594 :       CALL timeset(routineN, handle)
    1991              : 
    1992              : ! Juergs temporary hack to get the grids sorted for large (4000Ry) cutoffs.
    1993              : ! might need to call lapack for machine precision.
    1994              : 
    1995        44594 :       ng = SIZE(gsq)
    1996        44594 :       s_begin = -1.0_dp
    1997        44594 :       s1 = 0
    1998        44594 :       s2 = 0
    1999              :       ig = 1
    2000   1131568758 :       DO ig = 1, ng
    2001   1131568758 :          IF (ABS(gsq(ig) - s_begin) < small) THEN
    2002   1065983269 :             s2 = ig
    2003              :          ELSE
    2004     65540895 :             CALL redist(g_hat, idx, s1, s2)
    2005     65540895 :             s_begin = gsq(ig)
    2006     65540895 :             s1 = ig
    2007     65540895 :             s2 = ig
    2008              :          END IF
    2009              :       END DO
    2010        44594 :       CALL redist(g_hat, idx, s1, s2)
    2011              : 
    2012        44594 :       CALL timestop(handle)
    2013              : 
    2014        44594 :    END SUBROUTINE sort_shells
    2015              : 
    2016              : ! **************************************************************************************************
    2017              : !> \brief ...
    2018              : !> \param g_hat ...
    2019              : !> \param idx ...
    2020              : !> \param s1 ...
    2021              : !> \param s2 ...
    2022              : ! **************************************************************************************************
    2023     65585489 :    SUBROUTINE redist(g_hat, idx, s1, s2)
    2024              : 
    2025              :       ! Argument
    2026              :       INTEGER, DIMENSION(:, :), INTENT(IN)               :: g_hat
    2027              :       INTEGER, DIMENSION(:), INTENT(INOUT)               :: idx
    2028              :       INTEGER, INTENT(IN)                                :: s1, s2
    2029              : 
    2030              :       INTEGER                                            :: i, ii, n1, n2, n3, ns
    2031     65585489 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: indl
    2032     65585489 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: slen
    2033              : 
    2034     65585489 :       IF (s2 <= s1) RETURN
    2035     61991583 :       ns = s2 - s1 + 1
    2036    185974749 :       ALLOCATE (indl(ns))
    2037    185974749 :       ALLOCATE (slen(ns))
    2038              : 
    2039   1189966435 :       DO i = s1, s2
    2040   1127974852 :          ii = idx(i)
    2041   1127974852 :          n1 = g_hat(1, ii)
    2042   1127974852 :          n2 = g_hat(2, ii)
    2043   1127974852 :          n3 = g_hat(3, ii)
    2044              :          slen(i - s1 + 1) = 1000.0_dp*REAL(n1, dp) + &
    2045   1189966435 :                             REAL(n2, dp) + 0.001_dp*REAL(n3, dp)
    2046              :       END DO
    2047     61991583 :       CALL sort(slen, ns, indl)
    2048   1189966435 :       DO i = 1, ns
    2049   1127974852 :          ii = indl(i) + s1 - 1
    2050   1189966435 :          indl(i) = idx(ii)
    2051              :       END DO
    2052   1189966435 :       idx(s1:s2) = indl(1:ns)
    2053              : 
    2054     61991583 :       DEALLOCATE (indl)
    2055     61991583 :       DEALLOCATE (slen)
    2056              : 
    2057              :    END SUBROUTINE redist
    2058              : 
    2059              : ! **************************************************************************************************
    2060              : !> \brief Reorder yzq and yzp arrays for parallel FFT according to FFT mapping
    2061              : !> \param pw_grid ...
    2062              : !> \param yz ...
    2063              : !> \par History
    2064              : !>      none
    2065              : !> \author JGH (17-Jan-2001)
    2066              : ! **************************************************************************************************
    2067        44594 :    SUBROUTINE pw_grid_remap(pw_grid, yz)
    2068              : 
    2069              :       ! Argument
    2070              :       TYPE(pw_grid_type), INTENT(INOUT)                  :: pw_grid
    2071              :       INTEGER, DIMENSION(:, :), INTENT(OUT)              :: yz
    2072              : 
    2073              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_grid_remap'
    2074              : 
    2075              :       INTEGER                                            :: gpt, handle, i, ip, is, j, m, n
    2076              : 
    2077        44594 :       IF (pw_grid%para%mode == PW_MODE_LOCAL) RETURN
    2078              : 
    2079        39291 :       CALL timeset(routineN, handle)
    2080              : 
    2081              :       ASSOCIATE (ny => pw_grid%npts(2), nz => pw_grid%npts(3), posm => pw_grid%mapm%pos, posn => pw_grid%mapn%pos, &
    2082              :                  negm => pw_grid%mapm%neg, negn => pw_grid%mapn%neg)
    2083              : 
    2084     42030569 :          yz = 0
    2085    119629575 :          pw_grid%para%yzp = 0
    2086     42030569 :          pw_grid%para%yzq = 0
    2087              : 
    2088   1082905344 :          DO gpt = 1, SIZE(pw_grid%gsq)
    2089   1082866053 :             m = posm(pw_grid%g_hat(2, gpt)) + 1
    2090   1082866053 :             n = posn(pw_grid%g_hat(3, gpt)) + 1
    2091   1082905344 :             yz(m, n) = yz(m, n) + 1
    2092              :          END DO
    2093        39291 :          IF (pw_grid%grid_span == HALFSPACE) THEN
    2094     18717074 :             DO gpt = 1, SIZE(pw_grid%gsq)
    2095     18714538 :                m = negm(pw_grid%g_hat(2, gpt)) + 1
    2096     18714538 :                n = negn(pw_grid%g_hat(3, gpt)) + 1
    2097     18717074 :                yz(m, n) = yz(m, n) + 1
    2098              :             END DO
    2099              :          END IF
    2100              : 
    2101        39291 :          ip = pw_grid%para%group%mepos
    2102        39291 :          is = 0
    2103      1098737 :          DO i = 1, nz
    2104     42030569 :             DO j = 1, ny
    2105     41991278 :                IF (yz(j, i) > 0) THEN
    2106     19898585 :                   is = is + 1
    2107     19898585 :                   pw_grid%para%yzp(1, is, ip) = j
    2108     19898585 :                   pw_grid%para%yzp(2, is, ip) = i
    2109     19898585 :                   pw_grid%para%yzq(j, i) = is
    2110              :                END IF
    2111              :             END DO
    2112              :          END DO
    2113              :       END ASSOCIATE
    2114              : 
    2115        39291 :       CPASSERT(is == pw_grid%para%nyzray(ip))
    2116        39291 :       CALL pw_grid%para%group%sum(pw_grid%para%yzp)
    2117              : 
    2118        39291 :       CALL timestop(handle)
    2119              : 
    2120        39291 :    END SUBROUTINE pw_grid_remap
    2121              : 
    2122              : ! **************************************************************************************************
    2123              : !> \brief Recalculate the g-vectors after a change of the box
    2124              : !> \param cell_hmat ...
    2125              : !> \param pw_grid ...
    2126              : !> \par History
    2127              : !>      JGH (20-12-2000) : get local grid size from definition of g.
    2128              : !>                         Assume that gsq is allocated.
    2129              : !>                         Local routine, no information on distribution of
    2130              : !>                         PW required.
    2131              : !>      JGH (8-Mar-2001) : also update information on volume and grid spaceing
    2132              : !> \author apsi
    2133              : !>      Christopher Mundy
    2134              : ! **************************************************************************************************
    2135        13880 :    SUBROUTINE pw_grid_change(cell_hmat, pw_grid)
    2136              :       ! Argument
    2137              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN)         :: cell_hmat
    2138              :       TYPE(pw_grid_type), INTENT(INOUT)                  :: pw_grid
    2139              : 
    2140              :       INTEGER                                            :: gpt
    2141              :       REAL(KIND=dp)                                      :: cell_deth, l, m, n
    2142              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: cell_h_inv
    2143        13880 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: g
    2144              : 
    2145        13880 :       cell_deth = ABS(det_3x3(cell_hmat))
    2146        13880 :       IF (cell_deth < 1.0E-10_dp) THEN
    2147              :          CALL cp_abort(__LOCATION__, &
    2148              :                        "An invalid set of cell vectors was specified. "// &
    2149            0 :                        "The determinant det(h) is too small")
    2150              :       END IF
    2151        13880 :       cell_h_inv = inv_3x3(cell_hmat)
    2152              : 
    2153        13880 :       g => pw_grid%g
    2154              : 
    2155        13880 :       CALL cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
    2156              : 
    2157    103426088 :       DO gpt = 1, SIZE(g, 2)
    2158              : 
    2159    103412208 :          l = twopi*REAL(pw_grid%g_hat(1, gpt), KIND=dp)
    2160    103412208 :          m = twopi*REAL(pw_grid%g_hat(2, gpt), KIND=dp)
    2161    103412208 :          n = twopi*REAL(pw_grid%g_hat(3, gpt), KIND=dp)
    2162              : 
    2163    103412208 :          g(1, gpt) = l*cell_h_inv(1, 1) + m*cell_h_inv(2, 1) + n*cell_h_inv(3, 1)
    2164    103412208 :          g(2, gpt) = l*cell_h_inv(1, 2) + m*cell_h_inv(2, 2) + n*cell_h_inv(3, 2)
    2165    103412208 :          g(3, gpt) = l*cell_h_inv(1, 3) + m*cell_h_inv(2, 3) + n*cell_h_inv(3, 3)
    2166              : 
    2167              :          pw_grid%gsq(gpt) = g(1, gpt)*g(1, gpt) &
    2168              :                             + g(2, gpt)*g(2, gpt) &
    2169    103426088 :                             + g(3, gpt)*g(3, gpt)
    2170              : 
    2171              :       END DO
    2172              : 
    2173        13880 :    END SUBROUTINE pw_grid_change
    2174              : 
    2175              : ! **************************************************************************************************
    2176              : !> \brief retains the given pw grid
    2177              : !> \param pw_grid the pw grid to retain
    2178              : !> \par History
    2179              : !>      04.2003 created [fawzi]
    2180              : !> \author fawzi
    2181              : !> \note
    2182              : !>      see doc/ReferenceCounting.html
    2183              : ! **************************************************************************************************
    2184      9457361 :    SUBROUTINE pw_grid_retain(pw_grid)
    2185              :       TYPE(pw_grid_type), INTENT(INOUT)                  :: pw_grid
    2186              : 
    2187      9457361 :       CPASSERT(pw_grid%ref_count > 0)
    2188      9457361 :       pw_grid%ref_count = pw_grid%ref_count + 1
    2189      9457361 :    END SUBROUTINE pw_grid_retain
    2190              : 
    2191              : ! **************************************************************************************************
    2192              : !> \brief releases the given pw grid
    2193              : !> \param pw_grid the pw grid to release
    2194              : !> \par History
    2195              : !>      04.2003 created [fawzi]
    2196              : !> \author fawzi
    2197              : !> \note
    2198              : !>      see doc/ReferenceCounting.html
    2199              : ! **************************************************************************************************
    2200     19453922 :    SUBROUTINE pw_grid_release(pw_grid)
    2201              : 
    2202              :       TYPE(pw_grid_type), POINTER              :: pw_grid
    2203              : 
    2204              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    2205              :       INTEGER, POINTER :: dummy_ptr
    2206              :       INTEGER          :: stat
    2207              : #endif
    2208              : 
    2209     19453922 :       IF (ASSOCIATED(pw_grid)) THEN
    2210      9595709 :          CPASSERT(pw_grid%ref_count > 0)
    2211      9595709 :          pw_grid%ref_count = pw_grid%ref_count - 1
    2212      9595709 :          IF (pw_grid%ref_count == 0) THEN
    2213       138363 :             IF (ASSOCIATED(pw_grid%gidx)) THEN
    2214        27152 :                DEALLOCATE (pw_grid%gidx)
    2215              :             END IF
    2216       138363 :             IF (ASSOCIATED(pw_grid%g)) THEN
    2217        44589 :                DEALLOCATE (pw_grid%g)
    2218              :             END IF
    2219       138363 :             IF (ASSOCIATED(pw_grid%gsq)) THEN
    2220        44589 :                DEALLOCATE (pw_grid%gsq)
    2221              :             END IF
    2222       138363 :             IF (ALLOCATED(pw_grid%g_hat)) THEN
    2223        44589 :                DEALLOCATE (pw_grid%g_hat)
    2224              :             END IF
    2225       138363 :             IF (ASSOCIATED(pw_grid%g_hatmap)) THEN
    2226              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
    2227              :                dummy_ptr => pw_grid%g_hatmap(1, 1)
    2228              :                stat = offload_free_pinned_mem(c_loc(dummy_ptr))
    2229              :                CPASSERT(stat == 0)
    2230              : #else
    2231        44589 :                DEALLOCATE (pw_grid%g_hatmap)
    2232              : #endif
    2233              :             END IF
    2234       138363 :             IF (ASSOCIATED(pw_grid%grays)) THEN
    2235        39286 :                DEALLOCATE (pw_grid%grays)
    2236              :             END IF
    2237       138363 :             IF (ALLOCATED(pw_grid%mapl%pos)) THEN
    2238        44589 :                DEALLOCATE (pw_grid%mapl%pos)
    2239              :             END IF
    2240       138363 :             IF (ALLOCATED(pw_grid%mapm%pos)) THEN
    2241        44589 :                DEALLOCATE (pw_grid%mapm%pos)
    2242              :             END IF
    2243       138363 :             IF (ALLOCATED(pw_grid%mapn%pos)) THEN
    2244        44589 :                DEALLOCATE (pw_grid%mapn%pos)
    2245              :             END IF
    2246       138363 :             IF (ALLOCATED(pw_grid%mapl%neg)) THEN
    2247        44589 :                DEALLOCATE (pw_grid%mapl%neg)
    2248              :             END IF
    2249       138363 :             IF (ALLOCATED(pw_grid%mapm%neg)) THEN
    2250        44589 :                DEALLOCATE (pw_grid%mapm%neg)
    2251              :             END IF
    2252       138363 :             IF (ALLOCATED(pw_grid%mapn%neg)) THEN
    2253        44589 :                DEALLOCATE (pw_grid%mapn%neg)
    2254              :             END IF
    2255       138363 :             IF (ALLOCATED(pw_grid%para%bo)) THEN
    2256        44589 :                DEALLOCATE (pw_grid%para%bo)
    2257              :             END IF
    2258       138363 :             IF (pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
    2259        39294 :                IF (ALLOCATED(pw_grid%para%yzp)) THEN
    2260        39286 :                   DEALLOCATE (pw_grid%para%yzp)
    2261              :                END IF
    2262        39294 :                IF (ALLOCATED(pw_grid%para%yzq)) THEN
    2263        39286 :                   DEALLOCATE (pw_grid%para%yzq)
    2264              :                END IF
    2265        39294 :                IF (ALLOCATED(pw_grid%para%nyzray)) THEN
    2266        39286 :                   DEALLOCATE (pw_grid%para%nyzray)
    2267              :                END IF
    2268              :             END IF
    2269              :             ! also release groups
    2270       138363 :             CALL pw_grid%para%group%free()
    2271       138363 :             IF (ALLOCATED(pw_grid%para%pos_of_x)) THEN
    2272        45601 :                DEALLOCATE (pw_grid%para%pos_of_x)
    2273              :             END IF
    2274              : 
    2275       138363 :             IF (ASSOCIATED(pw_grid)) THEN
    2276       138363 :                DEALLOCATE (pw_grid)
    2277              :             END IF
    2278              :          END IF
    2279              :       END IF
    2280     19453922 :       NULLIFY (pw_grid)
    2281     19453922 :    END SUBROUTINE pw_grid_release
    2282              : 
    2283              : END MODULE pw_grids
        

Generated by: LCOV version 2.0-1