(git:e7e05ae)
qs_fb_distribution_methods.F
Go to the documentation of this file.
1 !--------------------------------------------------------------------------------------------------!
2 ! CP2K: A general program to perform molecular dynamics simulations !
3 ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 ! !
5 ! SPDX-License-Identifier: GPL-2.0-or-later !
6 !--------------------------------------------------------------------------------------------------!
7 
9 
10  USE cell_types, ONLY: cell_type
12  cp_logger_type
15  USE dbcsr_api, ONLY: dbcsr_distribution_get,&
16  dbcsr_distribution_type,&
17  dbcsr_get_info,&
18  dbcsr_nblkcols_total,&
19  dbcsr_p_type,&
20  dbcsr_type
21  USE input_section_types, ONLY: section_vals_type
22  USE kinds, ONLY: dp
23  USE message_passing, ONLY: mp_para_env_type
24  USE particle_types, ONLY: particle_type
25  USE qs_environment_types, ONLY: get_qs_env,&
26  qs_environment_type
27  USE qs_fb_atomic_halo_types, ONLY: &
31  USE qs_fb_env_types, ONLY: fb_env_get,&
32  fb_env_obj,&
34  USE qs_kind_types, ONLY: qs_kind_type
35  USE util, ONLY: sort
36 #include "./base/base_uses.f90"
37 
38  IMPLICIT NONE
39 
40  PRIVATE
41 
42  PUBLIC :: fb_distribution_build
43 
44  CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_fb_distribution_methods'
45 
46 ! **************************************************************************************************
47 !> \brief derived type containing cost data used for process distribution
48 !> \param id : global atomic index
49 !> \param cost : computational cost for the atomic matrix associated
50 !> to this atom
51 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
52 ! **************************************************************************************************
53  TYPE fb_distribution_element
54  INTEGER :: id
55  REAL(KIND=dp) :: cost
56  END TYPE fb_distribution_element
57 
58 ! **************************************************************************************************
59 !> \brief derived type containing the list of atoms currently allocated to a
60 !> processor
61 !> \param list : list of atoms and their associated costs
62 !> \param cost : total cost of the list
63 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
64 ! **************************************************************************************************
65  TYPE fb_distribution_list
66  TYPE(fb_distribution_element), DIMENSION(:), POINTER :: list => null()
67  INTEGER :: nelements
68  REAL(KIND=dp) :: cost
69  END TYPE fb_distribution_list
70 
71 ! **************************************************************************************************
72 !> \brief In filter matrix algorithm, each atomic matrix contributes to a
73 !> column in the filter matrix, which is stored in DBCSR format.
74 !> When distributing the atoms (and hence the atomic matrics) to the
75 !> processors, we want the processors to have atoms that would be
76 !> correspond to the block columns in the DBCSR format local to them.
77 !> This derived type stores this information. For each atom, it
78 !> corresponds to a DBCSR block column, and the list of processors
79 !> in the 2D processor grid responsible for this column will be the
80 !> preferred processors for this atom.
81 !> \param list : list of preferred processors for an atom
82 !> note that here the processors are indexed from
83 !> 1, i.e. = MPI_RANK+1
84 !> \param nprocs : number of processors in the list
85 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
86 ! **************************************************************************************************
87  TYPE fb_preferred_procs_list
88  INTEGER, DIMENSION(:), POINTER :: list => null()
89  INTEGER :: nprocs
90  END TYPE fb_preferred_procs_list
91 
92 ! Parameters related to automatic resizing of the hash_table:
93 ! Resize by EXPAND_FACTOR if total no. slots / no. of filled slots < ENLARGE_RATIO
94  INTEGER, PARAMETER, PRIVATE :: ENLARGE_RATIO = 1
95  INTEGER, PARAMETER, PRIVATE :: REDUCE_RATIO = 3
96  INTEGER, PARAMETER, PRIVATE :: EXPAND_FACTOR = 2
97  INTEGER, PARAMETER, PRIVATE :: SHRINK_FACTOR = 2
98 
99  INTERFACE fb_distribution_remove
100  MODULE PROCEDURE fb_distribution_remove_ind, &
101  fb_distribution_remove_el
102  END INTERFACE fb_distribution_remove
103 
104  INTERFACE fb_distribution_move
105  MODULE PROCEDURE fb_distribution_move_ind, &
106  fb_distribution_move_el
107  END INTERFACE fb_distribution_move
108 
109 CONTAINS
110 
111 ! **************************************************************************************************
112 !> \brief Build local atoms associated to filter matrix algorithm for each
113 !> MPI process, trying to balance the load for calculating the
114 !> filter matrix
115 !> \param fb_env : the filter matrix environment
116 !> \param qs_env : quickstep environment
117 !> \param scf_section : SCF input section
118 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
119 ! **************************************************************************************************
120  SUBROUTINE fb_distribution_build(fb_env, qs_env, scf_section)
121  TYPE(fb_env_obj), INTENT(INOUT) :: fb_env
122  TYPE(qs_environment_type), POINTER :: qs_env
123  TYPE(section_vals_type), POINTER :: scf_section
124 
125  CHARACTER(len=*), PARAMETER :: routinen = 'fb_distribution_build'
126 
127  INTEGER :: handle, i_common_set, iatom, ii, ipe, lb, lowest_cost_ind, my_pe, n_common_sets, &
128  natoms, nhalo_atoms, nkinds, nprocs, owner_id_in_halo, pref_pe, ub
129  INTEGER, ALLOCATABLE, DIMENSION(:) :: common_set_ids, local_atoms_all, &
130  local_atoms_sizes, local_atoms_starts, &
131  pe, pos_in_preferred_list
132  INTEGER, DIMENSION(:), POINTER :: halo_atoms, local_atoms
133  LOGICAL :: acceptable_move, move_happened
134  REAL(kind=dp) :: average_cost
135  REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: cost_per_atom, cost_per_proc
136  REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: pair_radii
137  REAL(kind=dp), DIMENSION(:), POINTER :: rcut
138  TYPE(cell_type), POINTER :: cell
139  TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: mat_ks
140  TYPE(fb_atomic_halo_obj) :: atomic_halo
141  TYPE(fb_distribution_element) :: element
142  TYPE(fb_distribution_list), ALLOCATABLE, &
143  DIMENSION(:) :: dist
144  TYPE(fb_preferred_procs_list), ALLOCATABLE, &
145  DIMENSION(:) :: preferred_procs_set
146  TYPE(mp_para_env_type), POINTER :: para_env
147  TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
148  TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
149 
150  CALL timeset(routinen, handle)
151 
152  NULLIFY (mat_ks, rcut, cell, para_env, particle_set, qs_kind_set, &
153  halo_atoms, local_atoms)
154  CALL fb_atomic_halo_nullify(atomic_halo)
155 
156  ! obtain relevant data from fb_env, qs_env
157  CALL fb_env_get(fb_env=fb_env, &
158  rcut=rcut)
159  CALL get_qs_env(qs_env=qs_env, &
160  natom=natoms, &
161  particle_set=particle_set, &
162  qs_kind_set=qs_kind_set, &
163  nkind=nkinds, &
164  cell=cell, &
165  para_env=para_env, &
166  matrix_ks=mat_ks)
167  nprocs = para_env%num_pe
168  my_pe = para_env%mepos + 1 ! counting from 1
169 
170  ! for each global atom, build atomic halo and get the associated cost
171  ALLOCATE (pair_radii(nkinds, nkinds))
172  CALL fb_build_pair_radii(rcut, nkinds, pair_radii)
173  CALL fb_atomic_halo_create(atomic_halo)
174  ALLOCATE (cost_per_atom(natoms))
175  DO iatom = 1, natoms
176  CALL fb_atomic_halo_init(atomic_halo)
177  CALL fb_atomic_halo_build_halo_atoms(iatom, &
178  particle_set, &
179  cell, &
180  pair_radii, &
181  halo_atoms, &
182  nhalo_atoms, &
183  owner_id_in_halo)
184  CALL fb_atomic_halo_set(atomic_halo=atomic_halo, &
185  owner_atom=iatom, &
186  natoms=nhalo_atoms, &
187  halo_atoms=halo_atoms)
188  NULLIFY (halo_atoms)
189  cost_per_atom(iatom) = fb_atomic_halo_cost(atomic_halo, particle_set, qs_kind_set)
190  END DO
191  DEALLOCATE (pair_radii)
192  CALL fb_atomic_halo_release(atomic_halo)
193 
194  ! build the preferred_procs_set according to DBCSR mat H
195  ALLOCATE (preferred_procs_set(natoms))
196  ALLOCATE (common_set_ids(natoms))
197  CALL fb_build_preferred_procs(mat_ks(1)%matrix, &
198  natoms, &
199  preferred_procs_set, &
200  common_set_ids, &
201  n_common_sets)
202 
203  ! for each atomic halo, construct distribution_element, and assign
204  ! the element to a processors using preferred_procs_set in a
205  ! round-robin manner
206  ALLOCATE (dist(nprocs))
207  DO ipe = 1, nprocs
208  CALL fb_distribution_init(dist=dist(ipe))
209  END DO
210  ALLOCATE (pos_in_preferred_list(n_common_sets))
211  pos_in_preferred_list(:) = 0
212  DO iatom = 1, natoms
213  element%id = iatom
214  element%cost = cost_per_atom(iatom)
215  i_common_set = common_set_ids(iatom)
216  pos_in_preferred_list(i_common_set) = &
217  mod(pos_in_preferred_list(i_common_set), &
218  preferred_procs_set(iatom)%nprocs) + 1
219  ipe = preferred_procs_set(iatom)%list(pos_in_preferred_list(i_common_set))
220  CALL fb_distribution_add(dist(ipe), element)
221  END DO
222 
223  DEALLOCATE (pos_in_preferred_list)
224  DEALLOCATE (common_set_ids)
225  DEALLOCATE (cost_per_atom)
226 
227  ! sort processors according to the overall cost of their assigned
228  ! corresponding distribution
229  ALLOCATE (cost_per_proc(nprocs))
230  DO ipe = 1, nprocs
231  cost_per_proc(ipe) = dist(ipe)%cost
232  END DO
233  ALLOCATE (pe(nprocs))
234  CALL sort(cost_per_proc, nprocs, pe)
235  ! now that cost_per_proc is sorted, ipe's no longer give mpi
236  ! ranks, the correct one to use should be pe(ipe)
237 
238  ! work out the ideal average cost per proc if work load is evenly
239  ! distributed
240  average_cost = sum(cost_per_proc)/real(nprocs, dp)
241 
242  DEALLOCATE (cost_per_proc)
243 
244  ! loop over the processors, starting with the highest cost, move
245  ! atoms one by one:
246  ! 1. FIRST to the next processor in the preferred list that has
247  ! cost below average. IF no such proc is found, THEN
248  ! 2. to the next procesor in the overall list that has cost
249  ! below average.
250  ! repeat until the cost on this processor is less than or equal
251  ! to the average cost
252  lowest_cost_ind = 1
253  DO ipe = nprocs, 1, -1
254  redistribute: DO WHILE (dist(pe(ipe))%cost .GT. average_cost)
255  iatom = dist(pe(ipe))%list(lowest_cost_ind)%id
256  move_happened = .false.
257  ! first try to move to a preferred process
258  preferred: DO ii = 1, preferred_procs_set(iatom)%nprocs
259  pref_pe = preferred_procs_set(iatom)%list(ii)
260  acceptable_move = &
261  fb_distribution_acceptable_move(dist(pe(ipe)), &
262  dist(pe(ipe))%list(lowest_cost_ind), &
263  dist(pref_pe), &
264  average_cost)
265  IF ((pref_pe .NE. pe(ipe)) .AND. acceptable_move) THEN
266  CALL fb_distribution_move(dist(pe(ipe)), &
267  lowest_cost_ind, &
268  dist(pref_pe))
269  move_happened = .true.
270  EXIT preferred
271  END IF
272  END DO preferred
273  ! if no preferred process is available, move to a proc in
274  ! the sorted list that has cost less than average. remember
275  ! that some of the proc may have already taken redistributed
276  ! atoms, and thus may become unavailable (full)
277  IF (.NOT. move_happened) THEN
278  ! searching from the proc with the least initial cost
279  next_in_line: DO ii = 1, nprocs
280  acceptable_move = &
281  fb_distribution_acceptable_move(dist(pe(ipe)), &
282  dist(pe(ipe))%list(lowest_cost_ind), &
283  dist(pe(ii)), &
284  average_cost)
285  IF ((pe(ii) .NE. pe(ipe)) .AND. acceptable_move) THEN
286  CALL fb_distribution_move(dist(pe(ipe)), &
287  lowest_cost_ind, &
288  dist(pe(ii)))
289  move_happened = .true.
290  EXIT next_in_line
291  END IF
292  END DO next_in_line
293  END IF
294  ! if the atom cannot be moved, then this means it is too
295  ! costly for all other processes to accept. When this
296  ! happens we must stop the redistribution process for this
297  ! processor---as all other of its atoms will be even more
298  ! costly
299  IF (.NOT. move_happened) THEN
300  EXIT redistribute
301  END IF
302  END DO redistribute ! while
303  END DO ! ipe
304 
305  DEALLOCATE (pe)
306  DO ii = 1, SIZE(preferred_procs_set)
307  CALL fb_preferred_procs_list_release(preferred_procs_set(ii))
308  END DO
309  DEALLOCATE (preferred_procs_set)
310 
311  ! generate local atoms from dist
312  ALLOCATE (local_atoms_all(natoms))
313  ALLOCATE (local_atoms_starts(nprocs))
314  ALLOCATE (local_atoms_sizes(nprocs))
315  CALL fb_distribution_to_local_atoms(dist, &
316  local_atoms_all, &
317  local_atoms_starts, &
318  local_atoms_sizes)
319  ALLOCATE (local_atoms(local_atoms_sizes(my_pe)))
320  lb = local_atoms_starts(my_pe)
321  ub = local_atoms_starts(my_pe) + local_atoms_sizes(my_pe) - 1
322  local_atoms(1:local_atoms_sizes(my_pe)) = local_atoms_all(lb:ub)
323  CALL fb_env_set(fb_env=fb_env, &
324  local_atoms=local_atoms, &
325  nlocal_atoms=local_atoms_sizes(my_pe))
326 
327  ! write out info
328  CALL fb_distribution_write_info(dist, scf_section)
329 
330  DEALLOCATE (local_atoms_all)
331  DEALLOCATE (local_atoms_starts)
332  DEALLOCATE (local_atoms_sizes)
333  DO ipe = 1, SIZE(dist)
334  CALL fb_distribution_release(dist(ipe))
335  END DO
336  DEALLOCATE (dist)
337 
338  CALL timestop(handle)
339 
340  END SUBROUTINE fb_distribution_build
341 
342 ! **************************************************************************************************
343 !> \brief Checks if moving an element from one distribution to another is
344 !> allowed in mind of load balancing.
345 !> \param dist_from : the source distribution
346 !> \param element : the element in source distribution considered for the
347 !> move
348 !> \param dist_to : the destination distribution
349 !> \param threshold ...
350 !> \return : TRUE or FALSE
351 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
352 ! **************************************************************************************************
353  PURE FUNCTION fb_distribution_acceptable_move(dist_from, &
354  element, &
355  dist_to, &
356  threshold) &
357  result(acceptable)
358  TYPE(fb_distribution_list), INTENT(IN) :: dist_from
359  TYPE(fb_distribution_element), INTENT(IN) :: element
360  TYPE(fb_distribution_list), INTENT(IN) :: dist_to
361  REAL(kind=dp), INTENT(IN) :: threshold
362  LOGICAL :: acceptable
363 
364  acceptable = (dist_to%cost + element%cost .LT. dist_from%cost) .AND. &
365  (dist_to%cost .LT. threshold)
366  END FUNCTION fb_distribution_acceptable_move
367 
368 ! **************************************************************************************************
369 !> \brief Write out information on the load distribution on processors
370 !> \param dist_set : set of distributions for the processors
371 !> \param scf_section : SCF input section
372 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
373 ! **************************************************************************************************
374  SUBROUTINE fb_distribution_write_info(dist_set, scf_section)
375  TYPE(fb_distribution_list), DIMENSION(:), &
376  INTENT(IN) :: dist_set
377  TYPE(section_vals_type), POINTER :: scf_section
378 
379  INTEGER :: ii, max_natoms, min_natoms, natoms, &
380  nprocs, unit_nr
381  REAL(kind=dp) :: ave_cost, ave_natoms, max_cost, &
382  min_cost, total_cost
383  TYPE(cp_logger_type), POINTER :: logger
384 
385  nprocs = SIZE(dist_set)
386  natoms = 0
387  total_cost = 0.0_dp
388  DO ii = 1, nprocs
389  natoms = natoms + dist_set(ii)%nelements
390  total_cost = total_cost + dist_set(ii)%cost
391  END DO
392  ave_natoms = real(natoms, dp)/real(nprocs, dp)
393  ave_cost = total_cost/real(nprocs, dp)
394  max_natoms = 0
395  max_cost = 0._dp
396  DO ii = 1, nprocs
397  max_natoms = max(max_natoms, dist_set(ii)%nelements)
398  max_cost = max(max_cost, dist_set(ii)%cost)
399  END DO
400  min_natoms = natoms
401  min_cost = total_cost
402  DO ii = 1, nprocs
403  min_natoms = min(min_natoms, dist_set(ii)%nelements)
404  min_cost = min(min_cost, dist_set(ii)%cost)
405  END DO
406 
407  logger => cp_get_default_logger()
408  unit_nr = cp_print_key_unit_nr(logger, scf_section, &
409  "PRINT%FILTER_MATRIX", &
410  extension="")
411 
412  IF (unit_nr > 0) THEN
413  WRITE (unit=unit_nr, fmt="(/,A,I6,A)") &
414  " FILTER_MAT_DIAG| Load distribution across ", nprocs, " processors:"
415  WRITE (unit=unit_nr, &
416  fmt="(A,T40,A,T55,A,T70,A,T85,A)") &
417  " FILTER_MAT_DIAG| ", "Total", "Average", "Max", "Min"
418  WRITE (unit=unit_nr, &
419  fmt="(A,T40,I12,T55,F12.1,T70,I12,T85,I10)") &
420  " FILTER_MAT_DIAG| Atomic Matrices", &
421  natoms, ave_natoms, max_natoms, min_natoms
422  WRITE (unit=unit_nr, &
423  fmt="(A,T40,D12.7,T55,D12.7,T70,D12.7,T85,D12.7)") &
424  " FILTER_MAT_DIAG| Cost*", &
425  total_cost, ave_cost, max_cost, min_cost
426  WRITE (unit=unit_nr, fmt="(A)") &
427  " FILTER_MAT_DIAG| (* cost is calculated as sum of cube of atomic matrix sizes)"
428  END IF
429  CALL cp_print_key_finished_output(unit_nr, logger, scf_section, &
430  "PRINT%FILTER_MATRIX")
431  END SUBROUTINE fb_distribution_write_info
432 
433 ! **************************************************************************************************
434 !> \brief Build the preferred list of processors for atoms
435 !> \param dbcsr_mat : the reference DBCSR matrix, from which the local block
436 !> cols and the processor maps are obtained
437 !> \param natoms : total number of atoms globally
438 !> \param preferred_procs_set : set of preferred procs list for each atom
439 !> \param common_set_ids : atoms (block cols) local to the same processor grid
440 !> col will have the same preferred list. This list
441 !> maps each atom to their corresponding group
442 !> \param n_common_sets : number of unique preferred lists (groups)
443 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
444 ! **************************************************************************************************
445  SUBROUTINE fb_build_preferred_procs(dbcsr_mat, &
446  natoms, &
447  preferred_procs_set, &
448  common_set_ids, &
449  n_common_sets)
450  TYPE(dbcsr_type), POINTER :: dbcsr_mat
451  INTEGER, INTENT(IN) :: natoms
452  TYPE(fb_preferred_procs_list), DIMENSION(:), &
453  INTENT(INOUT) :: preferred_procs_set
454  INTEGER, DIMENSION(:), INTENT(OUT) :: common_set_ids
455  INTEGER, INTENT(OUT) :: n_common_sets
456 
457  INTEGER :: icol, nprows, pcol, prow
458  INTEGER, DIMENSION(:), POINTER :: col_dist
459  INTEGER, DIMENSION(:, :), POINTER :: pgrid
460  LOGICAL :: check_ok
461  TYPE(dbcsr_distribution_type) :: dbcsr_dist
462 
463  check_ok = natoms .LE. dbcsr_nblkcols_total(dbcsr_mat)
464  cpassert(check_ok)
465  check_ok = SIZE(preferred_procs_set) .GE. natoms
466  cpassert(check_ok)
467  check_ok = SIZE(common_set_ids) .GE. natoms
468  cpassert(check_ok)
469 
470  CALL dbcsr_get_info(dbcsr_mat, distribution=dbcsr_dist, proc_col_dist=col_dist)
471  CALL dbcsr_distribution_get(dbcsr_dist, pgrid=pgrid, nprows=nprows, npcols=n_common_sets)
472 
473  DO icol = 1, natoms
474  IF (ASSOCIATED(preferred_procs_set(icol)%list)) THEN
475  DEALLOCATE (preferred_procs_set(icol)%list)
476  END IF
477  ALLOCATE (preferred_procs_set(icol)%list(nprows))
478  pcol = col_dist(icol)
479  ! dbcsr prow and pcol counts from 0
480  DO prow = 0, nprows - 1
481  ! here, we count processes from 1, so +1 from mpirank
482  preferred_procs_set(icol)%list(prow + 1) = pgrid(prow, pcol) + 1
483  END DO
484  preferred_procs_set(icol)%nprocs = nprows
485  END DO
486 
487  common_set_ids(:) = 0
488  common_set_ids(1:natoms) = col_dist(1:natoms) + 1
489 
490  END SUBROUTINE fb_build_preferred_procs
491 
492 ! **************************************************************************************************
493 !> \brief Release a preferred_procs_list
494 !> \param preferred_procs_list : the preferred procs list in question
495 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
496 ! **************************************************************************************************
497  SUBROUTINE fb_preferred_procs_list_release(preferred_procs_list)
498  TYPE(fb_preferred_procs_list), INTENT(INOUT) :: preferred_procs_list
499 
500  IF (ASSOCIATED(preferred_procs_list%list)) THEN
501  DEALLOCATE (preferred_procs_list%list)
502  END IF
503  END SUBROUTINE fb_preferred_procs_list_release
504 
505 ! **************************************************************************************************
506 !> \brief Convert distribution data to 1D array containing information of
507 !> which atoms are distributed to which processor
508 !> \param dist_set : set of distributions for the processors
509 !> \param local_atoms : continuous array of atoms arranged in order
510 !> corresponding their allocated processors
511 !> \param local_atoms_starts : starting position in local_atoms array for
512 !> each processor
513 !> \param local_atoms_sizes : number of atoms local to each processor
514 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
515 ! **************************************************************************************************
516  SUBROUTINE fb_distribution_to_local_atoms(dist_set, &
517  local_atoms, &
518  local_atoms_starts, &
519  local_atoms_sizes)
520  TYPE(fb_distribution_list), DIMENSION(:), &
521  INTENT(IN) :: dist_set
522  INTEGER, DIMENSION(:), INTENT(OUT) :: local_atoms, local_atoms_starts, &
523  local_atoms_sizes
524 
525  INTEGER :: iatom, ipe, n_procs, pos
526  LOGICAL :: check_ok
527 
528  n_procs = SIZE(dist_set)
529 
530  check_ok = SIZE(local_atoms_starts) .GE. n_procs
531  cpassert(check_ok)
532  check_ok = SIZE(local_atoms_sizes) .GE. n_procs
533  cpassert(check_ok)
534 
535  local_atoms(:) = 0
536  local_atoms_starts(:) = 0
537  local_atoms_sizes(:) = 0
538 
539  pos = 1
540  DO ipe = 1, n_procs
541  local_atoms_starts(ipe) = pos
542  DO iatom = 1, dist_set(ipe)%nelements
543  local_atoms(pos) = dist_set(ipe)%list(iatom)%id
544  pos = pos + 1
545  local_atoms_sizes(ipe) = local_atoms_sizes(ipe) + 1
546  END DO
547  END DO
548  END SUBROUTINE fb_distribution_to_local_atoms
549 
550 ! **************************************************************************************************
551 !> \brief Initialise a distribution
552 !> \param dist : the distribution in question
553 !> \param nmax : [OPTIONAL] size of the list array to be allocated
554 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
555 ! **************************************************************************************************
556  SUBROUTINE fb_distribution_init(dist, nmax)
557  TYPE(fb_distribution_list), INTENT(INOUT) :: dist
558  INTEGER, INTENT(IN), OPTIONAL :: nmax
559 
560  INTEGER :: ii, my_nmax
561 
562  my_nmax = 0
563  IF (PRESENT(nmax)) my_nmax = nmax
564  IF (ASSOCIATED(dist%list)) THEN
565  DEALLOCATE (dist%list)
566  END IF
567  NULLIFY (dist%list)
568  IF (my_nmax .GT. 0) THEN
569  ALLOCATE (dist%list(my_nmax))
570  DO ii = 1, SIZE(dist%list)
571  dist%list(ii)%id = 0
572  dist%list(ii)%cost = 0.0_dp
573  END DO
574  END IF
575  dist%nelements = 0
576  dist%cost = 0.0_dp
577  END SUBROUTINE fb_distribution_init
578 
579 ! **************************************************************************************************
580 !> \brief Resize the list array in a distribution
581 !> \param dist : The distribution in question
582 !> \param nmax : new size of the list array
583 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
584 ! **************************************************************************************************
585  SUBROUTINE fb_distribution_resize(dist, nmax)
586  TYPE(fb_distribution_list), INTENT(INOUT) :: dist
587  INTEGER, INTENT(IN) :: nmax
588 
589  INTEGER :: ii, my_nmax
590  TYPE(fb_distribution_element), DIMENSION(:), &
591  POINTER :: new_list
592 
593  IF (.NOT. ASSOCIATED(dist%list)) THEN
594  my_nmax = max(nmax, 1)
595  ALLOCATE (dist%list(my_nmax))
596  ELSE
597  my_nmax = max(nmax, dist%nelements)
598  ALLOCATE (new_list(my_nmax))
599  DO ii = 1, SIZE(new_list)
600  new_list(ii)%id = 0
601  new_list(ii)%cost = 0.0_dp
602  END DO
603  DO ii = 1, dist%nelements
604  new_list(ii) = dist%list(ii)
605  END DO
606  DEALLOCATE (dist%list)
607  dist%list => new_list
608  END IF
609  END SUBROUTINE fb_distribution_resize
610 
611 ! **************************************************************************************************
612 !> \brief Add an atom (element) to a distribution
613 !> \param dist : the distribution in question
614 !> \param element : the element to be added
615 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
616 ! **************************************************************************************************
617  SUBROUTINE fb_distribution_add(dist, element)
618  TYPE(fb_distribution_list), INTENT(INOUT) :: dist
619  TYPE(fb_distribution_element), INTENT(IN) :: element
620 
621  INTEGER :: ii, new_nelements, pos
622 
623  new_nelements = dist%nelements + 1
624 
625  ! resize list if necessary
626  IF (.NOT. ASSOCIATED(dist%list)) THEN
627  CALL fb_distribution_resize(dist, new_nelements)
628  ELSE IF (new_nelements*enlarge_ratio .GT. SIZE(dist%list)) THEN
629  CALL fb_distribution_resize(dist, SIZE(dist%list)*expand_factor)
630  END IF
631  ! assuming the list of elements is always sorted with respect to cost
632  ! slot the new element into the appropriate spot
633  IF (new_nelements == 1) THEN
634  dist%list(1) = element
635  ELSE
636  pos = fb_distribution_find_slot(dist, element)
637  DO ii = dist%nelements, pos, -1
638  dist%list(ii + 1) = dist%list(ii)
639  END DO
640  dist%list(pos) = element
641  END IF
642  dist%nelements = new_nelements
643  dist%cost = dist%cost + element%cost
644  END SUBROUTINE fb_distribution_add
645 
646 ! **************************************************************************************************
647 !> \brief Find the correct slot in the list array to add a new element, so that
648 !> the list will always be ordered with respect to cost
649 !> \param dist : the distribution in question
650 !> \param element : element to be added
651 !> \return : the correct position to add the new element
652 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
653 ! **************************************************************************************************
654  PURE FUNCTION fb_distribution_find_slot(dist, element) RESULT(pos)
655  TYPE(fb_distribution_list), INTENT(IN) :: dist
656  TYPE(fb_distribution_element), INTENT(IN) :: element
657  INTEGER :: pos
658 
659  INTEGER :: lower, middle, n, upper
660 
661  n = dist%nelements
662  IF (element%cost .LT. dist%list(1)%cost) THEN
663  pos = 1
664  RETURN
665  END IF
666  IF (element%cost .GE. dist%list(n)%cost) THEN
667  pos = n + 1
668  RETURN
669  END IF
670  lower = 1
671  upper = n
672  DO WHILE ((upper - lower) .GT. 1)
673  middle = (lower + upper)/2
674  IF (element%cost .LT. dist%list(middle)%cost) THEN
675  upper = middle
676  ELSE
677  lower = middle
678  END IF
679  END DO
680  pos = upper
681  END FUNCTION fb_distribution_find_slot
682 
683 ! **************************************************************************************************
684 !> \brief Remove the pos-th element from a distribution
685 !> \param dist : the distribution in question
686 !> \param pos : index of the element in the list array
687 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
688 ! **************************************************************************************************
689  SUBROUTINE fb_distribution_remove_ind(dist, pos)
690  TYPE(fb_distribution_list), INTENT(INOUT) :: dist
691  INTEGER, INTENT(IN) :: pos
692 
693  INTEGER :: ii
694  LOGICAL :: check_ok
695 
696  check_ok = pos .GT. 0
697  cpassert(check_ok)
698  IF (pos .LE. dist%nelements) THEN
699  dist%cost = dist%cost - dist%list(pos)%cost
700  DO ii = pos, dist%nelements - 1
701  dist%list(ii) = dist%list(ii + 1)
702  END DO
703  dist%list(dist%nelements)%id = 0
704  dist%list(dist%nelements)%cost = 0.0_dp
705  dist%nelements = dist%nelements - 1
706  ! auto resize if required
707  IF (dist%nelements*reduce_ratio .LT. SIZE(dist%list)) THEN
708  CALL fb_distribution_resize(dist, dist%nelements/shrink_factor)
709  END IF
710  END IF
711  END SUBROUTINE fb_distribution_remove_ind
712 
713 ! **************************************************************************************************
714 !> \brief Remove a given element from a distribution
715 !> \param dist : the distribution in question
716 !> \param element : the element in question
717 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
718 ! **************************************************************************************************
719  SUBROUTINE fb_distribution_remove_el(dist, element)
720  TYPE(fb_distribution_list), INTENT(INOUT) :: dist
721  TYPE(fb_distribution_element), INTENT(IN) :: element
722 
723  INTEGER :: ii, pos
724 
725  pos = dist%nelements + 1
726  DO ii = 1, dist%nelements
727  IF (element%id == dist%list(ii)%id) THEN
728  pos = ii
729  EXIT
730  END IF
731  END DO
732  CALL fb_distribution_remove_ind(dist, pos)
733  END SUBROUTINE fb_distribution_remove_el
734 
735 ! **************************************************************************************************
736 !> \brief Move the pos-th element from a distribution to another
737 !> \param dist_from : the source distribution
738 !> \param pos : index of the element in the source distribution
739 !> \param dist_to : the destination distribution
740 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
741 ! **************************************************************************************************
742  SUBROUTINE fb_distribution_move_ind(dist_from, pos, dist_to)
743  TYPE(fb_distribution_list), INTENT(INOUT) :: dist_from
744  INTEGER, INTENT(IN) :: pos
745  TYPE(fb_distribution_list), INTENT(INOUT) :: dist_to
746 
747  LOGICAL :: check_ok
748  TYPE(fb_distribution_element) :: element
749 
750  check_ok = ASSOCIATED(dist_from%list)
751  cpassert(check_ok)
752  check_ok = pos .LE. dist_from%nelements
753  cpassert(check_ok)
754  element = dist_from%list(pos)
755  CALL fb_distribution_add(dist_to, element)
756  CALL fb_distribution_remove(dist_from, pos)
757  END SUBROUTINE fb_distribution_move_ind
758 
759 ! **************************************************************************************************
760 !> \brief Move a given element from a distribution to another
761 !> \param dist_from : the source distribution
762 !> \param element : the element in question
763 !> \param dist_to : the destination distribution
764 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
765 ! **************************************************************************************************
766  SUBROUTINE fb_distribution_move_el(dist_from, element, dist_to)
767  TYPE(fb_distribution_list), INTENT(INOUT) :: dist_from
768  TYPE(fb_distribution_element), INTENT(IN) :: element
769  TYPE(fb_distribution_list), INTENT(INOUT) :: dist_to
770 
771  LOGICAL :: check_ok
772 
773  check_ok = ASSOCIATED(dist_from%list)
774  cpassert(check_ok)
775  CALL fb_distribution_add(dist_to, element)
776  CALL fb_distribution_remove(dist_from, element)
777  END SUBROUTINE fb_distribution_move_el
778 
779 ! **************************************************************************************************
780 !> \brief Release a distribution
781 !> \param dist : the distribution in question
782 !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
783 ! **************************************************************************************************
784  SUBROUTINE fb_distribution_release(dist)
785  TYPE(fb_distribution_list), INTENT(INOUT) :: dist
786 
787  IF (ASSOCIATED(dist%list)) THEN
788  DEALLOCATE (dist%list)
789  END IF
790  END SUBROUTINE fb_distribution_release
791 
Handles all functions related to the CELL.
Definition: cell_types.F:15
various routines to log and control the output. The idea is that decisions about where to log should ...
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
routines to handle the output, The idea is to remove the decision of wheter to output and what to out...
integer function, public cp_print_key_unit_nr(logger, basis_section, print_key_path, extension, middle_name, local, log_filename, ignore_should_output, file_form, file_position, file_action, file_status, do_backup, on_file, is_new_file, mpi_io, fout)
...
subroutine, public cp_print_key_finished_output(unit_nr, logger, basis_section, print_key_path, local, ignore_should_output, on_file, mpi_io)
should be called after you finish working with a unit obtained with cp_print_key_unit_nr,...
objects that represent the structure of input sections and the data contained in an input section
Defines the basic variable types.
Definition: kinds.F:23
integer, parameter, public dp
Definition: kinds.F:34
Interface to the message passing library MPI.
Define the data structure for the particle information.
subroutine, public get_qs_env(qs_env, atomic_kind_set, qs_kind_set, cell, super_cell, cell_ref, use_ref_cell, kpoints, dft_control, mos, sab_orb, sab_all, qmmm, qmmm_periodic, sac_ae, sac_ppl, sac_lri, sap_ppnl, sab_vdw, sab_scp, sap_oce, sab_lrc, sab_se, sab_xtbe, sab_tbe, sab_core, sab_xb, sab_xtb_nonbond, sab_almo, sab_kp, sab_kp_nosym, particle_set, energy, force, matrix_h, matrix_h_im, matrix_ks, matrix_ks_im, matrix_vxc, run_rtp, rtp, matrix_h_kp, matrix_h_im_kp, matrix_ks_kp, matrix_ks_im_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, matrix_s_RI_aux_kp, matrix_s, matrix_s_RI_aux, matrix_w, matrix_p_mp2, matrix_p_mp2_admm, rho, rho_xc, pw_env, ewald_env, ewald_pw, active_space, mpools, input, para_env, blacs_env, scf_control, rel_control, kinetic, qs_charges, vppl, rho_core, rho_nlcc, rho_nlcc_g, ks_env, ks_qmmm_env, wf_history, scf_env, local_particles, local_molecules, distribution_2d, dbcsr_dist, molecule_kind_set, molecule_set, subsys, cp_subsys, oce, local_rho_set, rho_atom_set, task_list, task_list_soft, rho0_atom_set, rho0_mpole, rhoz_set, ecoul_1c, rho0_s_rs, rho0_s_gs, do_kpoints, has_unit_metric, requires_mo_derivs, mo_derivs, mo_loc_history, nkind, natom, nelectron_total, nelectron_spin, efield, neighbor_list_id, linres_control, xas_env, virial, cp_ddapc_env, cp_ddapc_ewald, outer_scf_history, outer_scf_ihistory, x_data, et_coupling, dftb_potential, results, se_taper, se_store_int_env, se_nddo_mpole, se_nonbond_env, admm_env, lri_env, lri_density, exstate_env, ec_env, dispersion_env, gcp_env, vee, rho_external, external_vxc, mask, mp2_env, bs_env, kg_env, WannierCentres, atprop, ls_scf_env, do_transport, transport_env, v_hartree_rspace, s_mstruct_changed, rho_changed, potential_changed, forces_up_to_date, mscfg_env, almo_scf_env, gradient_history, variable_history, embed_pot, spin_embed_pot, polar_env, mos_last_converged, rhs)
Get the QUICKSTEP environment.
real(kind=dp) function, public fb_atomic_halo_cost(atomic_halo, particle_set, qs_kind_set)
Estimates the computational cost with respect to the filter matrix calculation associated to an atomi...
subroutine, public fb_atomic_halo_build_halo_atoms(owner_atom, particle_set, cell, pair_radii, halo_atoms, nhalo_atoms, owner_id_in_halo)
Builds halo atoms for a given (owner) atom.
subroutine, public fb_atomic_halo_set(atomic_halo, owner_atom, owner_id_in_halo, natoms, nelectrons, halo_atoms, sorted, cost)
Sets attributes in a fb_atomic_halo object, one should only set the data content in a fb_atomic_halo ...
subroutine, public fb_atomic_halo_create(atomic_halo)
Creates and initialises an empty fb_atomic_halo object.
pure subroutine, public fb_build_pair_radii(rcut, nkinds, pair_radii)
Builds the required pair_radii array required for building the halo atoms from a given set of cut off...
subroutine, public fb_atomic_halo_nullify(atomic_halo)
Nullifies a fb_atomic_halo object, note that it does not release the original object....
subroutine, public fb_atomic_halo_release(atomic_halo)
Releases an fb_atomic_halo object.
subroutine, public fb_atomic_halo_init(atomic_halo)
Initialises an fb_atomic_halo object, and makes it empty.
subroutine, public fb_distribution_build(fb_env, qs_env, scf_section)
Build local atoms associated to filter matrix algorithm for each MPI process, trying to balance the l...
subroutine, public fb_env_get(fb_env, rcut, filter_temperature, auto_cutoff_scale, eps_default, atomic_halos, trial_fns, collective_com, local_atoms, nlocal_atoms)
method to get attributes from a given fb_env object
subroutine, public fb_env_set(fb_env, rcut, filter_temperature, auto_cutoff_scale, eps_default, atomic_halos, trial_fns, collective_com, local_atoms, nlocal_atoms)
method to set attributes from a given fb_env object
Define the quickstep kind type and their sub types.
Definition: qs_kind_types.F:23
All kind of helpful little routines.
Definition: util.F:14