(git:374b731)
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-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
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
22 USE kinds, ONLY: dp
27 USE qs_fb_atomic_halo_types, ONLY: &
31 USE qs_fb_env_types, ONLY: fb_env_get,&
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
109CONTAINS
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)
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.
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.