(git:ed6f26b)
Loading...
Searching...
No Matches
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-2025 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
21 USE kinds, ONLY: dp
26 USE qs_fb_atomic_halo_types, ONLY: &
30 USE qs_fb_env_types, ONLY: fb_env_get,&
34 USE util, ONLY: sort
35#include "./base/base_uses.f90"
36
37 IMPLICIT NONE
38
39 PRIVATE
40
41 PUBLIC :: fb_distribution_build
42
43 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_fb_distribution_methods'
44
45! **************************************************************************************************
46!> \brief derived type containing cost data used for process distribution
47!> \param id : global atomic index
48!> \param cost : computational cost for the atomic matrix associated
49!> to this atom
50!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
51! **************************************************************************************************
52 TYPE fb_distribution_element
53 INTEGER :: id = -1
54 REAL(KIND=dp) :: cost = -1.0_dp
55 END TYPE fb_distribution_element
56
57! **************************************************************************************************
58!> \brief derived type containing the list of atoms currently allocated to a
59!> processor
60!> \param list : list of atoms and their associated costs
61!> \param cost : total cost of the list
62!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
63! **************************************************************************************************
64 TYPE fb_distribution_list
65 TYPE(fb_distribution_element), DIMENSION(:), POINTER :: list => null()
66 INTEGER :: nelements = -1
67 REAL(KIND=dp) :: cost = -1.0_dp
68 END TYPE fb_distribution_list
69
70! **************************************************************************************************
71!> \brief In filter matrix algorithm, each atomic matrix contributes to a
72!> column in the filter matrix, which is stored in DBCSR format.
73!> When distributing the atoms (and hence the atomic matrics) to the
74!> processors, we want the processors to have atoms that would be
75!> correspond to the block columns in the DBCSR format local to them.
76!> This derived type stores this information. For each atom, it
77!> corresponds to a DBCSR block column, and the list of processors
78!> in the 2D processor grid responsible for this column will be the
79!> preferred processors for this atom.
80!> \param list : list of preferred processors for an atom
81!> note that here the processors are indexed from
82!> 1, i.e. = MPI_RANK+1
83!> \param nprocs : number of processors in the list
84!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
85! **************************************************************************************************
86 TYPE fb_preferred_procs_list
87 INTEGER, DIMENSION(:), POINTER :: list => null()
88 INTEGER :: nprocs = -1
89 END TYPE fb_preferred_procs_list
90
91! Parameters related to automatic resizing of the hash_table:
92! Resize by EXPAND_FACTOR if total no. slots / no. of filled slots < ENLARGE_RATIO
93 INTEGER, PARAMETER, PRIVATE :: ENLARGE_RATIO = 1
94 INTEGER, PARAMETER, PRIVATE :: REDUCE_RATIO = 3
95 INTEGER, PARAMETER, PRIVATE :: EXPAND_FACTOR = 2
96 INTEGER, PARAMETER, PRIVATE :: SHRINK_FACTOR = 2
97
98 INTERFACE fb_distribution_remove
99 MODULE PROCEDURE fb_distribution_remove_ind, &
100 fb_distribution_remove_el
101 END INTERFACE fb_distribution_remove
102
103 INTERFACE fb_distribution_move
104 MODULE PROCEDURE fb_distribution_move_ind, &
105 fb_distribution_move_el
106 END INTERFACE fb_distribution_move
107
108CONTAINS
109
110! **************************************************************************************************
111!> \brief Build local atoms associated to filter matrix algorithm for each
112!> MPI process, trying to balance the load for calculating the
113!> filter matrix
114!> \param fb_env : the filter matrix environment
115!> \param qs_env : quickstep environment
116!> \param scf_section : SCF input section
117!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
118! **************************************************************************************************
119 SUBROUTINE fb_distribution_build(fb_env, qs_env, scf_section)
120 TYPE(fb_env_obj), INTENT(INOUT) :: fb_env
121 TYPE(qs_environment_type), POINTER :: qs_env
122 TYPE(section_vals_type), POINTER :: scf_section
123
124 CHARACTER(len=*), PARAMETER :: routinen = 'fb_distribution_build'
125
126 INTEGER :: handle, i_common_set, iatom, ii, ipe, lb, lowest_cost_ind, my_pe, n_common_sets, &
127 natoms, nhalo_atoms, nkinds, nprocs, owner_id_in_halo, pref_pe, ub
128 INTEGER, ALLOCATABLE, DIMENSION(:) :: common_set_ids, local_atoms_all, &
129 local_atoms_sizes, local_atoms_starts, &
130 pe, pos_in_preferred_list
131 INTEGER, DIMENSION(:), POINTER :: halo_atoms, local_atoms
132 LOGICAL :: acceptable_move, move_happened
133 REAL(kind=dp) :: average_cost
134 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: cost_per_atom, cost_per_proc
135 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: pair_radii
136 REAL(kind=dp), DIMENSION(:), POINTER :: rcut
137 TYPE(cell_type), POINTER :: cell
138 TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: mat_ks
139 TYPE(fb_atomic_halo_obj) :: atomic_halo
140 TYPE(fb_distribution_element) :: element
141 TYPE(fb_distribution_list), ALLOCATABLE, &
142 DIMENSION(:) :: dist
143 TYPE(fb_preferred_procs_list), ALLOCATABLE, &
144 DIMENSION(:) :: preferred_procs_set
145 TYPE(mp_para_env_type), POINTER :: para_env
146 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
147 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
148
149 CALL timeset(routinen, handle)
150
151 NULLIFY (mat_ks, rcut, cell, para_env, particle_set, qs_kind_set, &
152 halo_atoms, local_atoms)
153 CALL fb_atomic_halo_nullify(atomic_halo)
154
155 ! obtain relevant data from fb_env, qs_env
156 CALL fb_env_get(fb_env=fb_env, &
157 rcut=rcut)
158 CALL get_qs_env(qs_env=qs_env, &
159 natom=natoms, &
160 particle_set=particle_set, &
161 qs_kind_set=qs_kind_set, &
162 nkind=nkinds, &
163 cell=cell, &
164 para_env=para_env, &
165 matrix_ks=mat_ks)
166 nprocs = para_env%num_pe
167 my_pe = para_env%mepos + 1 ! counting from 1
168
169 ! for each global atom, build atomic halo and get the associated cost
170 ALLOCATE (pair_radii(nkinds, nkinds))
171 CALL fb_build_pair_radii(rcut, nkinds, pair_radii)
172 CALL fb_atomic_halo_create(atomic_halo)
173 ALLOCATE (cost_per_atom(natoms))
174 DO iatom = 1, natoms
175 CALL fb_atomic_halo_init(atomic_halo)
177 particle_set, &
178 cell, &
179 pair_radii, &
180 halo_atoms, &
181 nhalo_atoms, &
182 owner_id_in_halo)
183 CALL fb_atomic_halo_set(atomic_halo=atomic_halo, &
184 owner_atom=iatom, &
185 natoms=nhalo_atoms, &
186 halo_atoms=halo_atoms)
187 NULLIFY (halo_atoms)
188 cost_per_atom(iatom) = fb_atomic_halo_cost(atomic_halo, particle_set, qs_kind_set)
189 END DO
190 DEALLOCATE (pair_radii)
191 CALL fb_atomic_halo_release(atomic_halo)
192
193 ! build the preferred_procs_set according to DBCSR mat H
194 ALLOCATE (preferred_procs_set(natoms))
195 ALLOCATE (common_set_ids(natoms))
196 CALL fb_build_preferred_procs(mat_ks(1)%matrix, &
197 natoms, &
198 preferred_procs_set, &
199 common_set_ids, &
200 n_common_sets)
201
202 ! for each atomic halo, construct distribution_element, and assign
203 ! the element to a processors using preferred_procs_set in a
204 ! round-robin manner
205 ALLOCATE (dist(nprocs))
206 DO ipe = 1, nprocs
207 CALL fb_distribution_init(dist=dist(ipe))
208 END DO
209 ALLOCATE (pos_in_preferred_list(n_common_sets))
210 pos_in_preferred_list(:) = 0
211 DO iatom = 1, natoms
212 element%id = iatom
213 element%cost = cost_per_atom(iatom)
214 i_common_set = common_set_ids(iatom)
215 pos_in_preferred_list(i_common_set) = &
216 mod(pos_in_preferred_list(i_common_set), &
217 preferred_procs_set(iatom)%nprocs) + 1
218 ipe = preferred_procs_set(iatom)%list(pos_in_preferred_list(i_common_set))
219 CALL fb_distribution_add(dist(ipe), element)
220 END DO
221
222 DEALLOCATE (pos_in_preferred_list)
223 DEALLOCATE (common_set_ids)
224 DEALLOCATE (cost_per_atom)
225
226 ! sort processors according to the overall cost of their assigned
227 ! corresponding distribution
228 ALLOCATE (cost_per_proc(nprocs))
229 DO ipe = 1, nprocs
230 cost_per_proc(ipe) = dist(ipe)%cost
231 END DO
232 ALLOCATE (pe(nprocs))
233 CALL sort(cost_per_proc, nprocs, pe)
234 ! now that cost_per_proc is sorted, ipe's no longer give mpi
235 ! ranks, the correct one to use should be pe(ipe)
236
237 ! work out the ideal average cost per proc if work load is evenly
238 ! distributed
239 average_cost = sum(cost_per_proc)/real(nprocs, dp)
240
241 DEALLOCATE (cost_per_proc)
242
243 ! loop over the processors, starting with the highest cost, move
244 ! atoms one by one:
245 ! 1. FIRST to the next processor in the preferred list that has
246 ! cost below average. IF no such proc is found, THEN
247 ! 2. to the next procesor in the overall list that has cost
248 ! below average.
249 ! repeat until the cost on this processor is less than or equal
250 ! to the average cost
251 lowest_cost_ind = 1
252 DO ipe = nprocs, 1, -1
253 redistribute: DO WHILE (dist(pe(ipe))%cost .GT. average_cost)
254 iatom = dist(pe(ipe))%list(lowest_cost_ind)%id
255 move_happened = .false.
256 ! first try to move to a preferred process
257 preferred: DO ii = 1, preferred_procs_set(iatom)%nprocs
258 pref_pe = preferred_procs_set(iatom)%list(ii)
259 acceptable_move = &
260 fb_distribution_acceptable_move(dist(pe(ipe)), &
261 dist(pe(ipe))%list(lowest_cost_ind), &
262 dist(pref_pe), &
263 average_cost)
264 IF ((pref_pe .NE. pe(ipe)) .AND. acceptable_move) THEN
265 CALL fb_distribution_move(dist(pe(ipe)), &
266 lowest_cost_ind, &
267 dist(pref_pe))
268 move_happened = .true.
269 EXIT preferred
270 END IF
271 END DO preferred
272 ! if no preferred process is available, move to a proc in
273 ! the sorted list that has cost less than average. remember
274 ! that some of the proc may have already taken redistributed
275 ! atoms, and thus may become unavailable (full)
276 IF (.NOT. move_happened) THEN
277 ! searching from the proc with the least initial cost
278 next_in_line: DO ii = 1, nprocs
279 acceptable_move = &
280 fb_distribution_acceptable_move(dist(pe(ipe)), &
281 dist(pe(ipe))%list(lowest_cost_ind), &
282 dist(pe(ii)), &
283 average_cost)
284 IF ((pe(ii) .NE. pe(ipe)) .AND. acceptable_move) THEN
285 CALL fb_distribution_move(dist(pe(ipe)), &
286 lowest_cost_ind, &
287 dist(pe(ii)))
288 move_happened = .true.
289 EXIT next_in_line
290 END IF
291 END DO next_in_line
292 END IF
293 ! if the atom cannot be moved, then this means it is too
294 ! costly for all other processes to accept. When this
295 ! happens we must stop the redistribution process for this
296 ! processor---as all other of its atoms will be even more
297 ! costly
298 IF (.NOT. move_happened) THEN
299 EXIT redistribute
300 END IF
301 END DO redistribute ! while
302 END DO ! ipe
303
304 DEALLOCATE (pe)
305 DO ii = 1, SIZE(preferred_procs_set)
306 CALL fb_preferred_procs_list_release(preferred_procs_set(ii))
307 END DO
308 DEALLOCATE (preferred_procs_set)
309
310 ! generate local atoms from dist
311 ALLOCATE (local_atoms_all(natoms))
312 ALLOCATE (local_atoms_starts(nprocs))
313 ALLOCATE (local_atoms_sizes(nprocs))
314 CALL fb_distribution_to_local_atoms(dist, &
315 local_atoms_all, &
316 local_atoms_starts, &
317 local_atoms_sizes)
318 ALLOCATE (local_atoms(local_atoms_sizes(my_pe)))
319 lb = local_atoms_starts(my_pe)
320 ub = local_atoms_starts(my_pe) + local_atoms_sizes(my_pe) - 1
321 local_atoms(1:local_atoms_sizes(my_pe)) = local_atoms_all(lb:ub)
322 CALL fb_env_set(fb_env=fb_env, &
323 local_atoms=local_atoms, &
324 nlocal_atoms=local_atoms_sizes(my_pe))
325
326 ! write out info
327 CALL fb_distribution_write_info(dist, scf_section)
328
329 DEALLOCATE (local_atoms_all)
330 DEALLOCATE (local_atoms_starts)
331 DEALLOCATE (local_atoms_sizes)
332 DO ipe = 1, SIZE(dist)
333 CALL fb_distribution_release(dist(ipe))
334 END DO
335 DEALLOCATE (dist)
336
337 CALL timestop(handle)
338
339 END SUBROUTINE fb_distribution_build
340
341! **************************************************************************************************
342!> \brief Checks if moving an element from one distribution to another is
343!> allowed in mind of load balancing.
344!> \param dist_from : the source distribution
345!> \param element : the element in source distribution considered for the
346!> move
347!> \param dist_to : the destination distribution
348!> \param threshold ...
349!> \return : TRUE or FALSE
350!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
351! **************************************************************************************************
352 PURE FUNCTION fb_distribution_acceptable_move(dist_from, &
353 element, &
354 dist_to, &
355 threshold) &
356 result(acceptable)
357 TYPE(fb_distribution_list), INTENT(IN) :: dist_from
358 TYPE(fb_distribution_element), INTENT(IN) :: element
359 TYPE(fb_distribution_list), INTENT(IN) :: dist_to
360 REAL(kind=dp), INTENT(IN) :: threshold
361 LOGICAL :: acceptable
362
363 acceptable = (dist_to%cost + element%cost .LT. dist_from%cost) .AND. &
364 (dist_to%cost .LT. threshold)
365 END FUNCTION fb_distribution_acceptable_move
366
367! **************************************************************************************************
368!> \brief Write out information on the load distribution on processors
369!> \param dist_set : set of distributions for the processors
370!> \param scf_section : SCF input section
371!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
372! **************************************************************************************************
373 SUBROUTINE fb_distribution_write_info(dist_set, scf_section)
374 TYPE(fb_distribution_list), DIMENSION(:), &
375 INTENT(IN) :: dist_set
376 TYPE(section_vals_type), POINTER :: scf_section
377
378 INTEGER :: ii, max_natoms, min_natoms, natoms, &
379 nprocs, unit_nr
380 REAL(kind=dp) :: ave_cost, ave_natoms, max_cost, &
381 min_cost, total_cost
382 TYPE(cp_logger_type), POINTER :: logger
383
384 nprocs = SIZE(dist_set)
385 natoms = 0
386 total_cost = 0.0_dp
387 DO ii = 1, nprocs
388 natoms = natoms + dist_set(ii)%nelements
389 total_cost = total_cost + dist_set(ii)%cost
390 END DO
391 ave_natoms = real(natoms, dp)/real(nprocs, dp)
392 ave_cost = total_cost/real(nprocs, dp)
393 max_natoms = 0
394 max_cost = 0._dp
395 DO ii = 1, nprocs
396 max_natoms = max(max_natoms, dist_set(ii)%nelements)
397 max_cost = max(max_cost, dist_set(ii)%cost)
398 END DO
399 min_natoms = natoms
400 min_cost = total_cost
401 DO ii = 1, nprocs
402 min_natoms = min(min_natoms, dist_set(ii)%nelements)
403 min_cost = min(min_cost, dist_set(ii)%cost)
404 END DO
405
406 logger => cp_get_default_logger()
407 unit_nr = cp_print_key_unit_nr(logger, scf_section, &
408 "PRINT%FILTER_MATRIX", &
409 extension="")
410
411 IF (unit_nr > 0) THEN
412 WRITE (unit=unit_nr, fmt="(/,A,I6,A)") &
413 " FILTER_MAT_DIAG| Load distribution across ", nprocs, " processors:"
414 WRITE (unit=unit_nr, &
415 fmt="(A,T40,A,T55,A,T70,A,T85,A)") &
416 " FILTER_MAT_DIAG| ", "Total", "Average", "Max", "Min"
417 WRITE (unit=unit_nr, &
418 fmt="(A,T40,I12,T55,F12.1,T70,I12,T85,I10)") &
419 " FILTER_MAT_DIAG| Atomic Matrices", &
420 natoms, ave_natoms, max_natoms, min_natoms
421 WRITE (unit=unit_nr, &
422 fmt="(A,T40,D12.7,T55,D12.7,T70,D12.7,T85,D12.7)") &
423 " FILTER_MAT_DIAG| Cost*", &
424 total_cost, ave_cost, max_cost, min_cost
425 WRITE (unit=unit_nr, fmt="(A)") &
426 " FILTER_MAT_DIAG| (* cost is calculated as sum of cube of atomic matrix sizes)"
427 END IF
428 CALL cp_print_key_finished_output(unit_nr, logger, scf_section, &
429 "PRINT%FILTER_MATRIX")
430 END SUBROUTINE fb_distribution_write_info
431
432! **************************************************************************************************
433!> \brief Build the preferred list of processors for atoms
434!> \param dbcsr_mat : the reference DBCSR matrix, from which the local block
435!> cols and the processor maps are obtained
436!> \param natoms : total number of atoms globally
437!> \param preferred_procs_set : set of preferred procs list for each atom
438!> \param common_set_ids : atoms (block cols) local to the same processor grid
439!> col will have the same preferred list. This list
440!> maps each atom to their corresponding group
441!> \param n_common_sets : number of unique preferred lists (groups)
442!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
443! **************************************************************************************************
444 SUBROUTINE fb_build_preferred_procs(dbcsr_mat, &
445 natoms, &
446 preferred_procs_set, &
447 common_set_ids, &
448 n_common_sets)
449 TYPE(dbcsr_type), POINTER :: dbcsr_mat
450 INTEGER, INTENT(IN) :: natoms
451 TYPE(fb_preferred_procs_list), DIMENSION(:), &
452 INTENT(INOUT) :: preferred_procs_set
453 INTEGER, DIMENSION(:), INTENT(OUT) :: common_set_ids
454 INTEGER, INTENT(OUT) :: n_common_sets
455
456 INTEGER :: icol, nblkcols_tot, nprows, pcol, prow
457 INTEGER, DIMENSION(:), POINTER :: col_dist
458 INTEGER, DIMENSION(:, :), POINTER :: pgrid
459 TYPE(dbcsr_distribution_type) :: dbcsr_dist
460
461 CALL dbcsr_get_info(dbcsr_mat, nblkcols_total=nblkcols_tot)
462 cpassert(natoms <= nblkcols_tot)
463 cpassert(SIZE(preferred_procs_set) >= natoms)
464 cpassert(SIZE(common_set_ids) >= natoms)
465
466 CALL dbcsr_get_info(dbcsr_mat, distribution=dbcsr_dist, proc_col_dist=col_dist)
467 CALL dbcsr_distribution_get(dbcsr_dist, pgrid=pgrid, nprows=nprows, npcols=n_common_sets)
468
469 DO icol = 1, natoms
470 IF (ASSOCIATED(preferred_procs_set(icol)%list)) THEN
471 DEALLOCATE (preferred_procs_set(icol)%list)
472 END IF
473 ALLOCATE (preferred_procs_set(icol)%list(nprows))
474 pcol = col_dist(icol)
475 ! dbcsr prow and pcol counts from 0
476 DO prow = 0, nprows - 1
477 ! here, we count processes from 1, so +1 from mpirank
478 preferred_procs_set(icol)%list(prow + 1) = pgrid(prow, pcol) + 1
479 END DO
480 preferred_procs_set(icol)%nprocs = nprows
481 END DO
482
483 common_set_ids(:) = 0
484 common_set_ids(1:natoms) = col_dist(1:natoms) + 1
485
486 END SUBROUTINE fb_build_preferred_procs
487
488! **************************************************************************************************
489!> \brief Release a preferred_procs_list
490!> \param preferred_procs_list : the preferred procs list in question
491!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
492! **************************************************************************************************
493 SUBROUTINE fb_preferred_procs_list_release(preferred_procs_list)
494 TYPE(fb_preferred_procs_list), INTENT(INOUT) :: preferred_procs_list
495
496 IF (ASSOCIATED(preferred_procs_list%list)) THEN
497 DEALLOCATE (preferred_procs_list%list)
498 END IF
499 END SUBROUTINE fb_preferred_procs_list_release
500
501! **************************************************************************************************
502!> \brief Convert distribution data to 1D array containing information of
503!> which atoms are distributed to which processor
504!> \param dist_set : set of distributions for the processors
505!> \param local_atoms : continuous array of atoms arranged in order
506!> corresponding their allocated processors
507!> \param local_atoms_starts : starting position in local_atoms array for
508!> each processor
509!> \param local_atoms_sizes : number of atoms local to each processor
510!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
511! **************************************************************************************************
512 SUBROUTINE fb_distribution_to_local_atoms(dist_set, &
513 local_atoms, &
514 local_atoms_starts, &
515 local_atoms_sizes)
516 TYPE(fb_distribution_list), DIMENSION(:), &
517 INTENT(IN) :: dist_set
518 INTEGER, DIMENSION(:), INTENT(OUT) :: local_atoms, local_atoms_starts, &
519 local_atoms_sizes
520
521 INTEGER :: iatom, ipe, n_procs, pos
522 LOGICAL :: check_ok
523
524 n_procs = SIZE(dist_set)
525
526 check_ok = SIZE(local_atoms_starts) .GE. n_procs
527 cpassert(check_ok)
528 check_ok = SIZE(local_atoms_sizes) .GE. n_procs
529 cpassert(check_ok)
530
531 local_atoms(:) = 0
532 local_atoms_starts(:) = 0
533 local_atoms_sizes(:) = 0
534
535 pos = 1
536 DO ipe = 1, n_procs
537 local_atoms_starts(ipe) = pos
538 DO iatom = 1, dist_set(ipe)%nelements
539 local_atoms(pos) = dist_set(ipe)%list(iatom)%id
540 pos = pos + 1
541 local_atoms_sizes(ipe) = local_atoms_sizes(ipe) + 1
542 END DO
543 END DO
544 END SUBROUTINE fb_distribution_to_local_atoms
545
546! **************************************************************************************************
547!> \brief Initialise a distribution
548!> \param dist : the distribution in question
549!> \param nmax : [OPTIONAL] size of the list array to be allocated
550!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
551! **************************************************************************************************
552 SUBROUTINE fb_distribution_init(dist, nmax)
553 TYPE(fb_distribution_list), INTENT(INOUT) :: dist
554 INTEGER, INTENT(IN), OPTIONAL :: nmax
555
556 INTEGER :: ii, my_nmax
557
558 my_nmax = 0
559 IF (PRESENT(nmax)) my_nmax = nmax
560 IF (ASSOCIATED(dist%list)) THEN
561 DEALLOCATE (dist%list)
562 END IF
563 NULLIFY (dist%list)
564 IF (my_nmax .GT. 0) THEN
565 ALLOCATE (dist%list(my_nmax))
566 DO ii = 1, SIZE(dist%list)
567 dist%list(ii)%id = 0
568 dist%list(ii)%cost = 0.0_dp
569 END DO
570 END IF
571 dist%nelements = 0
572 dist%cost = 0.0_dp
573 END SUBROUTINE fb_distribution_init
574
575! **************************************************************************************************
576!> \brief Resize the list array in a distribution
577!> \param dist : The distribution in question
578!> \param nmax : new size of the list array
579!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
580! **************************************************************************************************
581 SUBROUTINE fb_distribution_resize(dist, nmax)
582 TYPE(fb_distribution_list), INTENT(INOUT) :: dist
583 INTEGER, INTENT(IN) :: nmax
584
585 INTEGER :: ii, my_nmax
586 TYPE(fb_distribution_element), DIMENSION(:), &
587 POINTER :: new_list
588
589 IF (.NOT. ASSOCIATED(dist%list)) THEN
590 my_nmax = max(nmax, 1)
591 ALLOCATE (dist%list(my_nmax))
592 ELSE
593 my_nmax = max(nmax, dist%nelements)
594 ALLOCATE (new_list(my_nmax))
595 DO ii = 1, SIZE(new_list)
596 new_list(ii)%id = 0
597 new_list(ii)%cost = 0.0_dp
598 END DO
599 DO ii = 1, dist%nelements
600 new_list(ii) = dist%list(ii)
601 END DO
602 DEALLOCATE (dist%list)
603 dist%list => new_list
604 END IF
605 END SUBROUTINE fb_distribution_resize
606
607! **************************************************************************************************
608!> \brief Add an atom (element) to a distribution
609!> \param dist : the distribution in question
610!> \param element : the element to be added
611!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
612! **************************************************************************************************
613 SUBROUTINE fb_distribution_add(dist, element)
614 TYPE(fb_distribution_list), INTENT(INOUT) :: dist
615 TYPE(fb_distribution_element), INTENT(IN) :: element
616
617 INTEGER :: ii, new_nelements, pos
618
619 new_nelements = dist%nelements + 1
620
621 ! resize list if necessary
622 IF (.NOT. ASSOCIATED(dist%list)) THEN
623 CALL fb_distribution_resize(dist, new_nelements)
624 ELSE IF (new_nelements*enlarge_ratio .GT. SIZE(dist%list)) THEN
625 CALL fb_distribution_resize(dist, SIZE(dist%list)*expand_factor)
626 END IF
627 ! assuming the list of elements is always sorted with respect to cost
628 ! slot the new element into the appropriate spot
629 IF (new_nelements == 1) THEN
630 dist%list(1) = element
631 ELSE
632 pos = fb_distribution_find_slot(dist, element)
633 DO ii = dist%nelements, pos, -1
634 dist%list(ii + 1) = dist%list(ii)
635 END DO
636 dist%list(pos) = element
637 END IF
638 dist%nelements = new_nelements
639 dist%cost = dist%cost + element%cost
640 END SUBROUTINE fb_distribution_add
641
642! **************************************************************************************************
643!> \brief Find the correct slot in the list array to add a new element, so that
644!> the list will always be ordered with respect to cost
645!> \param dist : the distribution in question
646!> \param element : element to be added
647!> \return : the correct position to add the new element
648!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
649! **************************************************************************************************
650 PURE FUNCTION fb_distribution_find_slot(dist, element) RESULT(pos)
651 TYPE(fb_distribution_list), INTENT(IN) :: dist
652 TYPE(fb_distribution_element), INTENT(IN) :: element
653 INTEGER :: pos
654
655 INTEGER :: lower, middle, n, upper
656
657 n = dist%nelements
658 IF (element%cost .LT. dist%list(1)%cost) THEN
659 pos = 1
660 RETURN
661 END IF
662 IF (element%cost .GE. dist%list(n)%cost) THEN
663 pos = n + 1
664 RETURN
665 END IF
666 lower = 1
667 upper = n
668 DO WHILE ((upper - lower) .GT. 1)
669 middle = (lower + upper)/2
670 IF (element%cost .LT. dist%list(middle)%cost) THEN
671 upper = middle
672 ELSE
673 lower = middle
674 END IF
675 END DO
676 pos = upper
677 END FUNCTION fb_distribution_find_slot
678
679! **************************************************************************************************
680!> \brief Remove the pos-th element from a distribution
681!> \param dist : the distribution in question
682!> \param pos : index of the element in the list array
683!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
684! **************************************************************************************************
685 SUBROUTINE fb_distribution_remove_ind(dist, pos)
686 TYPE(fb_distribution_list), INTENT(INOUT) :: dist
687 INTEGER, INTENT(IN) :: pos
688
689 INTEGER :: ii
690 LOGICAL :: check_ok
691
692 check_ok = pos .GT. 0
693 cpassert(check_ok)
694 IF (pos .LE. dist%nelements) THEN
695 dist%cost = dist%cost - dist%list(pos)%cost
696 DO ii = pos, dist%nelements - 1
697 dist%list(ii) = dist%list(ii + 1)
698 END DO
699 dist%list(dist%nelements)%id = 0
700 dist%list(dist%nelements)%cost = 0.0_dp
701 dist%nelements = dist%nelements - 1
702 ! auto resize if required
703 IF (dist%nelements*reduce_ratio .LT. SIZE(dist%list)) THEN
704 CALL fb_distribution_resize(dist, dist%nelements/shrink_factor)
705 END IF
706 END IF
707 END SUBROUTINE fb_distribution_remove_ind
708
709! **************************************************************************************************
710!> \brief Remove a given element from a distribution
711!> \param dist : the distribution in question
712!> \param element : the element in question
713!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
714! **************************************************************************************************
715 SUBROUTINE fb_distribution_remove_el(dist, element)
716 TYPE(fb_distribution_list), INTENT(INOUT) :: dist
717 TYPE(fb_distribution_element), INTENT(IN) :: element
718
719 INTEGER :: ii, pos
720
721 pos = dist%nelements + 1
722 DO ii = 1, dist%nelements
723 IF (element%id == dist%list(ii)%id) THEN
724 pos = ii
725 EXIT
726 END IF
727 END DO
728 CALL fb_distribution_remove_ind(dist, pos)
729 END SUBROUTINE fb_distribution_remove_el
730
731! **************************************************************************************************
732!> \brief Move the pos-th element from a distribution to another
733!> \param dist_from : the source distribution
734!> \param pos : index of the element in the source distribution
735!> \param dist_to : the destination distribution
736!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
737! **************************************************************************************************
738 SUBROUTINE fb_distribution_move_ind(dist_from, pos, dist_to)
739 TYPE(fb_distribution_list), INTENT(INOUT) :: dist_from
740 INTEGER, INTENT(IN) :: pos
741 TYPE(fb_distribution_list), INTENT(INOUT) :: dist_to
742
743 LOGICAL :: check_ok
744 TYPE(fb_distribution_element) :: element
745
746 check_ok = ASSOCIATED(dist_from%list)
747 cpassert(check_ok)
748 check_ok = pos .LE. dist_from%nelements
749 cpassert(check_ok)
750 element = dist_from%list(pos)
751 CALL fb_distribution_add(dist_to, element)
752 CALL fb_distribution_remove(dist_from, pos)
753 END SUBROUTINE fb_distribution_move_ind
754
755! **************************************************************************************************
756!> \brief Move a given element from a distribution to another
757!> \param dist_from : the source distribution
758!> \param element : the element in question
759!> \param dist_to : the destination distribution
760!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
761! **************************************************************************************************
762 SUBROUTINE fb_distribution_move_el(dist_from, element, dist_to)
763 TYPE(fb_distribution_list), INTENT(INOUT) :: dist_from
764 TYPE(fb_distribution_element), INTENT(IN) :: element
765 TYPE(fb_distribution_list), INTENT(INOUT) :: dist_to
766
767 LOGICAL :: check_ok
768
769 check_ok = ASSOCIATED(dist_from%list)
770 cpassert(check_ok)
771 CALL fb_distribution_add(dist_to, element)
772 CALL fb_distribution_remove(dist_from, element)
773 END SUBROUTINE fb_distribution_move_el
774
775! **************************************************************************************************
776!> \brief Release a distribution
777!> \param dist : the distribution in question
778!> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
779! **************************************************************************************************
780 SUBROUTINE fb_distribution_release(dist)
781 TYPE(fb_distribution_list), INTENT(INOUT) :: dist
782
783 IF (ASSOCIATED(dist%list)) THEN
784 DEALLOCATE (dist%list)
785 END IF
786 END SUBROUTINE fb_distribution_release
787
Handles all functions related to the CELL.
Definition cell_types.F:15
subroutine, public dbcsr_get_info(matrix, nblkrows_total, nblkcols_total, nfullrows_total, nfullcols_total, nblkrows_local, nblkcols_local, nfullrows_local, nfullcols_local, my_prow, my_pcol, local_rows, local_cols, proc_row_dist, proc_col_dist, row_blk_size, col_blk_size, row_blk_offset, col_blk_offset, distribution, name, matrix_type, group)
...
subroutine, public dbcsr_distribution_get(dist, row_dist, col_dist, nrows, ncols, has_threads, group, mynode, numnodes, nprows, npcols, myprow, mypcol, pgrid, subgroups_defined, prow_group, pcol_group)
...
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_pp, 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, harris_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, eeq, 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.
All kind of helpful little routines.
Definition util.F:14
Type defining parameters related to the simulation cell.
Definition cell_types.F:55
type of a logger, at the moment it contains just a print level starting at which level it should be l...
stores all the informations relevant to an mpi environment
the object container which allows for the creation of an array of pointers to fb_env
Provides all information about a quickstep kind.