Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : MODULE qs_tddfpt2_subgroups
9 : USE admm_types, ONLY: admm_type,&
10 : get_admm_env
11 : USE atomic_kind_types, ONLY: atomic_kind_type
12 : USE basis_set_types, ONLY: get_gto_basis_set,&
13 : gto_basis_set_type
14 : USE cell_types, ONLY: cell_type
15 : USE cp_blacs_env, ONLY: cp_blacs_env_create,&
16 : cp_blacs_env_release,&
17 : cp_blacs_env_type
18 : USE cp_control_types, ONLY: dft_control_type,&
19 : qs_control_type,&
20 : tddfpt2_control_type
21 : USE cp_dbcsr_api, ONLY: dbcsr_create,&
22 : dbcsr_distribution_release,&
23 : dbcsr_distribution_type,&
24 : dbcsr_get_info,&
25 : dbcsr_release,&
26 : dbcsr_type
27 : USE cp_dbcsr_cp2k_link, ONLY: cp_dbcsr_alloc_block_from_nbl
28 : USE cp_dbcsr_operations, ONLY: cp_dbcsr_dist2d_to_dist
29 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
30 : cp_fm_struct_release,&
31 : cp_fm_struct_type
32 : USE cp_fm_types, ONLY: cp_fm_copy_general,&
33 : cp_fm_create,&
34 : cp_fm_get_info,&
35 : cp_fm_release,&
36 : cp_fm_type
37 : USE distribution_1d_types, ONLY: distribution_1d_type
38 : USE distribution_2d_types, ONLY: distribution_2d_release,&
39 : distribution_2d_type
40 : USE distribution_methods, ONLY: distribute_molecules_2d
41 : USE hartree_local_methods, ONLY: init_coulomb_local
42 : USE hartree_local_types, ONLY: hartree_local_create,&
43 : hartree_local_release,&
44 : hartree_local_type
45 : USE input_constants, ONLY: tddfpt_kernel_full,&
46 : tddfpt_kernel_none,&
47 : tddfpt_kernel_stda
48 : USE input_section_types, ONLY: section_vals_type,&
49 : section_vals_val_get
50 : USE kinds, ONLY: default_string_length,&
51 : dp
52 : USE message_passing, ONLY: mp_para_env_release,&
53 : mp_para_env_type
54 : USE molecule_kind_types, ONLY: molecule_kind_type
55 : USE molecule_types, ONLY: molecule_type
56 : USE particle_types, ONLY: particle_type
57 : USE pw_env_methods, ONLY: pw_env_create,&
58 : pw_env_rebuild
59 : USE pw_env_types, ONLY: pw_env_release,&
60 : pw_env_retain,&
61 : pw_env_type
62 : USE pw_types, ONLY: pw_r3d_rs_type
63 : USE qs_environment_types, ONLY: get_qs_env,&
64 : qs_environment_type
65 : USE qs_kind_types, ONLY: get_qs_kind,&
66 : qs_kind_type
67 : USE qs_ks_types, ONLY: qs_ks_env_type
68 : USE qs_local_rho_types, ONLY: local_rho_set_create,&
69 : local_rho_set_release,&
70 : local_rho_type
71 : USE qs_neighbor_list_types, ONLY: neighbor_list_set_p_type,&
72 : release_neighbor_list_sets
73 : USE qs_neighbor_lists, ONLY: atom2d_build,&
74 : atom2d_cleanup,&
75 : build_neighbor_lists,&
76 : local_atoms_type,&
77 : pair_radius_setup
78 : USE qs_rho0_ggrid, ONLY: rho0_s_grid_create
79 : USE qs_rho0_methods, ONLY: init_rho0
80 : USE qs_rho_atom_methods, ONLY: allocate_rho_atom_internals
81 : USE task_list_methods, ONLY: generate_qs_task_list
82 : USE task_list_types, ONLY: allocate_task_list,&
83 : deallocate_task_list,&
84 : task_list_type
85 : #include "./base/base_uses.f90"
86 :
87 : IMPLICIT NONE
88 :
89 : PRIVATE
90 :
91 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_tddfpt2_subgroups'
92 : LOGICAL, PARAMETER, PRIVATE :: debug_this_module = .TRUE.
93 :
94 : PUBLIC :: tddfpt_subgroup_env_type
95 : PUBLIC :: tddfpt_sub_env_init, tddfpt_sub_env_release
96 : PUBLIC :: tddfpt_dbcsr_create_by_dist, tddfpt_fm_replicate_across_subgroups
97 :
98 : ! **************************************************************************************************
99 : !> \brief Parallel (sub)group environment.
100 : !> \par History
101 : !> * 01.2017 created [Sergey Chulkov]
102 : ! **************************************************************************************************
103 : TYPE tddfpt_subgroup_env_type
104 : !> indicates that the global MPI communicator has been split into subgroups; if it is .FALSE.
105 : !> certain components of the structure (blacs_env, para_env, admm_A, and mos_occ)
106 : !> can still be accessed; in this case they simply point to the corresponding global variables
107 : LOGICAL :: is_split = .FALSE.
108 : !> number of parallel groups
109 : INTEGER :: ngroups = -1
110 : !> group_distribution(0:ngroups-1) : a process with rank 'i' belongs to the parallel group
111 : !> with index 'group_distribution(i)'
112 : INTEGER, DIMENSION(:), ALLOCATABLE :: group_distribution
113 : !> group-specific BLACS parallel environment
114 : TYPE(cp_blacs_env_type), POINTER :: blacs_env => NULL()
115 : !> group-specific MPI parallel environment
116 : TYPE(mp_para_env_type), POINTER :: para_env => NULL()
117 : !> (active) occupied MOs stored in a matrix form [nao x nmo_occ(spin)] distributed across processes
118 : !> in the parallel group
119 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: mos_occ
120 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: mos_active
121 : !> group-specific copy of the ADMM A matrix 'admm_type%A'
122 : TYPE(cp_fm_type), POINTER :: admm_A => NULL()
123 : !
124 : !> indicates that a set of multi-grids has been allocated; if it is .FALSE. all the components
125 : !> below point to the corresponding global variables and can be accessed
126 : LOGICAL :: is_mgrid = .FALSE.
127 : !> group-specific DBCSR distribution
128 : TYPE(dbcsr_distribution_type), POINTER :: dbcsr_dist => NULL()
129 : !> group-specific two-dimensional distribution of pairs of particles
130 : TYPE(distribution_2d_type), POINTER :: dist_2d => NULL()
131 : !> group-specific plane wave environment
132 : TYPE(pw_env_type), POINTER :: pw_env => NULL()
133 : !> integration weights
134 : TYPE(pw_r3d_rs_type), POINTER :: xcint_weights => Null()
135 : !> lists of neighbours in auxiliary and primary basis sets
136 : TYPE(neighbor_list_set_p_type), &
137 : DIMENSION(:), POINTER :: sab_aux_fit => NULL(), sab_orb => NULL()
138 : !> task lists in auxiliary and primary basis sets
139 : TYPE(task_list_type), POINTER :: task_list_aux_fit => NULL(), task_list_orb => NULL()
140 : !> soft task lists in auxiliary and primary basis sets
141 : TYPE(task_list_type), POINTER :: task_list_aux_fit_soft => NULL(), task_list_orb_soft => NULL()
142 : !> GAPW local atomic grids
143 : TYPE(hartree_local_type), POINTER :: hartree_local => NULL()
144 : TYPE(local_rho_type), POINTER :: local_rho_set => NULL()
145 : TYPE(local_rho_type), POINTER :: local_rho_set_admm => NULL()
146 : END TYPE tddfpt_subgroup_env_type
147 :
148 : ! **************************************************************************************************
149 : !> \brief Structure to save global multi-grid related parameters.
150 : !> \par History
151 : !> * 09.2016 created [Sergey Chulkov]
152 : !> * 01.2017 moved from qs_tddfpt2_methods [Sergey Chulkov]
153 : ! **************************************************************************************************
154 : TYPE mgrid_saved_parameters
155 : !> create commensurate grids
156 : LOGICAL :: commensurate_mgrids = .FALSE.
157 : !> create real-space grids
158 : LOGICAL :: realspace_mgrids = .FALSE.
159 : !> do not perform load balancing
160 : LOGICAL :: skip_load_balance = .FALSE.
161 : !> cutoff value at the finest grid level
162 : REAL(KIND=dp) :: cutoff = 0.0_dp
163 : !> inverse scale factor
164 : REAL(KIND=dp) :: progression_factor = 0.0_dp
165 : !> relative cutoff
166 : REAL(KIND=dp) :: relative_cutoff = 0.0_dp
167 : !> list of explicitly given cutoff values
168 : REAL(KIND=dp), DIMENSION(:), POINTER :: e_cutoff => NULL()
169 : END TYPE mgrid_saved_parameters
170 :
171 : CONTAINS
172 :
173 : ! **************************************************************************************************
174 : !> \brief Split MPI communicator to create a set of parallel (sub)groups.
175 : !> \param sub_env parallel group environment (initialised on exit)
176 : !> \param qs_env Quickstep environment
177 : !> \param mos_occ ground state molecular orbitals in primary atomic basis set
178 : !> \param mos_active active ground state molecular orbitals in primary atomic basis set
179 : !> \param kernel Type of kernel (full/sTDA) that will be used
180 : !> \par History
181 : !> * 01.2017 (sub)group-related code has been moved here from the main subroutine tddfpt()
182 : !> [Sergey Chulkov]
183 : ! **************************************************************************************************
184 2832 : SUBROUTINE tddfpt_sub_env_init(sub_env, qs_env, mos_occ, mos_active, kernel)
185 : TYPE(tddfpt_subgroup_env_type), INTENT(out) :: sub_env
186 : TYPE(qs_environment_type), POINTER :: qs_env
187 : TYPE(cp_fm_type), DIMENSION(:), INTENT(in) :: mos_occ, mos_active
188 : INTEGER, INTENT(in) :: kernel
189 :
190 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_sub_env_init'
191 :
192 : INTEGER :: handle, ispin, nao, nao_aux, natom, &
193 : nmo_active, nmo_occ, nspins
194 : TYPE(admm_type), POINTER :: admm_env
195 1416 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
196 : TYPE(cp_blacs_env_type), POINTER :: blacs_env_global
197 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
198 : TYPE(dft_control_type), POINTER :: dft_control
199 : TYPE(mgrid_saved_parameters) :: mgrid_saved
200 : TYPE(mp_para_env_type), POINTER :: para_env_global
201 : TYPE(pw_env_type), POINTER :: pw_env_global
202 : TYPE(pw_r3d_rs_type), POINTER :: weights
203 : TYPE(qs_control_type), POINTER :: qs_control
204 1416 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
205 : TYPE(tddfpt2_control_type), POINTER :: tddfpt_control
206 :
207 1416 : CALL timeset(routineN, handle)
208 :
209 1416 : nspins = SIZE(mos_occ)
210 :
211 : CALL get_qs_env(qs_env, blacs_env=blacs_env_global, dft_control=dft_control, &
212 1416 : para_env=para_env_global, pw_env=pw_env_global)
213 :
214 1416 : tddfpt_control => dft_control%tddfpt2_control
215 1416 : qs_control => dft_control%qs_control
216 :
217 : ! ++ split mpi communicator if
218 : ! a) the requested number of processors per group > 0
219 : ! (means that the split has been requested explicitly), and
220 : ! b) the number of subgroups is >= 2
221 1416 : sub_env%is_split = tddfpt_control%nprocs > 0 .AND. tddfpt_control%nprocs*2 <= para_env_global%num_pe
222 :
223 5858 : ALLOCATE (sub_env%mos_occ(nspins))
224 4442 : ALLOCATE (sub_env%mos_active(nspins))
225 1416 : NULLIFY (sub_env%admm_A)
226 :
227 1416 : CALL get_qs_env(qs_env, xcint_weights=weights)
228 1416 : sub_env%xcint_weights => weights
229 1416 : IF (sub_env%is_split .AND. ASSOCIATED(weights)) THEN
230 0 : CPABORT('subgroups and integration weights not compatible')
231 : END IF
232 :
233 1416 : IF (sub_env%is_split) THEN
234 6 : ALLOCATE (sub_env%group_distribution(0:para_env_global%num_pe - 1))
235 :
236 2 : ALLOCATE (sub_env%para_env)
237 : CALL sub_env%para_env%from_split(comm=para_env_global, ngroups=sub_env%ngroups, &
238 2 : group_distribution=sub_env%group_distribution, subgroup_min_size=tddfpt_control%nprocs)
239 :
240 : ! ++ create a new parallel environment based on the given sub-communicator)
241 2 : NULLIFY (sub_env%blacs_env)
242 :
243 : ! use the default (SQUARE) BLACS grid layout and non-repeatable BLACS collective operations
244 : ! by omitting optional parameters 'blacs_grid_layout' and 'blacs_repeatable'.
245 : ! Ideally we should take these parameters from the variables globenv%blacs_grid_layout and
246 : ! globenv%blacs_repeatable, however the global environment is not available
247 : ! from the subroutine 'qs_energies_properties'.
248 2 : CALL cp_blacs_env_create(sub_env%blacs_env, sub_env%para_env)
249 :
250 2 : NULLIFY (fm_struct)
251 :
252 4 : DO ispin = 1, nspins
253 2 : CALL cp_fm_get_info(mos_occ(ispin), nrow_global=nao, ncol_global=nmo_occ)
254 2 : CALL cp_fm_struct_create(fm_struct, nrow_global=nao, ncol_global=nmo_occ, context=sub_env%blacs_env)
255 2 : CALL cp_fm_create(sub_env%mos_occ(ispin), fm_struct)
256 2 : CALL cp_fm_struct_release(fm_struct)
257 : CALL tddfpt_fm_replicate_across_subgroups(fm_src=mos_occ(ispin), &
258 6 : fm_dest_sub=sub_env%mos_occ(ispin), sub_env=sub_env)
259 : END DO
260 :
261 4 : DO ispin = 1, nspins
262 2 : CALL cp_fm_get_info(mos_active(ispin), nrow_global=nao, ncol_global=nmo_active)
263 2 : CALL cp_fm_struct_create(fm_struct, nrow_global=nao, ncol_global=nmo_active, context=sub_env%blacs_env)
264 2 : CALL cp_fm_create(sub_env%mos_active(ispin), fm_struct)
265 2 : CALL cp_fm_struct_release(fm_struct)
266 : CALL tddfpt_fm_replicate_across_subgroups(fm_src=mos_active(ispin), &
267 6 : fm_dest_sub=sub_env%mos_active(ispin), sub_env=sub_env)
268 : END DO
269 :
270 2 : IF (dft_control%do_admm) THEN
271 2 : CALL get_qs_env(qs_env, admm_env=admm_env)
272 2 : CALL cp_fm_get_info(admm_env%A, nrow_global=nao_aux, ncol_global=nao)
273 2 : CALL cp_fm_struct_create(fm_struct, nrow_global=nao_aux, ncol_global=nao, context=sub_env%blacs_env)
274 2 : ALLOCATE (sub_env%admm_A)
275 2 : CALL cp_fm_create(sub_env%admm_A, fm_struct)
276 2 : CALL cp_fm_struct_release(fm_struct)
277 2 : CALL tddfpt_fm_replicate_across_subgroups(fm_src=admm_env%A, fm_dest_sub=sub_env%admm_A, sub_env=sub_env)
278 : END IF
279 : ELSE
280 1414 : CALL para_env_global%retain()
281 1414 : sub_env%para_env => para_env_global
282 :
283 1414 : CALL blacs_env_global%retain()
284 1414 : sub_env%blacs_env => blacs_env_global
285 :
286 3022 : sub_env%mos_occ(:) = mos_occ(:)
287 3022 : sub_env%mos_active(:) = mos_active(:)
288 :
289 1414 : IF (dft_control%do_admm) THEN
290 248 : CALL get_qs_env(qs_env, admm_env=admm_env)
291 248 : sub_env%admm_A => admm_env%A
292 : END IF
293 : END IF
294 :
295 1416 : IF (kernel == tddfpt_kernel_full) THEN
296 : ! ++ allocate a new plane wave environment
297 852 : sub_env%is_mgrid = sub_env%is_split .OR. tddfpt_control%mgrid_is_explicit
298 :
299 852 : NULLIFY (sub_env%dbcsr_dist, sub_env%dist_2d)
300 852 : NULLIFY (sub_env%sab_orb, sub_env%sab_aux_fit)
301 852 : NULLIFY (sub_env%task_list_orb, sub_env%task_list_aux_fit)
302 852 : NULLIFY (sub_env%task_list_orb_soft, sub_env%task_list_aux_fit_soft)
303 :
304 852 : IF (sub_env%is_mgrid) THEN
305 12 : IF (tddfpt_control%mgrid_is_explicit) THEN
306 10 : CALL init_tddfpt_mgrid(qs_control, tddfpt_control, mgrid_saved)
307 : END IF
308 :
309 12 : IF (ASSOCIATED(weights)) THEN
310 0 : CPABORT('Redefining MGRID and integration weights not compatible')
311 : END IF
312 :
313 12 : NULLIFY (sub_env%pw_env)
314 :
315 12 : CALL pw_env_create(sub_env%pw_env)
316 12 : CALL pw_env_rebuild(sub_env%pw_env, qs_env, sub_env%para_env)
317 :
318 : CALL tddfpt_build_distribution_2d(distribution_2d=sub_env%dist_2d, dbcsr_dist=sub_env%dbcsr_dist, &
319 12 : blacs_env=sub_env%blacs_env, qs_env=qs_env)
320 :
321 : CALL tddfpt_build_tasklist(task_list=sub_env%task_list_orb, sab=sub_env%sab_orb, basis_type="ORB", &
322 : distribution_2d=sub_env%dist_2d, pw_env=sub_env%pw_env, qs_env=qs_env, &
323 : skip_load_balance=qs_control%skip_load_balance_distributed, &
324 12 : reorder_grid_ranks=.TRUE.)
325 :
326 12 : IF (qs_control%gapw .OR. qs_control%gapw_xc) THEN
327 : CALL tddfpt_build_tasklist(task_list=sub_env%task_list_orb_soft, sab=sub_env%sab_orb, basis_type="ORB_SOFT", &
328 : distribution_2d=sub_env%dist_2d, pw_env=sub_env%pw_env, qs_env=qs_env, &
329 : skip_load_balance=qs_control%skip_load_balance_distributed, &
330 8 : reorder_grid_ranks=.TRUE.)
331 : END IF
332 :
333 12 : IF (dft_control%do_admm) THEN
334 : CALL tddfpt_build_tasklist(task_list=sub_env%task_list_aux_fit, sab=sub_env%sab_aux_fit, &
335 : basis_type="AUX_FIT", distribution_2d=sub_env%dist_2d, &
336 : pw_env=sub_env%pw_env, qs_env=qs_env, &
337 : skip_load_balance=qs_control%skip_load_balance_distributed, &
338 8 : reorder_grid_ranks=.FALSE.)
339 8 : IF (qs_control%gapw .OR. qs_control%gapw_xc) THEN
340 : CALL tddfpt_build_tasklist(task_list=sub_env%task_list_aux_fit_soft, sab=sub_env%sab_aux_fit, &
341 : basis_type="AUX_FIT_SOFT", distribution_2d=sub_env%dist_2d, &
342 : pw_env=sub_env%pw_env, qs_env=qs_env, &
343 : skip_load_balance=qs_control%skip_load_balance_distributed, &
344 4 : reorder_grid_ranks=.FALSE.)
345 : END IF
346 : END IF
347 :
348 12 : IF (tddfpt_control%mgrid_is_explicit) THEN
349 10 : CALL restore_qs_mgrid(qs_control, mgrid_saved)
350 : END IF
351 : ELSE
352 840 : CALL pw_env_retain(pw_env_global)
353 840 : sub_env%pw_env => pw_env_global
354 :
355 : CALL get_qs_env(qs_env, dbcsr_dist=sub_env%dbcsr_dist, &
356 840 : sab_orb=sub_env%sab_orb, task_list=sub_env%task_list_orb)
357 840 : IF (dft_control%do_admm) THEN
358 : CALL get_admm_env(admm_env, sab_aux_fit=sub_env%sab_aux_fit, &
359 226 : task_list_aux_fit=sub_env%task_list_aux_fit)
360 226 : IF (qs_control%gapw .OR. qs_control%gapw_xc) THEN
361 90 : sub_env%task_list_aux_fit_soft => admm_env%admm_gapw_env%task_list
362 : END IF
363 : END IF
364 840 : IF (qs_control%gapw .OR. qs_control%gapw_xc) THEN
365 414 : CALL get_qs_env(qs_env, task_list_soft=sub_env%task_list_orb_soft)
366 : END IF
367 : END IF
368 :
369 : ! GAPW initializations
370 852 : IF (dft_control%qs_control%gapw) THEN
371 : CALL get_qs_env(qs_env, &
372 : atomic_kind_set=atomic_kind_set, &
373 : natom=natom, &
374 350 : qs_kind_set=qs_kind_set)
375 :
376 350 : CALL local_rho_set_create(sub_env%local_rho_set)
377 : CALL allocate_rho_atom_internals(sub_env%local_rho_set%rho_atom_set, atomic_kind_set, &
378 350 : qs_kind_set, dft_control, sub_env%para_env)
379 :
380 : CALL init_rho0(sub_env%local_rho_set, qs_env, dft_control%qs_control%gapw_control, &
381 350 : zcore=0.0_dp)
382 350 : CALL rho0_s_grid_create(sub_env%pw_env, sub_env%local_rho_set%rho0_mpole)
383 350 : CALL hartree_local_create(sub_env%hartree_local)
384 350 : CALL init_coulomb_local(sub_env%hartree_local, natom)
385 502 : ELSE IF (dft_control%qs_control%gapw_xc) THEN
386 : CALL get_qs_env(qs_env, &
387 : atomic_kind_set=atomic_kind_set, &
388 72 : qs_kind_set=qs_kind_set)
389 72 : CALL local_rho_set_create(sub_env%local_rho_set)
390 : CALL allocate_rho_atom_internals(sub_env%local_rho_set%rho_atom_set, atomic_kind_set, &
391 72 : qs_kind_set, dft_control, sub_env%para_env)
392 : END IF
393 :
394 : ! ADMM/GAPW
395 852 : IF (dft_control%do_admm) THEN
396 234 : IF (dft_control%qs_control%gapw .OR. dft_control%qs_control%gapw_xc) THEN
397 94 : CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set)
398 94 : CALL local_rho_set_create(sub_env%local_rho_set_admm)
399 : CALL allocate_rho_atom_internals(sub_env%local_rho_set_admm%rho_atom_set, atomic_kind_set, &
400 : admm_env%admm_gapw_env%admm_kind_set, &
401 94 : dft_control, sub_env%para_env)
402 : END IF
403 : END IF
404 :
405 564 : ELSE IF (kernel == tddfpt_kernel_stda) THEN
406 440 : sub_env%is_mgrid = .FALSE.
407 440 : NULLIFY (sub_env%dbcsr_dist, sub_env%dist_2d)
408 440 : NULLIFY (sub_env%sab_orb, sub_env%sab_aux_fit)
409 440 : NULLIFY (sub_env%task_list_orb, sub_env%task_list_orb_soft)
410 440 : NULLIFY (sub_env%task_list_aux_fit, sub_env%task_list_aux_fit_soft)
411 440 : NULLIFY (sub_env%pw_env)
412 440 : IF (sub_env%is_split) THEN
413 0 : CPABORT('Subsys option not available')
414 : ELSE
415 440 : CALL get_qs_env(qs_env, dbcsr_dist=sub_env%dbcsr_dist, sab_orb=sub_env%sab_orb)
416 : END IF
417 124 : ELSE IF (kernel == tddfpt_kernel_none) THEN
418 124 : sub_env%is_mgrid = .FALSE.
419 124 : NULLIFY (sub_env%dbcsr_dist, sub_env%dist_2d)
420 124 : NULLIFY (sub_env%sab_orb, sub_env%sab_aux_fit)
421 124 : NULLIFY (sub_env%task_list_orb, sub_env%task_list_orb_soft)
422 124 : NULLIFY (sub_env%task_list_aux_fit, sub_env%task_list_aux_fit_soft)
423 124 : NULLIFY (sub_env%pw_env)
424 124 : IF (sub_env%is_split) THEN
425 0 : CPABORT('Subsys option not available')
426 : ELSE
427 124 : CALL get_qs_env(qs_env, dbcsr_dist=sub_env%dbcsr_dist, sab_orb=sub_env%sab_orb)
428 : END IF
429 : ELSE
430 0 : CPABORT("Unknown kernel type")
431 : END IF
432 :
433 1416 : CALL timestop(handle)
434 :
435 2832 : END SUBROUTINE tddfpt_sub_env_init
436 :
437 : ! **************************************************************************************************
438 : !> \brief Release parallel group environment
439 : !> \param sub_env parallel group environment (modified on exit)
440 : !> \par History
441 : !> * 01.2017 created [Sergey Chulkov]
442 : ! **************************************************************************************************
443 1416 : SUBROUTINE tddfpt_sub_env_release(sub_env)
444 : TYPE(tddfpt_subgroup_env_type), INTENT(inout) :: sub_env
445 :
446 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_sub_env_release'
447 :
448 : INTEGER :: handle, i
449 :
450 1416 : CALL timeset(routineN, handle)
451 :
452 1416 : IF (sub_env%is_mgrid) THEN
453 12 : IF (ASSOCIATED(sub_env%task_list_aux_fit)) THEN
454 8 : CALL deallocate_task_list(sub_env%task_list_aux_fit)
455 : END IF
456 :
457 12 : IF (ASSOCIATED(sub_env%task_list_aux_fit_soft)) THEN
458 4 : CALL deallocate_task_list(sub_env%task_list_aux_fit_soft)
459 : END IF
460 :
461 12 : IF (ASSOCIATED(sub_env%task_list_orb)) THEN
462 12 : CALL deallocate_task_list(sub_env%task_list_orb)
463 : END IF
464 :
465 12 : IF (ASSOCIATED(sub_env%task_list_orb_soft)) THEN
466 8 : CALL deallocate_task_list(sub_env%task_list_orb_soft)
467 : END IF
468 :
469 12 : CALL release_neighbor_list_sets(sub_env%sab_aux_fit)
470 12 : CALL release_neighbor_list_sets(sub_env%sab_orb)
471 :
472 12 : IF (ASSOCIATED(sub_env%dbcsr_dist)) THEN
473 12 : CALL dbcsr_distribution_release(sub_env%dbcsr_dist)
474 12 : DEALLOCATE (sub_env%dbcsr_dist)
475 : END IF
476 :
477 12 : IF (ASSOCIATED(sub_env%dist_2d)) THEN
478 12 : CALL distribution_2d_release(sub_env%dist_2d)
479 : END IF
480 : END IF
481 :
482 : ! GAPW
483 1416 : IF (ASSOCIATED(sub_env%local_rho_set)) THEN
484 422 : CALL local_rho_set_release(sub_env%local_rho_set)
485 : END IF
486 1416 : IF (ASSOCIATED(sub_env%hartree_local)) THEN
487 350 : CALL hartree_local_release(sub_env%hartree_local)
488 : END IF
489 1416 : IF (ASSOCIATED(sub_env%local_rho_set_admm)) THEN
490 94 : CALL local_rho_set_release(sub_env%local_rho_set_admm)
491 : END IF
492 :
493 : ! if TDDFPT-specific plane-wave environment has not been requested,
494 : ! the pointers sub_env%dbcsr_dist, sub_env%sab_*, and sub_env%task_list_*
495 : ! point to the corresponding ground-state variables from qs_env
496 : ! and should not be deallocated
497 :
498 1416 : CALL pw_env_release(sub_env%pw_env)
499 :
500 1416 : sub_env%is_mgrid = .FALSE.
501 :
502 1416 : IF (sub_env%is_split .AND. ASSOCIATED(sub_env%admm_A)) THEN
503 2 : CALL cp_fm_release(sub_env%admm_A)
504 2 : DEALLOCATE (sub_env%admm_A)
505 : NULLIFY (sub_env%admm_A)
506 : END IF
507 :
508 1416 : IF (sub_env%is_split) THEN
509 4 : DO i = SIZE(sub_env%mos_occ), 1, -1
510 4 : CALL cp_fm_release(sub_env%mos_occ(i))
511 : END DO
512 4 : DO i = SIZE(sub_env%mos_active), 1, -1
513 4 : CALL cp_fm_release(sub_env%mos_active(i))
514 : END DO
515 : END IF
516 1416 : DEALLOCATE (sub_env%mos_occ)
517 1416 : DEALLOCATE (sub_env%mos_active)
518 :
519 1416 : CALL cp_blacs_env_release(sub_env%blacs_env)
520 1416 : CALL mp_para_env_release(sub_env%para_env)
521 :
522 1416 : IF (ALLOCATED(sub_env%group_distribution)) THEN
523 2 : DEALLOCATE (sub_env%group_distribution)
524 : END IF
525 :
526 1416 : sub_env%is_split = .FALSE.
527 :
528 1416 : CALL timestop(handle)
529 :
530 1416 : END SUBROUTINE tddfpt_sub_env_release
531 :
532 : ! **************************************************************************************************
533 : !> \brief Replace the global multi-grid related parameters in qs_control by the ones given in the
534 : !> TDDFPT/MGRID subsection. The original parameters are stored into the 'mgrid_saved'
535 : !> variable.
536 : !> \param qs_control Quickstep control parameters (modified on exit)
537 : !> \param tddfpt_control TDDFPT control parameters
538 : !> \param mgrid_saved structure to hold global MGRID-related parameters (initialised on exit)
539 : !> \par History
540 : !> * 09.2016 created [Sergey Chulkov]
541 : !> * 01.2017 moved from qs_tddfpt2_methods [Sergey Chulkov]
542 : !> \note the code to build the 'e_cutoff' list was taken from the subroutine read_mgrid_section()
543 : ! **************************************************************************************************
544 10 : SUBROUTINE init_tddfpt_mgrid(qs_control, tddfpt_control, mgrid_saved)
545 : TYPE(qs_control_type), POINTER :: qs_control
546 : TYPE(tddfpt2_control_type), POINTER :: tddfpt_control
547 : TYPE(mgrid_saved_parameters), INTENT(out) :: mgrid_saved
548 :
549 : CHARACTER(LEN=*), PARAMETER :: routineN = 'init_tddfpt_mgrid'
550 :
551 : INTEGER :: handle, igrid, ngrids
552 :
553 10 : CALL timeset(routineN, handle)
554 :
555 : ! ++ save global plane-wave grid parameters to the variable 'mgrid_saved'
556 10 : mgrid_saved%commensurate_mgrids = qs_control%commensurate_mgrids
557 10 : mgrid_saved%realspace_mgrids = qs_control%realspace_mgrids
558 10 : mgrid_saved%skip_load_balance = qs_control%skip_load_balance_distributed
559 10 : mgrid_saved%cutoff = qs_control%cutoff
560 10 : mgrid_saved%progression_factor = qs_control%progression_factor
561 10 : mgrid_saved%relative_cutoff = qs_control%relative_cutoff
562 10 : mgrid_saved%e_cutoff => qs_control%e_cutoff
563 :
564 : ! ++ set parameters from 'tddfpt_control' as default ones for all newly allocated plane-wave grids
565 10 : qs_control%commensurate_mgrids = tddfpt_control%mgrid_commensurate_mgrids
566 10 : qs_control%realspace_mgrids = tddfpt_control%mgrid_realspace_mgrids
567 10 : qs_control%skip_load_balance_distributed = tddfpt_control%mgrid_skip_load_balance
568 10 : qs_control%cutoff = tddfpt_control%mgrid_cutoff
569 10 : qs_control%progression_factor = tddfpt_control%mgrid_progression_factor
570 10 : qs_control%relative_cutoff = tddfpt_control%mgrid_relative_cutoff
571 :
572 30 : ALLOCATE (qs_control%e_cutoff(tddfpt_control%mgrid_ngrids))
573 10 : ngrids = tddfpt_control%mgrid_ngrids
574 10 : IF (ASSOCIATED(tddfpt_control%mgrid_e_cutoff)) THEN
575 : ! following read_mgrid_section() there is a magic scale factor there (0.5_dp)
576 0 : DO igrid = 1, ngrids
577 0 : qs_control%e_cutoff(igrid) = tddfpt_control%mgrid_e_cutoff(igrid)*0.5_dp
578 : END DO
579 : ! ++ round 'qs_control%cutoff' upward to the nearest sub-grid's cutoff value;
580 : ! here we take advantage of the fact that the array 'e_cutoff' has been sorted in descending order
581 0 : DO igrid = ngrids, 1, -1
582 0 : IF (qs_control%cutoff <= qs_control%e_cutoff(igrid)) THEN
583 0 : qs_control%cutoff = qs_control%e_cutoff(igrid)
584 0 : EXIT
585 : END IF
586 : END DO
587 : ! igrid == 0 if qs_control%cutoff is larger than the largest manually provided cutoff value;
588 : ! use the largest actual value
589 0 : IF (igrid <= 0) THEN
590 0 : qs_control%cutoff = qs_control%e_cutoff(1)
591 : END IF
592 : ELSE
593 10 : qs_control%e_cutoff(1) = qs_control%cutoff
594 44 : DO igrid = 2, ngrids
595 44 : qs_control%e_cutoff(igrid) = qs_control%e_cutoff(igrid - 1)/qs_control%progression_factor
596 : END DO
597 : END IF
598 :
599 10 : CALL timestop(handle)
600 10 : END SUBROUTINE init_tddfpt_mgrid
601 :
602 : ! **************************************************************************************************
603 : !> \brief Restore the global multi-grid related parameters stored in the 'mgrid_saved' variable.
604 : !> \param qs_control Quickstep control parameters (modified on exit)
605 : !> \param mgrid_saved structure that holds global MGRID-related parameters
606 : !> \par History
607 : !> * 09.2016 created [Sergey Chulkov]
608 : ! **************************************************************************************************
609 10 : SUBROUTINE restore_qs_mgrid(qs_control, mgrid_saved)
610 : TYPE(qs_control_type), POINTER :: qs_control
611 : TYPE(mgrid_saved_parameters), INTENT(in) :: mgrid_saved
612 :
613 : CHARACTER(LEN=*), PARAMETER :: routineN = 'restore_qs_mgrid'
614 :
615 : INTEGER :: handle
616 :
617 10 : CALL timeset(routineN, handle)
618 :
619 10 : IF (ASSOCIATED(qs_control%e_cutoff)) THEN
620 10 : DEALLOCATE (qs_control%e_cutoff)
621 : END IF
622 :
623 10 : qs_control%commensurate_mgrids = mgrid_saved%commensurate_mgrids
624 10 : qs_control%realspace_mgrids = mgrid_saved%realspace_mgrids
625 10 : qs_control%skip_load_balance_distributed = mgrid_saved%skip_load_balance
626 10 : qs_control%cutoff = mgrid_saved%cutoff
627 10 : qs_control%progression_factor = mgrid_saved%progression_factor
628 10 : qs_control%relative_cutoff = mgrid_saved%relative_cutoff
629 10 : qs_control%e_cutoff => mgrid_saved%e_cutoff
630 :
631 10 : CALL timestop(handle)
632 10 : END SUBROUTINE restore_qs_mgrid
633 :
634 : ! **************************************************************************************************
635 : !> \brief Distribute atoms across the two-dimensional grid of processors.
636 : !> \param distribution_2d new two-dimensional distribution of pairs of particles
637 : !> (allocated and initialised on exit)
638 : !> \param dbcsr_dist new DBCSR distribution (allocated and initialised on exit)
639 : !> \param blacs_env BLACS parallel environment
640 : !> \param qs_env Quickstep environment
641 : !> \par History
642 : !> * 09.2016 created [Sergey Chulkov]
643 : !> * 01.2017 moved from qs_tddfpt2_methods [Sergey Chulkov]
644 : ! **************************************************************************************************
645 24 : SUBROUTINE tddfpt_build_distribution_2d(distribution_2d, dbcsr_dist, blacs_env, qs_env)
646 : TYPE(distribution_2d_type), POINTER :: distribution_2d
647 : TYPE(dbcsr_distribution_type), POINTER :: dbcsr_dist
648 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
649 : TYPE(qs_environment_type), POINTER :: qs_env
650 :
651 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_build_distribution_2d'
652 :
653 : INTEGER :: handle
654 12 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
655 : TYPE(cell_type), POINTER :: cell
656 12 : TYPE(molecule_kind_type), DIMENSION(:), POINTER :: molecule_kind_set
657 12 : TYPE(molecule_type), DIMENSION(:), POINTER :: molecule_set
658 12 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
659 12 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
660 : TYPE(section_vals_type), POINTER :: input
661 :
662 12 : CALL timeset(routineN, handle)
663 :
664 : CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, cell=cell, input=input, &
665 : molecule_kind_set=molecule_kind_set, molecule_set=molecule_set, &
666 12 : particle_set=particle_set, qs_kind_set=qs_kind_set)
667 :
668 12 : NULLIFY (distribution_2d)
669 : CALL distribute_molecules_2d(cell=cell, &
670 : atomic_kind_set=atomic_kind_set, &
671 : particle_set=particle_set, &
672 : qs_kind_set=qs_kind_set, &
673 : molecule_kind_set=molecule_kind_set, &
674 : molecule_set=molecule_set, &
675 : distribution_2d=distribution_2d, &
676 : blacs_env=blacs_env, &
677 12 : force_env_section=input)
678 :
679 12 : ALLOCATE (dbcsr_dist)
680 12 : CALL cp_dbcsr_dist2d_to_dist(distribution_2d, dbcsr_dist)
681 :
682 12 : CALL timestop(handle)
683 12 : END SUBROUTINE tddfpt_build_distribution_2d
684 :
685 : ! **************************************************************************************************
686 : !> \brief Build task and neighbour lists for the given plane wave environment and basis set.
687 : !> \param task_list new task list (allocated and initialised on exit)
688 : !> \param sab new list of neighbours (allocated and initialised on exit)
689 : !> \param basis_type type of the basis set
690 : !> \param distribution_2d two-dimensional distribution of pairs of particles
691 : !> \param pw_env plane wave environment
692 : !> \param qs_env Quickstep environment
693 : !> \param skip_load_balance do not perform load balancing
694 : !> \param reorder_grid_ranks re-optimise grid ranks and re-create the real-space grid descriptor
695 : !> as well as grids
696 : !> \par History
697 : !> * 09.2016 created [Sergey Chulkov]
698 : !> * 01.2017 moved from qs_tddfpt2_methods [Sergey Chulkov]
699 : ! **************************************************************************************************
700 32 : SUBROUTINE tddfpt_build_tasklist(task_list, sab, basis_type, distribution_2d, pw_env, qs_env, &
701 : skip_load_balance, reorder_grid_ranks)
702 : TYPE(task_list_type), POINTER :: task_list
703 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
704 : POINTER :: sab
705 : CHARACTER(len=*), INTENT(in) :: basis_type
706 : TYPE(distribution_2d_type), POINTER :: distribution_2d
707 : TYPE(pw_env_type), POINTER :: pw_env
708 : TYPE(qs_environment_type), POINTER :: qs_env
709 : LOGICAL, INTENT(in) :: skip_load_balance, reorder_grid_ranks
710 :
711 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_build_tasklist'
712 :
713 : INTEGER :: handle, ikind, nkinds
714 32 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: orb_present
715 : REAL(kind=dp) :: subcells
716 32 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: orb_radius
717 32 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: pair_radius
718 32 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
719 : TYPE(cell_type), POINTER :: cell
720 : TYPE(distribution_1d_type), POINTER :: local_particles
721 : TYPE(gto_basis_set_type), POINTER :: orb_basis_set
722 32 : TYPE(local_atoms_type), ALLOCATABLE, DIMENSION(:) :: atom2d
723 32 : TYPE(molecule_type), DIMENSION(:), POINTER :: molecule_set
724 32 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
725 32 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
726 : TYPE(qs_ks_env_type), POINTER :: ks_env
727 : TYPE(section_vals_type), POINTER :: input
728 :
729 32 : CALL timeset(routineN, handle)
730 :
731 : CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, cell=cell, input=input, &
732 : ks_env=ks_env, local_particles=local_particles, molecule_set=molecule_set, &
733 32 : particle_set=particle_set, qs_kind_set=qs_kind_set)
734 :
735 32 : nkinds = SIZE(atomic_kind_set)
736 :
737 32 : IF (.NOT. (ASSOCIATED(sab))) THEN
738 108 : ALLOCATE (atom2d(nkinds))
739 : CALL atom2d_build(atom2d, local_particles, distribution_2d, atomic_kind_set, &
740 20 : molecule_set, molecule_only=.FALSE., particle_set=particle_set)
741 :
742 60 : ALLOCATE (orb_present(nkinds))
743 60 : ALLOCATE (orb_radius(nkinds))
744 80 : ALLOCATE (pair_radius(nkinds, nkinds))
745 :
746 68 : DO ikind = 1, nkinds
747 48 : CALL get_qs_kind(qs_kind_set(ikind), basis_set=orb_basis_set, basis_type=basis_type)
748 68 : IF (ASSOCIATED(orb_basis_set)) THEN
749 48 : orb_present(ikind) = .TRUE.
750 48 : CALL get_gto_basis_set(gto_basis_set=orb_basis_set, kind_radius=orb_radius(ikind))
751 : ELSE
752 0 : orb_present(ikind) = .FALSE.
753 0 : orb_radius(ikind) = 0.0_dp
754 : END IF
755 : END DO
756 :
757 20 : CALL pair_radius_setup(orb_present, orb_present, orb_radius, orb_radius, pair_radius)
758 :
759 20 : NULLIFY (sab)
760 20 : CALL section_vals_val_get(input, "DFT%SUBCELLS", r_val=subcells)
761 : CALL build_neighbor_lists(sab, particle_set, atom2d, cell, pair_radius, &
762 20 : mic=.FALSE., subcells=subcells, molecular=.FALSE., nlname="sab_orb")
763 :
764 20 : CALL atom2d_cleanup(atom2d)
765 40 : DEALLOCATE (atom2d, orb_present, orb_radius, pair_radius)
766 : END IF
767 :
768 32 : CALL allocate_task_list(task_list)
769 : CALL generate_qs_task_list(ks_env, task_list, basis_type=basis_type, &
770 : reorder_rs_grid_ranks=reorder_grid_ranks, &
771 : skip_load_balance_distributed=skip_load_balance, &
772 32 : pw_env_external=pw_env, sab_orb_external=sab)
773 :
774 32 : CALL timestop(handle)
775 64 : END SUBROUTINE tddfpt_build_tasklist
776 :
777 : ! **************************************************************************************************
778 : !> \brief Create a DBCSR matrix based on a template matrix, distribution object, and the list of
779 : !> neighbours.
780 : !> \param matrix matrix to create
781 : !> \param template template matrix
782 : !> \param dbcsr_dist DBCSR distribution
783 : !> \param sab list of neighbours
784 : !> \par History
785 : !> * 09.2016 created [Sergey Chulkov]
786 : !> * 01.2017 moved from qs_tddfpt2_methods [Sergey Chulkov]
787 : ! **************************************************************************************************
788 3024 : SUBROUTINE tddfpt_dbcsr_create_by_dist(matrix, template, dbcsr_dist, sab)
789 : TYPE(dbcsr_type), POINTER :: matrix, template
790 : TYPE(dbcsr_distribution_type), POINTER :: dbcsr_dist
791 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
792 : POINTER :: sab
793 :
794 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_dbcsr_create_by_dist'
795 :
796 : CHARACTER :: matrix_type
797 : CHARACTER(len=default_string_length) :: matrix_name
798 : INTEGER :: handle
799 3024 : INTEGER, DIMENSION(:), POINTER :: col_blk_sizes, row_blk_sizes
800 :
801 3024 : CALL timeset(routineN, handle)
802 :
803 3024 : CPASSERT(ASSOCIATED(template))
804 : CALL dbcsr_get_info(template, row_blk_size=row_blk_sizes, col_blk_size=col_blk_sizes, &
805 3024 : name=matrix_name, matrix_type=matrix_type)
806 :
807 3024 : IF (ASSOCIATED(matrix)) THEN
808 2852 : CALL dbcsr_release(matrix)
809 : ELSE
810 172 : ALLOCATE (matrix)
811 : END IF
812 :
813 3024 : CALL dbcsr_create(matrix, matrix_name, dbcsr_dist, matrix_type, row_blk_sizes, col_blk_sizes)
814 3024 : CALL cp_dbcsr_alloc_block_from_nbl(matrix, sab)
815 :
816 3024 : CALL timestop(handle)
817 :
818 3024 : END SUBROUTINE tddfpt_dbcsr_create_by_dist
819 :
820 : ! **************************************************************************************************
821 : !> \brief Replicate a globally distributed matrix across all sub-groups. At the end
822 : !> every sub-group will hold a local copy of the original globally distributed matrix.
823 : !>
824 : !> |--------------------|
825 : !> fm_src | 0 1 2 3 |
826 : !> |--------------------|
827 : !> / MPI ranks \
828 : !> |/_ _\|
829 : !> |--------------------| |--------------------|
830 : !> fm_dest_subgroup0 | 0 1 | | 2 3 | fm_dest_subgroup1
831 : !> |--------------------| |--------------------|
832 : !> subgroup 0 subgroup 1
833 : !>
834 : !> \param fm_src globally distributed matrix to replicate
835 : !> \param fm_dest_sub subgroup-specific copy of the replicated matrix
836 : !> \param sub_env subgroup environment
837 : !> \par History
838 : !> * 09.2016 created [Sergey Chulkov]
839 : !> * 01.2017 moved from qs_tddfpt2_methods [Sergey Chulkov]
840 : ! **************************************************************************************************
841 6 : SUBROUTINE tddfpt_fm_replicate_across_subgroups(fm_src, fm_dest_sub, sub_env)
842 : TYPE(cp_fm_type), INTENT(IN) :: fm_src, fm_dest_sub
843 : TYPE(tddfpt_subgroup_env_type), INTENT(in) :: sub_env
844 :
845 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_fm_replicate_across_subgroups'
846 :
847 : INTEGER :: handle, igroup, igroup_local, ncols_global_dest, ncols_global_src, ngroups, &
848 : nrows_global_dest, nrows_global_src
849 : TYPE(cp_blacs_env_type), POINTER :: blacs_env_global
850 : TYPE(cp_fm_type) :: fm_null
851 : TYPE(mp_para_env_type), POINTER :: para_env_global
852 :
853 24 : IF (sub_env%is_split) THEN
854 6 : CALL timeset(routineN, handle)
855 :
856 : CALL cp_fm_get_info(fm_src, nrow_global=nrows_global_src, ncol_global=ncols_global_src, &
857 6 : context=blacs_env_global, para_env=para_env_global)
858 6 : CALL cp_fm_get_info(fm_dest_sub, nrow_global=nrows_global_dest, ncol_global=ncols_global_dest)
859 :
860 : IF (debug_this_module) THEN
861 6 : CPASSERT(nrows_global_src == nrows_global_dest)
862 6 : CPASSERT(ncols_global_src == ncols_global_dest)
863 : END IF
864 :
865 6 : igroup_local = sub_env%group_distribution(para_env_global%mepos)
866 6 : ngroups = sub_env%ngroups
867 :
868 18 : DO igroup = 0, ngroups - 1
869 18 : IF (igroup == igroup_local) THEN
870 6 : CALL cp_fm_copy_general(fm_src, fm_dest_sub, para_env_global)
871 : ELSE
872 6 : CALL cp_fm_copy_general(fm_src, fm_null, para_env_global)
873 : END IF
874 : END DO
875 :
876 6 : CALL timestop(handle)
877 : END IF
878 6 : END SUBROUTINE tddfpt_fm_replicate_across_subgroups
879 0 : END MODULE qs_tddfpt2_subgroups
880 :
|