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