Line data Source code
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 :
8 : ! **************************************************************************************************
9 : !> \brief Utility subroutines for mixed CDFT calculations
10 : !> \par History
11 : !> separated from mixed_cdft_methods [01.2017]
12 : !> \author Nico Holmberg [01.2017]
13 : ! **************************************************************************************************
14 : MODULE mixed_cdft_utils
15 : USE atomic_kind_types, ONLY: atomic_kind_type
16 : USE cell_types, ONLY: cell_type
17 : USE cp_array_utils, ONLY: cp_1d_i_p_type,&
18 : cp_1d_r_p_type,&
19 : cp_2d_r_p_type
20 : USE cp_blacs_env, ONLY: cp_blacs_env_create,&
21 : cp_blacs_env_type
22 : USE cp_control_types, ONLY: dft_control_type
23 : USE cp_dbcsr_api, ONLY: dbcsr_desymmetrize,&
24 : dbcsr_get_info,&
25 : dbcsr_init_p,&
26 : dbcsr_p_type,&
27 : dbcsr_release,&
28 : dbcsr_release_p,&
29 : dbcsr_type
30 : USE cp_dbcsr_operations, ONLY: copy_dbcsr_to_fm,&
31 : copy_fm_to_dbcsr_bc
32 : USE cp_files, ONLY: open_file
33 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
34 : cp_fm_struct_release,&
35 : cp_fm_struct_type
36 : USE cp_fm_types, ONLY: cp_fm_copy_general,&
37 : cp_fm_create,&
38 : cp_fm_get_info,&
39 : cp_fm_release,&
40 : cp_fm_to_fm,&
41 : cp_fm_type
42 : USE cp_log_handling, ONLY: cp_get_default_logger,&
43 : cp_logger_create,&
44 : cp_logger_set,&
45 : cp_logger_type,&
46 : cp_to_string
47 : USE cp_output_handling, ONLY: cp_print_key_finished_output,&
48 : cp_print_key_unit_nr
49 : USE cp_realspace_grid_init, ONLY: init_input_type
50 : USE cp_subsys_types, ONLY: cp_subsys_get,&
51 : cp_subsys_type
52 : USE cube_utils, ONLY: init_cube_info,&
53 : return_cube_max_iradius
54 : USE d3_poly, ONLY: init_d3_poly_module
55 : USE force_env_types, ONLY: force_env_get,&
56 : force_env_type,&
57 : multiple_fe_list
58 : USE gaussian_gridlevels, ONLY: init_gaussian_gridlevel
59 : USE global_types, ONLY: global_environment_type
60 : USE hirshfeld_types, ONLY: create_hirshfeld_type,&
61 : release_hirshfeld_type,&
62 : set_hirshfeld_info
63 : USE input_constants, ONLY: becke_cutoff_element,&
64 : mixed_cdft_parallel,&
65 : mixed_cdft_parallel_nobuild,&
66 : mixed_cdft_serial,&
67 : outer_scf_becke_constraint,&
68 : outer_scf_hirshfeld_constraint,&
69 : shape_function_gaussian
70 : USE input_section_types, ONLY: section_vals_duplicate,&
71 : section_vals_get,&
72 : section_vals_get_subs_vals,&
73 : section_vals_release,&
74 : section_vals_type,&
75 : section_vals_val_get
76 : USE kinds, ONLY: default_path_length,&
77 : dp
78 : USE message_passing, ONLY: mp_request_type,&
79 : mp_waitall
80 : USE mixed_cdft_types, ONLY: mixed_cdft_result_type_release,&
81 : mixed_cdft_result_type_set,&
82 : mixed_cdft_settings_type,&
83 : mixed_cdft_type,&
84 : mixed_cdft_work_type_init
85 : USE mixed_environment_types, ONLY: get_mixed_env,&
86 : mixed_environment_type
87 : USE pw_env_methods, ONLY: pw_env_create
88 : USE pw_env_types, ONLY: pw_env_get,&
89 : pw_env_type
90 : USE pw_grid_types, ONLY: HALFSPACE,&
91 : pw_grid_type
92 : USE pw_grids, ONLY: do_pw_grid_blocked_false,&
93 : pw_grid_create,&
94 : pw_grid_release
95 : USE pw_pool_types, ONLY: pw_pool_create,&
96 : pw_pool_p_type,&
97 : pw_pool_type
98 : USE qs_cdft_types, ONLY: cdft_control_create,&
99 : cdft_control_type
100 : USE qs_environment_types, ONLY: get_qs_env,&
101 : qs_environment_type
102 : USE qs_kind_types, ONLY: create_qs_kind_set,&
103 : qs_kind_type
104 : USE realspace_grid_types, ONLY: realspace_grid_desc_p_type,&
105 : realspace_grid_input_type,&
106 : realspace_grid_type,&
107 : rs_grid_create,&
108 : rs_grid_create_descriptor,&
109 : rs_grid_print
110 : #include "./base/base_uses.f90"
111 :
112 : IMPLICIT NONE
113 : PRIVATE
114 :
115 : ! *** Public subroutines ***
116 :
117 : PUBLIC :: mixed_cdft_parse_settings, mixed_cdft_transfer_settings, &
118 : mixed_cdft_init_structures, mixed_cdft_redistribute_arrays, &
119 : mixed_cdft_print_couplings, map_permutation_to_states, hfun_zero, &
120 : mixed_cdft_release_work, mixed_cdft_read_block_diag, &
121 : mixed_cdft_get_blocks, mixed_cdft_diagonalize_blocks, &
122 : mixed_cdft_assemble_block_diag
123 :
124 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'mixed_cdft_utils'
125 :
126 : CONTAINS
127 :
128 : ! **************************************************************************************************
129 : !> \brief Parse settings for mixed cdft calculation and check their consistency
130 : !> \param force_env the force_env that holds the CDFT mixed_env
131 : !> \param mixed_env the mixed_env that holds the CDFT states
132 : !> \param mixed_cdft control section for mixed CDFT
133 : !> \param settings container for settings related to the mixed CDFT calculation
134 : !> \param natom the total number of atoms
135 : !> \par History
136 : !> 01.2017 created [Nico Holmberg]
137 : ! **************************************************************************************************
138 72 : SUBROUTINE mixed_cdft_parse_settings(force_env, mixed_env, mixed_cdft, &
139 : settings, natom)
140 : TYPE(force_env_type), POINTER :: force_env
141 : TYPE(mixed_environment_type), POINTER :: mixed_env
142 : TYPE(mixed_cdft_type), POINTER :: mixed_cdft
143 : TYPE(mixed_cdft_settings_type) :: settings
144 : INTEGER :: natom
145 :
146 : INTEGER :: i, iatom, iforce_eval, igroup, &
147 : nforce_eval, nkinds
148 72 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: constraint_type
149 72 : INTEGER, ALLOCATABLE, DIMENSION(:, :, :) :: array_sizes
150 : LOGICAL :: is_match
151 72 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
152 : TYPE(cdft_control_type), POINTER :: cdft_control
153 72 : TYPE(cp_1d_i_p_type), ALLOCATABLE, DIMENSION(:, :) :: atoms
154 72 : TYPE(cp_1d_r_p_type), ALLOCATABLE, DIMENSION(:, :) :: coeff
155 : TYPE(dft_control_type), POINTER :: dft_control
156 : TYPE(force_env_type), POINTER :: force_env_qs
157 : TYPE(pw_env_type), POINTER :: pw_env
158 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
159 : TYPE(qs_environment_type), POINTER :: qs_env
160 :
161 72 : NULLIFY (dft_control, qs_env, pw_env, auxbas_pw_pool, force_env_qs, &
162 72 : cdft_control)
163 : ! Allocate storage for temporaries used for checking settings consistency
164 72 : settings%max_nkinds = 30
165 72 : nforce_eval = SIZE(force_env%sub_force_env)
166 216 : ALLOCATE (settings%grid_span(nforce_eval))
167 216 : ALLOCATE (settings%npts(3, nforce_eval))
168 216 : ALLOCATE (settings%cutoff(nforce_eval))
169 144 : ALLOCATE (settings%rel_cutoff(nforce_eval))
170 144 : ALLOCATE (settings%spherical(nforce_eval))
171 216 : ALLOCATE (settings%rs_dims(2, nforce_eval))
172 144 : ALLOCATE (settings%odd(nforce_eval))
173 288 : ALLOCATE (settings%atoms(natom, nforce_eval))
174 72 : IF (mixed_cdft%run_type == mixed_cdft_parallel) THEN
175 88 : ALLOCATE (settings%coeffs(natom, nforce_eval))
176 154 : settings%coeffs = 0.0_dp
177 : END IF
178 : ! Some of the checked settings are only defined for certain types of constraints
179 : ! We nonetheless use arrays that are large enough to contain settings for all constraints
180 : ! This is not completely optimal...
181 216 : ALLOCATE (settings%si(6, nforce_eval))
182 216 : ALLOCATE (settings%sb(8, nforce_eval))
183 216 : ALLOCATE (settings%sr(5, nforce_eval))
184 216 : ALLOCATE (settings%cutoffs(settings%max_nkinds, nforce_eval))
185 144 : ALLOCATE (settings%radii(settings%max_nkinds, nforce_eval))
186 240 : settings%grid_span = 0
187 744 : settings%npts = 0
188 240 : settings%cutoff = 0.0_dp
189 240 : settings%rel_cutoff = 0.0_dp
190 240 : settings%spherical = 0
191 72 : settings%is_spherical = .FALSE.
192 576 : settings%rs_dims = 0
193 240 : settings%odd = 0
194 72 : settings%is_odd = .FALSE.
195 614 : settings%atoms = 0
196 1248 : settings%si = 0
197 1080 : settings%sr = 0.0_dp
198 1584 : settings%sb = .FALSE.
199 5280 : settings%cutoffs = 0.0_dp
200 5280 : settings%radii = 0.0_dp
201 : ! Get information from the sub_force_envs
202 240 : DO iforce_eval = 1, nforce_eval
203 168 : IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
204 144 : force_env_qs => force_env%sub_force_env(iforce_eval)%force_env
205 144 : IF (mixed_env%do_mixed_qmmm_cdft) THEN
206 12 : qs_env => force_env_qs%qmmm_env%qs_env
207 : ELSE
208 132 : CALL force_env_get(force_env_qs, qs_env=qs_env)
209 : END IF
210 144 : CALL get_qs_env(qs_env, pw_env=pw_env, dft_control=dft_control)
211 144 : IF (.NOT. dft_control%qs_control%cdft) &
212 : CALL cp_abort(__LOCATION__, &
213 : "A mixed CDFT simulation with multiple force_evals was requested, "// &
214 0 : "but CDFT constraints were not active in the QS section of all force_evals!")
215 144 : cdft_control => dft_control%qs_control%cdft_control
216 144 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
217 1440 : settings%bo = auxbas_pw_pool%pw_grid%bounds_local
218 : ! Only the rank 0 process collects info about pw_grid and CDFT
219 216 : IF (force_env_qs%para_env%is_source()) THEN
220 : ! Grid settings
221 84 : settings%grid_span(iforce_eval) = auxbas_pw_pool%pw_grid%grid_span
222 336 : settings%npts(:, iforce_eval) = auxbas_pw_pool%pw_grid%npts
223 84 : settings%cutoff(iforce_eval) = auxbas_pw_pool%pw_grid%cutoff
224 84 : settings%rel_cutoff(iforce_eval) = dft_control%qs_control%relative_cutoff
225 84 : IF (auxbas_pw_pool%pw_grid%spherical) settings%spherical(iforce_eval) = 1
226 252 : settings%rs_dims(:, iforce_eval) = auxbas_pw_pool%pw_grid%para%group%num_pe_cart
227 84 : IF (auxbas_pw_pool%pw_grid%grid_span == HALFSPACE) settings%odd(iforce_eval) = 1
228 : ! Becke constraint atoms/coeffs
229 84 : IF (cdft_control%natoms .GT. SIZE(settings%atoms, 1)) &
230 : CALL cp_abort(__LOCATION__, &
231 : "More CDFT constraint atoms than defined in mixed section. "// &
232 0 : "Use default values for MIXED\MAPPING.")
233 233 : settings%atoms(1:cdft_control%natoms, iforce_eval) = cdft_control%atoms
234 84 : IF (mixed_cdft%run_type == mixed_cdft_parallel) &
235 66 : settings%coeffs(1:cdft_control%natoms, iforce_eval) = cdft_control%group(1)%coeff
236 : ! Integer type settings
237 84 : IF (cdft_control%type == outer_scf_becke_constraint) THEN
238 76 : settings%si(1, iforce_eval) = cdft_control%becke_control%cutoff_type
239 76 : settings%si(2, iforce_eval) = cdft_control%becke_control%cavity_shape
240 : END IF
241 84 : settings%si(3, iforce_eval) = dft_control%multiplicity
242 84 : settings%si(4, iforce_eval) = SIZE(cdft_control%group)
243 84 : settings%si(5, iforce_eval) = cdft_control%type
244 84 : IF (cdft_control%type == outer_scf_hirshfeld_constraint) THEN
245 8 : settings%si(6, iforce_eval) = cdft_control%hirshfeld_control%shape_function
246 8 : settings%si(6, iforce_eval) = cdft_control%hirshfeld_control%gaussian_shape
247 : END IF
248 : ! Logicals
249 84 : IF (cdft_control%type == outer_scf_becke_constraint) THEN
250 76 : settings%sb(1, iforce_eval) = cdft_control%becke_control%cavity_confine
251 76 : settings%sb(2, iforce_eval) = cdft_control%becke_control%should_skip
252 76 : settings%sb(3, iforce_eval) = cdft_control%becke_control%print_cavity
253 76 : settings%sb(4, iforce_eval) = cdft_control%becke_control%in_memory
254 76 : settings%sb(5, iforce_eval) = cdft_control%becke_control%adjust
255 76 : settings%sb(8, iforce_eval) = cdft_control%becke_control%use_bohr
256 : END IF
257 84 : IF (cdft_control%type == outer_scf_hirshfeld_constraint) THEN
258 8 : settings%sb(8, iforce_eval) = cdft_control%hirshfeld_control%use_bohr
259 : END IF
260 84 : settings%sb(6, iforce_eval) = cdft_control%atomic_charges
261 84 : settings%sb(7, iforce_eval) = qs_env%has_unit_metric
262 : ! Reals
263 84 : IF (cdft_control%type == outer_scf_becke_constraint) THEN
264 76 : settings%sr(1, iforce_eval) = cdft_control%becke_control%rcavity
265 76 : settings%sr(2, iforce_eval) = cdft_control%becke_control%rglobal
266 76 : settings%sr(3, iforce_eval) = cdft_control%becke_control%eps_cavity
267 : END IF
268 84 : IF (cdft_control%type == outer_scf_hirshfeld_constraint) THEN
269 8 : settings%sr(2, iforce_eval) = cdft_control%hirshfeld_control%radius
270 : END IF
271 84 : settings%sr(4, iforce_eval) = dft_control%qs_control%eps_rho_rspace
272 84 : settings%sr(5, iforce_eval) = pw_env%cube_info(pw_env%auxbas_grid)%max_rad_ga
273 84 : IF (cdft_control%type == outer_scf_becke_constraint) THEN
274 76 : IF (cdft_control%becke_control%cutoff_type == becke_cutoff_element) THEN
275 50 : nkinds = SIZE(cdft_control%becke_control%cutoffs_tmp)
276 50 : IF (nkinds .GT. settings%max_nkinds) &
277 : CALL cp_abort(__LOCATION__, &
278 : "More than "//TRIM(cp_to_string(settings%max_nkinds))// &
279 : " unique elements were defined in BECKE_CONSTRAINT\ELEMENT_CUTOFF. Are you sure"// &
280 0 : " your input is correct? If yes, please increase max_nkinds and recompile.")
281 150 : settings%cutoffs(1:nkinds, iforce_eval) = cdft_control%becke_control%cutoffs_tmp(:)
282 : END IF
283 76 : IF (cdft_control%becke_control%adjust) THEN
284 52 : CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set)
285 52 : IF (.NOT. SIZE(atomic_kind_set) == SIZE(cdft_control%becke_control%radii_tmp)) &
286 : CALL cp_abort(__LOCATION__, &
287 : "Length of keyword BECKE_CONSTRAINT\ATOMIC_RADII does not "// &
288 0 : "match number of atomic kinds in the input coordinate file.")
289 52 : nkinds = SIZE(cdft_control%becke_control%radii_tmp)
290 52 : IF (nkinds .GT. settings%max_nkinds) &
291 : CALL cp_abort(__LOCATION__, &
292 : "More than "//TRIM(cp_to_string(settings%max_nkinds))// &
293 : " unique elements were defined in BECKE_CONSTRAINT\ATOMIC_RADII. Are you sure"// &
294 0 : " your input is correct? If yes, please increase max_nkinds and recompile.")
295 156 : settings%radii(1:nkinds, iforce_eval) = cdft_control%becke_control%radii_tmp(:)
296 : END IF
297 : END IF
298 108 : IF (cdft_control%type == outer_scf_hirshfeld_constraint) THEN
299 8 : IF (ASSOCIATED(cdft_control%hirshfeld_control%radii)) THEN
300 0 : CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set)
301 0 : IF (.NOT. SIZE(atomic_kind_set) == SIZE(cdft_control%hirshfeld_control%radii)) &
302 : CALL cp_abort(__LOCATION__, &
303 : "Length of keyword HIRSHFELD_CONSTRAINT&RADII does not "// &
304 0 : "match number of atomic kinds in the input coordinate file.")
305 0 : nkinds = SIZE(cdft_control%hirshfeld_control%radii)
306 0 : IF (nkinds .GT. settings%max_nkinds) &
307 : CALL cp_abort(__LOCATION__, &
308 : "More than "//TRIM(cp_to_string(settings%max_nkinds))// &
309 : " unique elements were defined in HIRSHFELD_CONSTRAINT&RADII. Are you sure"// &
310 0 : " your input is correct? If yes, please increase max_nkinds and recompile.")
311 0 : settings%radii(1:nkinds, iforce_eval) = cdft_control%hirshfeld_control%radii(:)
312 : END IF
313 : END IF
314 : END IF
315 : END DO
316 : ! Make sure the grids are consistent
317 408 : CALL force_env%para_env%sum(settings%grid_span)
318 1416 : CALL force_env%para_env%sum(settings%npts)
319 408 : CALL force_env%para_env%sum(settings%cutoff)
320 408 : CALL force_env%para_env%sum(settings%rel_cutoff)
321 408 : CALL force_env%para_env%sum(settings%spherical)
322 1080 : CALL force_env%para_env%sum(settings%rs_dims)
323 408 : CALL force_env%para_env%sum(settings%odd)
324 72 : is_match = .TRUE.
325 168 : DO iforce_eval = 2, nforce_eval
326 96 : is_match = is_match .AND. (settings%grid_span(1) == settings%grid_span(iforce_eval))
327 96 : is_match = is_match .AND. (settings%npts(1, 1) == settings%npts(1, iforce_eval))
328 96 : is_match = is_match .AND. (settings%cutoff(1) == settings%cutoff(iforce_eval))
329 96 : is_match = is_match .AND. (settings%rel_cutoff(1) == settings%rel_cutoff(iforce_eval))
330 96 : is_match = is_match .AND. (settings%spherical(1) == settings%spherical(iforce_eval))
331 96 : is_match = is_match .AND. (settings%rs_dims(1, 1) == settings%rs_dims(1, iforce_eval))
332 96 : is_match = is_match .AND. (settings%rs_dims(2, 1) == settings%rs_dims(2, iforce_eval))
333 168 : is_match = is_match .AND. (settings%odd(1) == settings%odd(iforce_eval))
334 : END DO
335 72 : IF (.NOT. is_match) &
336 : CALL cp_abort(__LOCATION__, &
337 0 : "Mismatch detected in the &MGRID settings of the CDFT force_evals.")
338 72 : IF (settings%spherical(1) == 1) settings%is_spherical = .TRUE.
339 72 : IF (settings%odd(1) == 1) settings%is_odd = .TRUE.
340 : ! Make sure CDFT settings are consistent
341 1156 : CALL force_env%para_env%sum(settings%atoms)
342 72 : IF (mixed_cdft%run_type == mixed_cdft_parallel) &
343 286 : CALL force_env%para_env%sum(settings%coeffs)
344 72 : settings%ncdft = 0
345 224 : DO i = 1, SIZE(settings%atoms, 1)
346 374 : DO iforce_eval = 2, nforce_eval
347 374 : IF (mixed_cdft%run_type == mixed_cdft_parallel) THEN
348 44 : IF (settings%atoms(i, 1) /= settings%atoms(i, iforce_eval)) is_match = .FALSE.
349 44 : IF (settings%coeffs(i, 1) /= settings%coeffs(i, iforce_eval)) is_match = .FALSE.
350 : END IF
351 : END DO
352 224 : IF (settings%atoms(i, 1) /= 0) settings%ncdft = settings%ncdft + 1
353 : END DO
354 72 : IF (.NOT. is_match .AND. mixed_cdft%run_type == mixed_cdft_parallel) &
355 : CALL cp_abort(__LOCATION__, &
356 : "Mismatch detected in the &CDFT section of the CDFT force_evals. "// &
357 : "Parallel mode mixed CDFT requires identical constraint definitions in both CDFT states. "// &
358 : "Switch to serial mode or disable keyword PARALLEL_BUILD if you "// &
359 0 : "want to use nonidentical constraint definitions.")
360 2424 : CALL force_env%para_env%sum(settings%si)
361 2088 : CALL force_env%para_env%sum(settings%sr)
362 648 : DO i = 1, SIZE(settings%sb, 1)
363 576 : CALL force_env%para_env%sum(settings%sb(i, 1))
364 1416 : DO iforce_eval = 2, nforce_eval
365 768 : CALL force_env%para_env%sum(settings%sb(i, iforce_eval))
366 1344 : IF (settings%sb(i, 1) .NEQV. settings%sb(i, iforce_eval)) is_match = .FALSE.
367 : END DO
368 : END DO
369 504 : DO i = 1, SIZE(settings%si, 1)
370 1080 : DO iforce_eval = 2, nforce_eval
371 1008 : IF (settings%si(i, 1) /= settings%si(i, iforce_eval)) is_match = .FALSE.
372 : END DO
373 : END DO
374 432 : DO i = 1, SIZE(settings%sr, 1)
375 912 : DO iforce_eval = 2, nforce_eval
376 840 : IF (settings%sr(i, 1) /= settings%sr(i, iforce_eval)) is_match = .FALSE.
377 : END DO
378 : END DO
379 72 : IF (.NOT. is_match) &
380 : CALL cp_abort(__LOCATION__, &
381 0 : "Mismatch detected in the &CDFT settings of the CDFT force_evals.")
382 : ! Some CDFT features are currently disabled for mixed calculations: check that these features were not requested
383 72 : IF (mixed_cdft%dlb .AND. .NOT. settings%sb(1, 1)) &
384 : CALL cp_abort(__LOCATION__, &
385 0 : "Parallel mode mixed CDFT load balancing requires Gaussian cavity confinement.")
386 : ! Check for identical constraints in case of run type serial/parallel_nobuild
387 72 : IF (mixed_cdft%run_type /= mixed_cdft_parallel) THEN
388 : ! Get array sizes
389 250 : ALLOCATE (array_sizes(nforce_eval, settings%si(4, 1), 2))
390 510 : array_sizes(:, :, :) = 0
391 174 : DO iforce_eval = 1, nforce_eval
392 124 : IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
393 122 : force_env_qs => force_env%sub_force_env(iforce_eval)%force_env
394 122 : IF (mixed_env%do_mixed_qmmm_cdft) THEN
395 8 : qs_env => force_env_qs%qmmm_env%qs_env
396 : ELSE
397 114 : CALL force_env_get(force_env_qs, qs_env=qs_env)
398 : END IF
399 122 : CALL get_qs_env(qs_env, dft_control=dft_control)
400 122 : cdft_control => dft_control%qs_control%cdft_control
401 172 : IF (force_env_qs%para_env%is_source()) THEN
402 128 : DO igroup = 1, SIZE(cdft_control%group)
403 64 : array_sizes(iforce_eval, igroup, 1) = SIZE(cdft_control%group(igroup)%atoms)
404 126 : array_sizes(iforce_eval, igroup, 2) = SIZE(cdft_control%group(igroup)%coeff)
405 : END DO
406 : END IF
407 : END DO
408 : ! Sum up array sizes and check consistency
409 50 : CALL force_env%para_env%sum(array_sizes)
410 410 : IF (ANY(array_sizes(:, :, 1) /= array_sizes(1, 1, 1)) .OR. &
411 : ANY(array_sizes(:, :, 2) /= array_sizes(1, 1, 2))) &
412 0 : mixed_cdft%identical_constraints = .FALSE.
413 : ! Check constraint definitions
414 50 : IF (mixed_cdft%identical_constraints) THEN
415 : ! Prepare temporary storage
416 380 : ALLOCATE (atoms(nforce_eval, settings%si(4, 1)))
417 330 : ALLOCATE (coeff(nforce_eval, settings%si(4, 1)))
418 200 : ALLOCATE (constraint_type(nforce_eval, settings%si(4, 1)))
419 230 : constraint_type(:, :) = 0
420 174 : DO iforce_eval = 1, nforce_eval
421 252 : DO i = 1, settings%si(4, 1)
422 128 : NULLIFY (atoms(iforce_eval, i)%array)
423 : NULLIFY (coeff(iforce_eval, i)%array)
424 384 : ALLOCATE (atoms(iforce_eval, i)%array(array_sizes(iforce_eval, i, 1)))
425 384 : ALLOCATE (coeff(iforce_eval, i)%array(array_sizes(iforce_eval, i, 1)))
426 346 : atoms(iforce_eval, i)%array(:) = 0
427 470 : coeff(iforce_eval, i)%array(:) = 0
428 : END DO
429 : ! Get constraint definitions
430 124 : IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
431 122 : force_env_qs => force_env%sub_force_env(iforce_eval)%force_env
432 122 : IF (mixed_env%do_mixed_qmmm_cdft) THEN
433 8 : qs_env => force_env_qs%qmmm_env%qs_env
434 : ELSE
435 114 : CALL force_env_get(force_env_qs, qs_env=qs_env)
436 : END IF
437 122 : CALL get_qs_env(qs_env, dft_control=dft_control)
438 122 : cdft_control => dft_control%qs_control%cdft_control
439 172 : IF (force_env_qs%para_env%is_source()) THEN
440 128 : DO i = 1, settings%si(4, 1)
441 173 : atoms(iforce_eval, i)%array(:) = cdft_control%group(i)%atoms
442 173 : coeff(iforce_eval, i)%array(:) = cdft_control%group(i)%coeff
443 126 : constraint_type(iforce_eval, i) = cdft_control%group(i)%constraint_type
444 : END DO
445 : END IF
446 : END DO
447 : ! Sum up constraint definitions and check consistency
448 100 : DO i = 1, settings%si(4, 1)
449 180 : DO iforce_eval = 1, nforce_eval
450 564 : CALL force_env%para_env%sum(atoms(iforce_eval, i)%array)
451 564 : CALL force_env%para_env%sum(coeff(iforce_eval, i)%array)
452 180 : CALL force_env%para_env%sum(constraint_type(iforce_eval, i))
453 : END DO
454 126 : DO iforce_eval = 2, nforce_eval
455 194 : DO iatom = 1, SIZE(atoms(1, i)%array)
456 120 : IF (atoms(1, i)%array(iatom) /= atoms(iforce_eval, i)%array(iatom)) &
457 0 : mixed_cdft%identical_constraints = .FALSE.
458 120 : IF (coeff(1, i)%array(iatom) /= coeff(iforce_eval, i)%array(iatom)) &
459 2 : mixed_cdft%identical_constraints = .FALSE.
460 194 : IF (.NOT. mixed_cdft%identical_constraints) EXIT
461 : END DO
462 76 : IF (constraint_type(1, i) /= constraint_type(iforce_eval, i)) &
463 0 : mixed_cdft%identical_constraints = .FALSE.
464 126 : IF (.NOT. mixed_cdft%identical_constraints) EXIT
465 : END DO
466 100 : IF (.NOT. mixed_cdft%identical_constraints) EXIT
467 : END DO
468 : ! Deallocate temporary storage
469 174 : DO iforce_eval = 1, nforce_eval
470 302 : DO i = 1, settings%si(4, 1)
471 128 : DEALLOCATE (atoms(iforce_eval, i)%array)
472 252 : DEALLOCATE (coeff(iforce_eval, i)%array)
473 : END DO
474 : END DO
475 50 : DEALLOCATE (atoms)
476 50 : DEALLOCATE (coeff)
477 50 : DEALLOCATE (constraint_type)
478 : END IF
479 50 : DEALLOCATE (array_sizes)
480 : END IF
481 : ! Deallocate some arrays that are no longer needed
482 72 : IF (mixed_cdft%identical_constraints .AND. mixed_cdft%run_type /= mixed_cdft_parallel_nobuild) THEN
483 228 : DO iforce_eval = 1, nforce_eval
484 160 : IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
485 138 : force_env_qs => force_env%sub_force_env(iforce_eval)%force_env
486 138 : IF (mixed_env%do_mixed_qmmm_cdft) THEN
487 12 : qs_env => force_env_qs%qmmm_env%qs_env
488 : ELSE
489 126 : CALL force_env_get(force_env_qs, qs_env=qs_env)
490 : END IF
491 138 : CALL get_qs_env(qs_env, dft_control=dft_control)
492 138 : cdft_control => dft_control%qs_control%cdft_control
493 206 : IF (mixed_cdft%run_type == mixed_cdft_parallel) THEN
494 22 : IF (.NOT. dft_control%qs_control%gapw) THEN
495 44 : DO i = 1, SIZE(cdft_control%group)
496 22 : DEALLOCATE (cdft_control%group(i)%coeff)
497 44 : DEALLOCATE (cdft_control%group(i)%atoms)
498 : END DO
499 22 : IF (.NOT. cdft_control%atomic_charges) DEALLOCATE (cdft_control%atoms)
500 : END IF
501 116 : ELSE IF (mixed_cdft%run_type == mixed_cdft_serial) THEN
502 116 : IF (iforce_eval == 1) CYCLE
503 142 : DO igroup = 1, SIZE(cdft_control%group)
504 142 : IF (.NOT. dft_control%qs_control%gapw) THEN
505 72 : DEALLOCATE (cdft_control%group(igroup)%coeff)
506 72 : DEALLOCATE (cdft_control%group(igroup)%atoms)
507 : END IF
508 : END DO
509 70 : IF (cdft_control%type == outer_scf_becke_constraint) THEN
510 64 : IF (.NOT. cdft_control%atomic_charges) DEALLOCATE (cdft_control%atoms)
511 64 : IF (cdft_control%becke_control%cavity_confine) &
512 62 : CALL release_hirshfeld_type(cdft_control%becke_control%cavity_env)
513 64 : IF (cdft_control%becke_control%cutoff_type == becke_cutoff_element) &
514 42 : DEALLOCATE (cdft_control%becke_control%cutoffs_tmp)
515 64 : IF (cdft_control%becke_control%adjust) &
516 44 : DEALLOCATE (cdft_control%becke_control%radii_tmp)
517 : END IF
518 : END IF
519 : END DO
520 : END IF
521 :
522 144 : END SUBROUTINE mixed_cdft_parse_settings
523 :
524 : ! **************************************************************************************************
525 : !> \brief Transfer settings to mixed_cdft
526 : !> \param force_env the force_env that holds the CDFT states
527 : !> \param mixed_cdft the control section for mixed CDFT calculations
528 : !> \param settings container for settings related to the mixed CDFT calculation
529 : !> \par History
530 : !> 01.2017 created [Nico Holmberg]
531 : ! **************************************************************************************************
532 72 : SUBROUTINE mixed_cdft_transfer_settings(force_env, mixed_cdft, settings)
533 : TYPE(force_env_type), POINTER :: force_env
534 : TYPE(mixed_cdft_type), POINTER :: mixed_cdft
535 : TYPE(mixed_cdft_settings_type) :: settings
536 :
537 : INTEGER :: i, nkinds
538 : LOGICAL :: is_match
539 : TYPE(cdft_control_type), POINTER :: cdft_control
540 :
541 72 : NULLIFY (cdft_control)
542 72 : is_match = .TRUE.
543 : ! Transfer global settings
544 72 : mixed_cdft%multiplicity = settings%si(3, 1)
545 72 : mixed_cdft%has_unit_metric = settings%sb(7, 1)
546 72 : mixed_cdft%eps_rho_rspace = settings%sr(4, 1)
547 72 : mixed_cdft%nconstraint = settings%si(4, 1)
548 72 : settings%radius = settings%sr(5, 1)
549 : ! Transfer settings only needed if the constraint should be built in parallel
550 72 : IF (mixed_cdft%run_type == mixed_cdft_parallel) THEN
551 22 : IF (settings%sb(6, 1)) &
552 : CALL cp_abort(__LOCATION__, &
553 0 : "Calculation of atomic Becke charges not supported with parallel mode mixed CDFT")
554 22 : IF (mixed_cdft%nconstraint /= 1) &
555 : CALL cp_abort(__LOCATION__, &
556 0 : "Parallel mode mixed CDFT does not yet support multiple constraints.")
557 :
558 22 : IF (settings%si(5, 1) /= outer_scf_becke_constraint) &
559 : CALL cp_abort(__LOCATION__, &
560 0 : "Parallel mode mixed CDFT does not support Hirshfeld constraints.")
561 :
562 66 : ALLOCATE (mixed_cdft%cdft_control)
563 22 : CALL cdft_control_create(mixed_cdft%cdft_control)
564 22 : cdft_control => mixed_cdft%cdft_control
565 66 : ALLOCATE (cdft_control%atoms(settings%ncdft))
566 66 : cdft_control%atoms = settings%atoms(1:settings%ncdft, 1)
567 44 : ALLOCATE (cdft_control%group(1))
568 66 : ALLOCATE (cdft_control%group(1)%atoms(settings%ncdft))
569 66 : ALLOCATE (cdft_control%group(1)%coeff(settings%ncdft))
570 22 : NULLIFY (cdft_control%group(1)%weight)
571 22 : NULLIFY (cdft_control%group(1)%gradients)
572 22 : NULLIFY (cdft_control%group(1)%integrated)
573 66 : cdft_control%group(1)%atoms = cdft_control%atoms
574 66 : cdft_control%group(1)%coeff = settings%coeffs(1:settings%ncdft, 1)
575 22 : cdft_control%natoms = settings%ncdft
576 22 : cdft_control%atomic_charges = settings%sb(6, 1)
577 22 : cdft_control%becke_control%cutoff_type = settings%si(1, 1)
578 22 : cdft_control%becke_control%cavity_confine = settings%sb(1, 1)
579 22 : cdft_control%becke_control%should_skip = settings%sb(2, 1)
580 22 : cdft_control%becke_control%print_cavity = settings%sb(3, 1)
581 22 : cdft_control%becke_control%in_memory = settings%sb(4, 1)
582 22 : cdft_control%becke_control%adjust = settings%sb(5, 1)
583 22 : cdft_control%becke_control%cavity_shape = settings%si(2, 1)
584 22 : cdft_control%becke_control%use_bohr = settings%sb(8, 1)
585 22 : cdft_control%becke_control%rcavity = settings%sr(1, 1)
586 22 : cdft_control%becke_control%rglobal = settings%sr(2, 1)
587 22 : cdft_control%becke_control%eps_cavity = settings%sr(3, 1)
588 22 : nkinds = 0
589 22 : IF (cdft_control%becke_control%cutoff_type == becke_cutoff_element) THEN
590 2250 : CALL force_env%para_env%sum(settings%cutoffs)
591 558 : DO i = 1, SIZE(settings%cutoffs, 1)
592 540 : IF (settings%cutoffs(i, 1) /= settings%cutoffs(i, 2)) is_match = .FALSE.
593 558 : IF (settings%cutoffs(i, 1) /= 0.0_dp) nkinds = nkinds + 1
594 : END DO
595 18 : IF (.NOT. is_match) &
596 : CALL cp_abort(__LOCATION__, &
597 : "Mismatch detected in the &BECKE_CONSTRAINT "// &
598 0 : "&ELEMENT_CUTOFF settings of the two force_evals.")
599 54 : ALLOCATE (cdft_control%becke_control%cutoffs_tmp(nkinds))
600 54 : cdft_control%becke_control%cutoffs_tmp = settings%cutoffs(1:nkinds, 1)
601 : END IF
602 22 : nkinds = 0
603 22 : IF (cdft_control%becke_control%adjust) THEN
604 2250 : CALL force_env%para_env%sum(settings%radii)
605 558 : DO i = 1, SIZE(settings%radii, 1)
606 540 : IF (settings%radii(i, 1) /= settings%radii(i, 2)) is_match = .FALSE.
607 558 : IF (settings%radii(i, 1) /= 0.0_dp) nkinds = nkinds + 1
608 : END DO
609 18 : IF (.NOT. is_match) &
610 : CALL cp_abort(__LOCATION__, &
611 : "Mismatch detected in the &BECKE_CONSTRAINT "// &
612 0 : "&ATOMIC_RADII settings of the two force_evals.")
613 54 : ALLOCATE (cdft_control%becke_control%radii(nkinds))
614 54 : cdft_control%becke_control%radii = settings%radii(1:nkinds, 1)
615 : END IF
616 : END IF
617 :
618 72 : END SUBROUTINE mixed_cdft_transfer_settings
619 :
620 : ! **************************************************************************************************
621 : !> \brief Initialize all the structures needed for a mixed CDFT calculation
622 : !> \param force_env the force_env that holds the CDFT mixed_env
623 : !> \param force_env_qs the force_env that holds the qs_env, which is CDFT state specific
624 : !> \param mixed_env the mixed_env that holds the CDFT states
625 : !> \param mixed_cdft the control section for mixed CDFT calculations
626 : !> \param settings container for settings related to the mixed CDFT calculation
627 : !> \par History
628 : !> 01.2017 created [Nico Holmberg]
629 : ! **************************************************************************************************
630 72 : SUBROUTINE mixed_cdft_init_structures(force_env, force_env_qs, mixed_env, mixed_cdft, settings)
631 : TYPE(force_env_type), POINTER :: force_env, force_env_qs
632 : TYPE(mixed_environment_type), POINTER :: mixed_env
633 : TYPE(mixed_cdft_type), POINTER :: mixed_cdft
634 : TYPE(mixed_cdft_settings_type) :: settings
635 :
636 : CHARACTER(len=default_path_length) :: c_val, input_file_path, output_file_path
637 : INTEGER :: i, imap, iounit, j, lp, n_force_eval, &
638 : ncpu, nforce_eval, ntargets, offset, &
639 : unit_nr
640 72 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: bounds
641 : INTEGER, DIMENSION(2, 3) :: bo, bo_mixed
642 : INTEGER, DIMENSION(3) :: higher_grid_layout
643 144 : INTEGER, DIMENSION(:), POINTER :: i_force_eval, mixed_rs_dims, recvbuffer, &
644 144 : recvbuffer2, sendbuffer
645 : LOGICAL :: is_match
646 72 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
647 : TYPE(cell_type), POINTER :: cell_mix
648 : TYPE(cp_logger_type), POINTER :: logger
649 : TYPE(cp_subsys_type), POINTER :: subsys_mix
650 : TYPE(global_environment_type), POINTER :: globenv
651 288 : TYPE(mp_request_type), DIMENSION(3) :: req
652 : TYPE(pw_env_type), POINTER :: pw_env
653 : TYPE(pw_grid_type), POINTER :: pw_grid
654 72 : TYPE(pw_pool_p_type), DIMENSION(:), POINTER :: pw_pools
655 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
656 : TYPE(qs_environment_type), POINTER :: qs_env
657 72 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
658 : TYPE(realspace_grid_desc_p_type), DIMENSION(:), &
659 72 : POINTER :: rs_descs
660 : TYPE(realspace_grid_input_type) :: input_settings
661 72 : TYPE(realspace_grid_type), DIMENSION(:), POINTER :: rs_grids
662 : TYPE(section_vals_type), POINTER :: force_env_section, force_env_sections, kind_section, &
663 : print_section, root_section, rs_grid_section, subsys_section
664 :
665 72 : NULLIFY (cell_mix, subsys_mix, force_env_section, subsys_section, &
666 72 : print_section, root_section, kind_section, force_env_sections, &
667 72 : rs_grid_section, auxbas_pw_pool, pw_env, pw_pools, pw_grid, &
668 72 : sendbuffer, qs_env, mixed_rs_dims, i_force_eval, recvbuffer, &
669 72 : recvbuffer2, globenv, atomic_kind_set, qs_kind_set, rs_descs, &
670 72 : rs_grids)
671 :
672 144 : logger => cp_get_default_logger()
673 72 : CALL force_env_get(force_env=force_env, force_env_section=force_env_section)
674 72 : print_section => section_vals_get_subs_vals(force_env_section, "MIXED%MIXED_CDFT%PRINT%PROGRAM_RUN_INFO")
675 72 : iounit = cp_print_key_unit_nr(logger, print_section, '', extension='.mixedLog')
676 72 : is_match = .TRUE.
677 72 : nforce_eval = SIZE(force_env%sub_force_env)
678 72 : ncpu = force_env%para_env%num_pe
679 : ! Get infos about the mixed subsys
680 72 : IF (.NOT. mixed_env%do_mixed_qmmm_cdft) THEN
681 : CALL force_env_get(force_env=force_env, &
682 64 : subsys=subsys_mix)
683 : ELSE
684 : CALL get_qs_env(force_env_qs%qmmm_env%qs_env, &
685 8 : cp_subsys=subsys_mix)
686 : END IF
687 : ! Init structures only needed when the CDFT states are treated in parallel
688 72 : IF (mixed_cdft%run_type == mixed_cdft_parallel) THEN
689 : ! Start building the mixed auxbas_pw_pool
690 22 : CALL pw_env_create(mixed_cdft%pw_env)
691 : ! Decide what kind of layout to use and setup the grid
692 : ! Processor mappings currently supported:
693 : ! (2np,1) --> (np,1)
694 : ! (nx,2ny) --> (nx,ny)
695 : ! (nx,ny) --> (nx*ny/2,1) (required when xc_smooth is in use and with intermediate proc counts)
696 : !
697 : ! For cases 2 and 3, dlb redistributes YZ slices from overloaded processors to underloaded processors
698 : ! For case 1, XZ slices are redistributed
699 : ! TODO: Unify mappings. Now we essentially have separate code for cases 1-2 and 3.
700 : ! This leads to very messy code especially with dlb turned on...
701 : ! In terms of memory usage, it would be beneficial to replace case 1 with 3
702 : ! and implement a similar arbitrary mapping to replace case 2
703 :
704 22 : mixed_cdft%is_pencil = .FALSE. ! Flag to control the first two mappings
705 22 : mixed_cdft%is_special = .FALSE. ! Flag to control the last mapping
706 : ! With xc smoothing, the grid is always (ncpu/2,1) distributed
707 : ! and correct behavior cannot be guaranteed for ncpu/2 > nx, so we abort...
708 22 : IF (ncpu/2 .GT. settings%npts(1, 1)) &
709 0 : CPABORT("ncpu/2 => nx: decrease ncpu or disable xc_smoothing")
710 : !
711 22 : ALLOCATE (mixed_rs_dims(2))
712 22 : IF (settings%rs_dims(2, 1) /= 1) mixed_cdft%is_pencil = .TRUE.
713 22 : IF (.NOT. mixed_cdft%is_pencil .AND. ncpu .GT. settings%npts(1, 1)) mixed_cdft%is_special = .TRUE.
714 22 : IF (mixed_cdft%is_special) THEN
715 0 : mixed_rs_dims = (/-1, -1/)
716 22 : ELSE IF (mixed_cdft%is_pencil) THEN
717 0 : mixed_rs_dims = (/settings%rs_dims(1, 1), 2*settings%rs_dims(2, 1)/)
718 : ELSE
719 66 : mixed_rs_dims = (/2*settings%rs_dims(1, 1), 1/)
720 : END IF
721 22 : IF (.NOT. mixed_env%do_mixed_qmmm_cdft) THEN
722 : CALL force_env_get(force_env=force_env, &
723 18 : cell=cell_mix)
724 : ELSE
725 : CALL get_qs_env(force_env_qs%qmmm_env%qs_env, &
726 4 : cell=cell_mix)
727 : END IF
728 : CALL pw_grid_create(pw_grid, force_env%para_env, cell_mix%hmat, grid_span=settings%grid_span(1), &
729 : npts=settings%npts(:, 1), cutoff=settings%cutoff(1), &
730 : spherical=settings%is_spherical, odd=settings%is_odd, &
731 : fft_usage=.TRUE., ncommensurate=0, icommensurate=1, &
732 : blocked=do_pw_grid_blocked_false, rs_dims=mixed_rs_dims, &
733 22 : iounit=iounit)
734 : ! Check if the layout was successfully created
735 22 : IF (mixed_cdft%is_special) THEN
736 0 : IF (.NOT. pw_grid%para%group%num_pe_cart(2) /= 1) is_match = .FALSE.
737 22 : ELSE IF (mixed_cdft%is_pencil) THEN
738 0 : IF (.NOT. pw_grid%para%group%num_pe_cart(1) == mixed_rs_dims(1)) is_match = .FALSE.
739 : ELSE
740 22 : IF (.NOT. pw_grid%para%group%num_pe_cart(2) == 1) is_match = .FALSE.
741 : END IF
742 : IF (.NOT. is_match) &
743 : CALL cp_abort(__LOCATION__, &
744 : "Unable to create a suitable grid distribution "// &
745 : "for mixed CDFT calculations. Try decreasing the total number "// &
746 0 : "of processors or disabling xc_smoothing.")
747 22 : DEALLOCATE (mixed_rs_dims)
748 : ! Create the pool
749 220 : bo_mixed = pw_grid%bounds_local
750 44 : ALLOCATE (pw_pools(1))
751 22 : NULLIFY (pw_pools(1)%pool)
752 22 : CALL pw_pool_create(pw_pools(1)%pool, pw_grid=pw_grid)
753 : ! Initialize Gaussian cavity confinement
754 22 : IF (mixed_cdft%cdft_control%becke_control%cavity_confine) THEN
755 22 : CALL create_hirshfeld_type(mixed_cdft%cdft_control%becke_control%cavity_env)
756 : CALL set_hirshfeld_info(mixed_cdft%cdft_control%becke_control%cavity_env, &
757 : shape_function_type=shape_function_gaussian, iterative=.FALSE., &
758 : radius_type=mixed_cdft%cdft_control%becke_control%cavity_shape, &
759 22 : use_bohr=mixed_cdft%cdft_control%becke_control%use_bohr)
760 : END IF
761 : ! Gaussian confinement/wavefunction overlap method needs qs_kind_set
762 : ! Gaussian cavity confinement also needs the auxbas_rs_grid
763 22 : IF (mixed_cdft%cdft_control%becke_control%cavity_confine .OR. &
764 : mixed_cdft%wfn_overlap_method) THEN
765 : print_section => section_vals_get_subs_vals(force_env_section, &
766 22 : "PRINT%GRID_INFORMATION")
767 22 : ALLOCATE (mixed_cdft%pw_env%gridlevel_info)
768 : CALL init_gaussian_gridlevel(mixed_cdft%pw_env%gridlevel_info, &
769 : ngrid_levels=1, cutoff=settings%cutoff, &
770 : rel_cutoff=settings%rel_cutoff(1), &
771 22 : print_section=print_section)
772 44 : ALLOCATE (rs_descs(1))
773 374 : ALLOCATE (rs_grids(1))
774 638 : ALLOCATE (mixed_cdft%pw_env%cube_info(1))
775 22 : higher_grid_layout = (/-1, -1, -1/)
776 22 : CALL init_d3_poly_module()
777 : CALL init_cube_info(mixed_cdft%pw_env%cube_info(1), &
778 : pw_grid%dr(:), pw_grid%dh(:, :), &
779 : pw_grid%dh_inv(:, :), &
780 22 : pw_grid%orthorhombic, settings%radius)
781 22 : NULLIFY (root_section, force_env_section, force_env_sections, rs_grid_section)
782 22 : CALL force_env_get(force_env, root_section=root_section)
783 22 : force_env_sections => section_vals_get_subs_vals(root_section, "FORCE_EVAL")
784 22 : CALL multiple_fe_list(force_env_sections, root_section, i_force_eval, n_force_eval)
785 : CALL section_vals_duplicate(force_env_sections, force_env_section, &
786 22 : i_force_eval(2), i_force_eval(2))
787 22 : rs_grid_section => section_vals_get_subs_vals(force_env_section, "DFT%MGRID%RS_GRID")
788 : CALL init_input_type(input_settings, &
789 : nsmax=2*MAX(1, return_cube_max_iradius(mixed_cdft%pw_env%cube_info(1))) + 1, &
790 : rs_grid_section=rs_grid_section, ilevel=1, &
791 22 : higher_grid_layout=higher_grid_layout)
792 22 : NULLIFY (rs_descs(1)%rs_desc)
793 22 : CALL rs_grid_create_descriptor(rs_descs(1)%rs_desc, pw_grid, input_settings)
794 22 : IF (rs_descs(1)%rs_desc%distributed) higher_grid_layout = rs_descs(1)%rs_desc%group_dim
795 22 : CALL rs_grid_create(rs_grids(1), rs_descs(1)%rs_desc)
796 22 : CALL rs_grid_print(rs_grids(1), iounit)
797 22 : mixed_cdft%pw_env%rs_descs => rs_descs
798 22 : mixed_cdft%pw_env%rs_grids => rs_grids
799 : ! qs_kind_set
800 : subsys_section => section_vals_get_subs_vals(force_env_sections, "SUBSYS", &
801 22 : i_rep_section=i_force_eval(1))
802 22 : kind_section => section_vals_get_subs_vals(subsys_section, "KIND")
803 22 : NULLIFY (qs_kind_set)
804 22 : CALL cp_subsys_get(subsys_mix, atomic_kind_set=atomic_kind_set)
805 : CALL create_qs_kind_set(qs_kind_set, atomic_kind_set, kind_section, &
806 22 : force_env%para_env, force_env_section)
807 22 : mixed_cdft%qs_kind_set => qs_kind_set
808 22 : DEALLOCATE (i_force_eval)
809 22 : CALL section_vals_release(force_env_section)
810 : END IF
811 : CALL force_env_get(force_env=force_env, &
812 22 : force_env_section=force_env_section)
813 22 : CALL pw_grid_release(pw_grid)
814 22 : mixed_cdft%pw_env%auxbas_grid = 1
815 22 : NULLIFY (mixed_cdft%pw_env%pw_pools)
816 22 : mixed_cdft%pw_env%pw_pools => pw_pools
817 220 : bo = settings%bo
818 : ! Determine which processors need to exchange data when redistributing the weight/gradient
819 22 : IF (.NOT. mixed_cdft%is_special) THEN
820 22 : ALLOCATE (mixed_cdft%dest_list(2))
821 22 : ALLOCATE (mixed_cdft%source_list(2))
822 22 : imap = force_env%para_env%mepos/2
823 66 : mixed_cdft%dest_list = (/imap, imap + force_env%para_env%num_pe/2/)
824 : imap = MOD(force_env%para_env%mepos, force_env%para_env%num_pe/2) + &
825 22 : MODULO(force_env%para_env%mepos, force_env%para_env%num_pe/2)
826 66 : mixed_cdft%source_list = (/imap, imap + 1/)
827 : ! Determine bounds of the data that is replicated
828 22 : ALLOCATE (mixed_cdft%recv_bo(4))
829 22 : ALLOCATE (sendbuffer(2), recvbuffer(2), recvbuffer2(2))
830 22 : IF (mixed_cdft%is_pencil) THEN
831 0 : sendbuffer = (/bo_mixed(1, 2), bo_mixed(2, 2)/)
832 : ELSE
833 66 : sendbuffer = (/bo_mixed(1, 1), bo_mixed(2, 1)/)
834 : END IF
835 : ! Communicate bounds in steps
836 : CALL force_env%para_env%isend(msgin=sendbuffer, dest=mixed_cdft%dest_list(1), &
837 22 : request=req(1))
838 : CALL force_env%para_env%irecv(msgout=recvbuffer, source=mixed_cdft%source_list(1), &
839 22 : request=req(2))
840 : CALL force_env%para_env%irecv(msgout=recvbuffer2, source=mixed_cdft%source_list(2), &
841 22 : request=req(3))
842 22 : CALL req(1)%wait()
843 : CALL force_env%para_env%isend(msgin=sendbuffer, dest=mixed_cdft%dest_list(2), &
844 22 : request=req(1))
845 22 : CALL mp_waitall(req)
846 110 : mixed_cdft%recv_bo(1:2) = recvbuffer
847 110 : mixed_cdft%recv_bo(3:4) = recvbuffer2
848 22 : DEALLOCATE (sendbuffer, recvbuffer, recvbuffer2)
849 : ELSE
850 0 : IF (mixed_env%do_mixed_qmmm_cdft) THEN
851 0 : qs_env => force_env_qs%qmmm_env%qs_env
852 : ELSE
853 0 : CALL force_env_get(force_env_qs, qs_env=qs_env)
854 : END IF
855 0 : CALL get_qs_env(qs_env, pw_env=pw_env)
856 0 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
857 : ! work out the pw grid points each proc holds in the two (identical) parallel proc groups
858 : ! note we only care about the x dir since we assume the y dir is not subdivided
859 0 : ALLOCATE (bounds(0:auxbas_pw_pool%pw_grid%para%group%num_pe - 1, 1:2))
860 0 : DO i = 0, auxbas_pw_pool%pw_grid%para%group%num_pe - 1
861 0 : bounds(i, 1:2) = auxbas_pw_pool%pw_grid%para%bo(1:2, 1, i, 1)
862 0 : bounds(i, 1:2) = bounds(i, 1:2) - auxbas_pw_pool%pw_grid%npts(1)/2 - 1
863 : END DO
864 : ! work out which procs to send my grid points
865 : ! first get the number of target procs per group
866 0 : ntargets = 0
867 0 : offset = -1
868 0 : DO i = 0, auxbas_pw_pool%pw_grid%para%group%num_pe - 1
869 0 : IF ((bounds(i, 1) .GE. bo_mixed(1, 1) .AND. bounds(i, 1) .LE. bo_mixed(2, 1)) .OR. &
870 0 : (bounds(i, 2) .GE. bo_mixed(1, 1) .AND. bounds(i, 2) .LE. bo_mixed(2, 1))) THEN
871 0 : ntargets = ntargets + 1
872 0 : IF (offset == -1) offset = i
873 0 : ELSE IF (bounds(i, 2) .GT. bo_mixed(2, 1)) THEN
874 : EXIT
875 : ELSE
876 0 : CYCLE
877 : END IF
878 : END DO
879 0 : ALLOCATE (mixed_cdft%dest_list(ntargets))
880 0 : ALLOCATE (mixed_cdft%dest_list_bo(2, ntargets))
881 : ! now determine the actual grid points to send
882 0 : j = 1
883 0 : DO i = offset, offset + ntargets - 1
884 0 : mixed_cdft%dest_list(j) = i
885 : mixed_cdft%dest_list_bo(:, j) = (/bo_mixed(1, 1) + (bounds(i, 1) - bo_mixed(1, 1)), &
886 0 : bo_mixed(2, 1) + (bounds(i, 2) - bo_mixed(2, 1))/)
887 0 : j = j + 1
888 : END DO
889 0 : ALLOCATE (mixed_cdft%dest_list_save(ntargets), mixed_cdft%dest_bo_save(2, ntargets))
890 : ! We need to store backups of these arrays since they might get reallocated during dlb
891 0 : mixed_cdft%dest_list_save = mixed_cdft%dest_list
892 0 : mixed_cdft%dest_bo_save = mixed_cdft%dest_list_bo
893 : ! finally determine which procs will send me grid points
894 : ! now we need info about y dir also
895 0 : DEALLOCATE (bounds)
896 0 : ALLOCATE (bounds(0:pw_pools(1)%pool%pw_grid%para%group%num_pe - 1, 1:4))
897 0 : DO i = 0, pw_pools(1)%pool%pw_grid%para%group%num_pe - 1
898 0 : bounds(i, 1:2) = pw_pools(1)%pool%pw_grid%para%bo(1:2, 1, i, 1)
899 0 : bounds(i, 3:4) = pw_pools(1)%pool%pw_grid%para%bo(1:2, 2, i, 1)
900 0 : bounds(i, 1:2) = bounds(i, 1:2) - pw_pools(1)%pool%pw_grid%npts(1)/2 - 1
901 0 : bounds(i, 3:4) = bounds(i, 3:4) - pw_pools(1)%pool%pw_grid%npts(2)/2 - 1
902 : END DO
903 0 : ntargets = 0
904 0 : offset = -1
905 0 : DO i = 0, pw_pools(1)%pool%pw_grid%para%group%num_pe - 1
906 0 : IF ((bo(1, 1) .GE. bounds(i, 1) .AND. bo(1, 1) .LE. bounds(i, 2)) .OR. &
907 0 : (bo(2, 1) .GE. bounds(i, 1) .AND. bo(2, 1) .LE. bounds(i, 2))) THEN
908 0 : ntargets = ntargets + 1
909 0 : IF (offset == -1) offset = i
910 0 : ELSE IF (bo(2, 1) .LT. bounds(i, 1)) THEN
911 : EXIT
912 : ELSE
913 0 : CYCLE
914 : END IF
915 : END DO
916 0 : ALLOCATE (mixed_cdft%source_list(ntargets))
917 0 : ALLOCATE (mixed_cdft%source_list_bo(4, ntargets))
918 0 : j = 1
919 0 : DO i = offset, offset + ntargets - 1
920 0 : mixed_cdft%source_list(j) = i
921 0 : IF (bo(1, 1) .GE. bounds(i, 1) .AND. bo(2, 1) .LE. bounds(i, 2)) THEN
922 : mixed_cdft%source_list_bo(:, j) = (/bo(1, 1), bo(2, 1), &
923 0 : bounds(i, 3), bounds(i, 4)/)
924 0 : ELSE IF (bo(1, 1) .GE. bounds(i, 1) .AND. bo(1, 1) .LE. bounds(i, 2)) THEN
925 : mixed_cdft%source_list_bo(:, j) = (/bo(1, 1), bounds(i, 2), &
926 0 : bounds(i, 3), bounds(i, 4)/)
927 : ELSE
928 : mixed_cdft%source_list_bo(:, j) = (/bounds(i, 1), bo(2, 1), &
929 0 : bounds(i, 3), bounds(i, 4)/)
930 : END IF
931 0 : j = j + 1
932 : END DO
933 0 : ALLOCATE (mixed_cdft%source_list_save(ntargets), mixed_cdft%source_bo_save(4, ntargets))
934 : ! We need to store backups of these arrays since they might get reallocated during dlb
935 0 : mixed_cdft%source_list_save = mixed_cdft%source_list
936 0 : mixed_cdft%source_bo_save = mixed_cdft%source_list_bo
937 0 : DEALLOCATE (bounds)
938 : END IF
939 : ELSE
940 : ! Create loggers to redirect the output of all CDFT states to different files
941 : ! even when the states are treated in serial (the initial print of QS data [basis set etc] for
942 : ! all states unfortunately goes to the first log file)
943 50 : CALL force_env_get(force_env, root_section=root_section)
944 224 : ALLOCATE (mixed_cdft%sub_logger(nforce_eval - 1))
945 124 : DO i = 1, nforce_eval - 1
946 74 : IF (force_env%para_env%is_source()) THEN
947 : CALL section_vals_val_get(root_section, "GLOBAL%PROJECT_NAME", &
948 37 : c_val=input_file_path)
949 37 : lp = LEN_TRIM(input_file_path)
950 37 : input_file_path(lp + 1:LEN(input_file_path)) = "-r-"//ADJUSTL(cp_to_string(i + 1))
951 37 : lp = LEN_TRIM(input_file_path)
952 37 : output_file_path = input_file_path(1:lp)//".out"
953 : CALL open_file(file_name=output_file_path, file_status="UNKNOWN", &
954 : file_action="WRITE", file_position="APPEND", &
955 37 : unit_number=unit_nr)
956 : ELSE
957 37 : unit_nr = -1
958 : END IF
959 : CALL cp_logger_create(mixed_cdft%sub_logger(i)%p, &
960 : para_env=force_env%para_env, &
961 : default_global_unit_nr=unit_nr, &
962 74 : close_global_unit_on_dealloc=.FALSE.)
963 : ! Try to use better names for the local log if it is not too late
964 : CALL section_vals_val_get(root_section, "GLOBAL%OUTPUT_FILE_NAME", &
965 74 : c_val=c_val)
966 74 : IF (c_val /= "") THEN
967 : CALL cp_logger_set(mixed_cdft%sub_logger(i)%p, &
968 0 : local_filename=TRIM(c_val)//"_localLog")
969 : END IF
970 74 : CALL section_vals_val_get(root_section, "GLOBAL%PROJECT", c_val=c_val)
971 74 : IF (c_val /= "") THEN
972 : CALL cp_logger_set(mixed_cdft%sub_logger(i)%p, &
973 74 : local_filename=TRIM(c_val)//"_localLog")
974 : END IF
975 74 : mixed_cdft%sub_logger(i)%p%iter_info%project_name = c_val
976 : CALL section_vals_val_get(root_section, "GLOBAL%PRINT_LEVEL", &
977 124 : i_val=mixed_cdft%sub_logger(i)%p%iter_info%print_level)
978 : END DO
979 50 : IF (mixed_cdft%wfn_overlap_method) THEN
980 : ! qs_kind_set
981 6 : NULLIFY (root_section, force_env_section, force_env_sections, rs_grid_section)
982 6 : CALL force_env_get(force_env, root_section=root_section)
983 6 : force_env_sections => section_vals_get_subs_vals(root_section, "FORCE_EVAL")
984 6 : CALL multiple_fe_list(force_env_sections, root_section, i_force_eval, n_force_eval)
985 : CALL section_vals_duplicate(force_env_sections, force_env_section, &
986 6 : i_force_eval(2), i_force_eval(2))
987 : subsys_section => section_vals_get_subs_vals(force_env_sections, "SUBSYS", &
988 6 : i_rep_section=i_force_eval(1))
989 6 : kind_section => section_vals_get_subs_vals(subsys_section, "KIND")
990 6 : NULLIFY (qs_kind_set)
991 6 : CALL cp_subsys_get(subsys_mix, atomic_kind_set=atomic_kind_set)
992 : CALL create_qs_kind_set(qs_kind_set, atomic_kind_set, kind_section, &
993 6 : force_env%para_env, force_env_section)
994 6 : mixed_cdft%qs_kind_set => qs_kind_set
995 6 : DEALLOCATE (i_force_eval)
996 6 : CALL section_vals_release(force_env_section)
997 6 : mixed_cdft%qs_kind_set => qs_kind_set
998 : END IF
999 : CALL force_env_get(force_env=force_env, &
1000 50 : force_env_section=force_env_section)
1001 : END IF
1002 : ! Deallocate settings temporaries
1003 72 : DEALLOCATE (settings%grid_span)
1004 72 : DEALLOCATE (settings%npts)
1005 72 : DEALLOCATE (settings%spherical)
1006 72 : DEALLOCATE (settings%rs_dims)
1007 72 : DEALLOCATE (settings%odd)
1008 72 : DEALLOCATE (settings%atoms)
1009 72 : IF (mixed_cdft%run_type == mixed_cdft_parallel) &
1010 22 : DEALLOCATE (settings%coeffs)
1011 72 : DEALLOCATE (settings%cutoffs)
1012 72 : DEALLOCATE (settings%radii)
1013 72 : DEALLOCATE (settings%si)
1014 72 : DEALLOCATE (settings%sr)
1015 72 : DEALLOCATE (settings%sb)
1016 72 : DEALLOCATE (settings%cutoff)
1017 72 : DEALLOCATE (settings%rel_cutoff)
1018 : ! Setup mixed blacs_env for redistributing arrays during ET coupling calculation
1019 72 : IF (mixed_env%do_mixed_et) THEN
1020 72 : NULLIFY (root_section)
1021 72 : CALL force_env_get(force_env, globenv=globenv, root_section=root_section)
1022 : CALL cp_blacs_env_create(mixed_cdft%blacs_env, force_env%para_env, globenv%blacs_grid_layout, &
1023 72 : globenv%blacs_repeatable)
1024 : END IF
1025 : CALL cp_print_key_finished_output(iounit, logger, force_env_section, &
1026 72 : "MIXED%MIXED_CDFT%PRINT%PROGRAM_RUN_INFO")
1027 :
1028 360 : END SUBROUTINE mixed_cdft_init_structures
1029 :
1030 : ! **************************************************************************************************
1031 : !> \brief Redistribute arrays needed for an ET coupling calculation from individual CDFT states to
1032 : !> the mixed CDFT env, that is, move the arrays to the correct blacs context. For parallel
1033 : !> simulations, the array processor distributions also change from N to 2N processors.
1034 : !> \param force_env the force_env that holds the CDFT states
1035 : !> \par History
1036 : !> 01.2017 created [Nico Holmberg]
1037 : ! **************************************************************************************************
1038 94 : SUBROUTINE mixed_cdft_redistribute_arrays(force_env)
1039 : TYPE(force_env_type), POINTER :: force_env
1040 :
1041 : INTEGER :: iforce_eval, ispin, ivar, ncol_overlap, &
1042 : ncol_wmat, nforce_eval, nrow_overlap, &
1043 : nrow_wmat, nspins, nvar
1044 94 : INTEGER, ALLOCATABLE, DIMENSION(:) :: ncol_mo, nrow_mo
1045 : LOGICAL :: uniform_occupation
1046 94 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: has_occupation_numbers
1047 94 : TYPE(cp_1d_r_p_type), ALLOCATABLE, DIMENSION(:, :) :: occno_tmp
1048 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
1049 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_mo, fm_struct_overlap, &
1050 : fm_struct_tmp, fm_struct_wmat
1051 : TYPE(cp_fm_type) :: matrix_s_tmp, mixed_matrix_s_tmp
1052 94 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :) :: matrix_p_tmp, mixed_matrix_p_tmp, &
1053 94 : mixed_wmat_tmp, mo_coeff_tmp, wmat_tmp
1054 94 : TYPE(cp_fm_type), DIMENSION(:, :), POINTER :: mixed_mo_coeff
1055 94 : TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: density_matrix, w_matrix
1056 : TYPE(dbcsr_type) :: desymm_tmp
1057 : TYPE(dbcsr_type), POINTER :: mixed_matrix_s
1058 : TYPE(dft_control_type), POINTER :: dft_control
1059 : TYPE(force_env_type), POINTER :: force_env_qs
1060 : TYPE(mixed_cdft_type), POINTER :: mixed_cdft
1061 : TYPE(mixed_environment_type), POINTER :: mixed_env
1062 : TYPE(qs_environment_type), POINTER :: qs_env
1063 :
1064 94 : NULLIFY (mixed_env, mixed_cdft, qs_env, dft_control, fm_struct_mo, &
1065 94 : fm_struct_wmat, fm_struct_overlap, fm_struct_tmp, &
1066 94 : mixed_mo_coeff, mixed_matrix_s, density_matrix, blacs_env, w_matrix, force_env_qs)
1067 0 : CPASSERT(ASSOCIATED(force_env))
1068 94 : mixed_env => force_env%mixed_env
1069 94 : nforce_eval = SIZE(force_env%sub_force_env)
1070 94 : CALL get_mixed_env(mixed_env, cdft_control=mixed_cdft)
1071 94 : CPASSERT(ASSOCIATED(mixed_cdft))
1072 94 : CALL mixed_cdft_work_type_init(mixed_cdft%matrix)
1073 : ! Get nspins and query for non-uniform occupation numbers
1074 282 : ALLOCATE (has_occupation_numbers(nforce_eval))
1075 306 : has_occupation_numbers = .FALSE.
1076 306 : DO iforce_eval = 1, nforce_eval
1077 212 : IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
1078 176 : force_env_qs => force_env%sub_force_env(iforce_eval)%force_env
1079 176 : IF (force_env%mixed_env%do_mixed_qmmm_cdft) THEN
1080 24 : qs_env => force_env_qs%qmmm_env%qs_env
1081 : ELSE
1082 152 : CALL force_env_get(force_env_qs, qs_env=qs_env)
1083 : END IF
1084 176 : CALL get_qs_env(qs_env, dft_control=dft_control)
1085 176 : CPASSERT(ASSOCIATED(dft_control))
1086 176 : nspins = dft_control%nspins
1087 176 : IF (force_env_qs%para_env%is_source()) &
1088 236 : has_occupation_numbers(iforce_eval) = ALLOCATED(dft_control%qs_control%cdft_control%occupations)
1089 : END DO
1090 94 : CALL force_env%para_env%sum(has_occupation_numbers(1))
1091 212 : DO iforce_eval = 2, nforce_eval
1092 118 : CALL force_env%para_env%sum(has_occupation_numbers(iforce_eval))
1093 118 : IF (has_occupation_numbers(1) .NEQV. has_occupation_numbers(iforce_eval)) &
1094 : CALL cp_abort(__LOCATION__, &
1095 94 : "Mixing of uniform and non-uniform occupations is not allowed.")
1096 : END DO
1097 94 : uniform_occupation = .NOT. has_occupation_numbers(1)
1098 94 : DEALLOCATE (has_occupation_numbers)
1099 : ! Get number of weight functions per state as well as the type of each constraint
1100 94 : nvar = SIZE(dft_control%qs_control%cdft_control%target)
1101 94 : IF (.NOT. ALLOCATED(mixed_cdft%constraint_type)) THEN
1102 288 : ALLOCATE (mixed_cdft%constraint_type(nvar, nforce_eval))
1103 412 : mixed_cdft%constraint_type(:, :) = 0
1104 72 : IF (mixed_cdft%identical_constraints) THEN
1105 142 : DO ivar = 1, nvar
1106 : mixed_cdft%constraint_type(ivar, :) = &
1107 310 : dft_control%qs_control%cdft_control%group(ivar)%constraint_type
1108 : END DO
1109 : ELSE
1110 : ! Possibly couple spin and charge constraints
1111 6 : DO iforce_eval = 1, nforce_eval
1112 4 : IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
1113 4 : IF (force_env%mixed_env%do_mixed_qmmm_cdft) THEN
1114 0 : qs_env => force_env%sub_force_env(iforce_eval)%force_env%qmmm_env%qs_env
1115 : ELSE
1116 4 : CALL force_env_get(force_env%sub_force_env(iforce_eval)%force_env, qs_env=qs_env)
1117 : END IF
1118 4 : CALL get_qs_env(qs_env, dft_control=dft_control)
1119 6 : IF (force_env%sub_force_env(iforce_eval)%force_env%para_env%is_source()) THEN
1120 4 : DO ivar = 1, nvar
1121 : mixed_cdft%constraint_type(ivar, iforce_eval) = &
1122 4 : dft_control%qs_control%cdft_control%group(ivar)%constraint_type
1123 : END DO
1124 : END IF
1125 : END DO
1126 2 : CALL force_env%para_env%sum(mixed_cdft%constraint_type)
1127 : END IF
1128 : END IF
1129 : ! Transfer data from sub_force_envs to temporaries
1130 988 : ALLOCATE (mixed_cdft%matrix%mixed_mo_coeff(nforce_eval, nspins))
1131 94 : mixed_mo_coeff => mixed_cdft%matrix%mixed_mo_coeff
1132 688 : ALLOCATE (mixed_cdft%matrix%w_matrix(nforce_eval, nvar))
1133 94 : w_matrix => mixed_cdft%matrix%w_matrix
1134 94 : CALL dbcsr_init_p(mixed_cdft%matrix%mixed_matrix_s)
1135 94 : mixed_matrix_s => mixed_cdft%matrix%mixed_matrix_s
1136 94 : IF (mixed_cdft%calculate_metric) THEN
1137 144 : ALLOCATE (mixed_cdft%matrix%density_matrix(nforce_eval, nspins))
1138 14 : density_matrix => mixed_cdft%matrix%density_matrix
1139 : END IF
1140 1488 : ALLOCATE (mo_coeff_tmp(nforce_eval, nspins), wmat_tmp(nforce_eval, nvar))
1141 376 : ALLOCATE (nrow_mo(nspins), ncol_mo(nspins))
1142 210 : IF (mixed_cdft%calculate_metric) ALLOCATE (matrix_p_tmp(nforce_eval, nspins))
1143 94 : IF (.NOT. uniform_occupation) THEN
1144 140 : ALLOCATE (mixed_cdft%occupations(nforce_eval, nspins))
1145 126 : ALLOCATE (occno_tmp(nforce_eval, nspins))
1146 : END IF
1147 306 : DO iforce_eval = 1, nforce_eval
1148 : ! Temporary arrays need to be nulled on every process
1149 636 : DO ispin = 1, nspins
1150 : ! Valgrind 3.12/gfortran 4.8.4 oddly complains here (unconditional jump)
1151 : ! if mixed_cdft%calculate_metric = .FALSE. and the need to null the array
1152 : ! is queried with IF (mixed_cdft%calculate_metric) &
1153 424 : IF (.NOT. uniform_occupation) &
1154 268 : NULLIFY (occno_tmp(iforce_eval, ispin)%array)
1155 : END DO
1156 212 : IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
1157 : ! From this point onward, we access data local to the sub_force_envs
1158 : ! Get qs_env
1159 176 : force_env_qs => force_env%sub_force_env(iforce_eval)%force_env
1160 176 : IF (force_env%mixed_env%do_mixed_qmmm_cdft) THEN
1161 24 : qs_env => force_env_qs%qmmm_env%qs_env
1162 : ELSE
1163 152 : CALL force_env_get(force_env_qs, qs_env=qs_env)
1164 : END IF
1165 176 : CALL get_qs_env(qs_env, dft_control=dft_control, blacs_env=blacs_env)
1166 : ! Store dimensions of the transferred arrays
1167 : CALL dbcsr_get_info(dft_control%qs_control%cdft_control%matrix_s%matrix, &
1168 176 : nfullrows_total=nrow_overlap, nfullcols_total=ncol_overlap)
1169 : CALL dbcsr_get_info(dft_control%qs_control%cdft_control%wmat(1)%matrix, &
1170 176 : nfullrows_total=nrow_wmat, nfullcols_total=ncol_wmat)
1171 : ! MO Coefficients
1172 528 : DO ispin = 1, nspins
1173 : CALL cp_fm_get_info(dft_control%qs_control%cdft_control%mo_coeff(ispin), &
1174 352 : ncol_global=ncol_mo(ispin), nrow_global=nrow_mo(ispin))
1175 : CALL cp_fm_create(matrix=mo_coeff_tmp(iforce_eval, ispin), &
1176 : matrix_struct=dft_control%qs_control%cdft_control%mo_coeff(ispin)%matrix_struct, &
1177 : name="MO_COEFF_"//TRIM(ADJUSTL(cp_to_string(iforce_eval)))//"_" &
1178 352 : //TRIM(ADJUSTL(cp_to_string(ispin)))//"_MATRIX")
1179 : CALL cp_fm_to_fm(dft_control%qs_control%cdft_control%mo_coeff(ispin), &
1180 528 : mo_coeff_tmp(iforce_eval, ispin))
1181 : END DO
1182 176 : CALL cp_fm_release(dft_control%qs_control%cdft_control%mo_coeff)
1183 : ! Matrix representation(s) of the weight function(s) (dbcsr -> fm)
1184 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nrow_wmat, ncol_global=ncol_wmat, context=blacs_env, &
1185 : para_env=force_env%sub_force_env(iforce_eval)%force_env%para_env, &
1186 176 : square_blocks=.TRUE.)
1187 356 : DO ivar = 1, nvar
1188 180 : CALL cp_fm_create(wmat_tmp(iforce_eval, ivar), fm_struct_tmp, name="w_matrix")
1189 180 : CALL dbcsr_desymmetrize(dft_control%qs_control%cdft_control%wmat(ivar)%matrix, desymm_tmp)
1190 180 : CALL copy_dbcsr_to_fm(desymm_tmp, wmat_tmp(iforce_eval, ivar))
1191 180 : CALL dbcsr_release(desymm_tmp)
1192 356 : CALL dbcsr_release_p(dft_control%qs_control%cdft_control%wmat(ivar)%matrix)
1193 : END DO
1194 176 : DEALLOCATE (dft_control%qs_control%cdft_control%wmat)
1195 176 : CALL cp_fm_struct_release(fm_struct_tmp)
1196 : ! Overlap matrix is the same for all sub_force_envs, so we just copy the first one (dbcsr -> fm)
1197 176 : IF (iforce_eval == 1) THEN
1198 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nrow_overlap, &
1199 : ncol_global=ncol_overlap, context=blacs_env, &
1200 76 : para_env=force_env%sub_force_env(iforce_eval)%force_env%para_env)
1201 76 : CALL cp_fm_create(matrix_s_tmp, fm_struct_tmp, name="s_matrix")
1202 76 : CALL cp_fm_struct_release(fm_struct_tmp)
1203 76 : CALL dbcsr_desymmetrize(dft_control%qs_control%cdft_control%matrix_s%matrix, desymm_tmp)
1204 76 : CALL copy_dbcsr_to_fm(desymm_tmp, matrix_s_tmp)
1205 76 : CALL dbcsr_release(desymm_tmp)
1206 : END IF
1207 176 : CALL dbcsr_release_p(dft_control%qs_control%cdft_control%matrix_s%matrix)
1208 : ! Density_matrix (dbcsr -> fm)
1209 176 : IF (mixed_cdft%calculate_metric) THEN
1210 72 : DO ispin = 1, nspins
1211 : ! Size AOxAO
1212 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol_overlap, &
1213 : ncol_global=ncol_overlap, context=blacs_env, &
1214 48 : para_env=force_env%sub_force_env(iforce_eval)%force_env%para_env)
1215 48 : CALL cp_fm_create(matrix_p_tmp(iforce_eval, ispin), fm_struct_tmp, name="dm_matrix")
1216 48 : CALL cp_fm_struct_release(fm_struct_tmp)
1217 48 : CALL dbcsr_desymmetrize(dft_control%qs_control%cdft_control%matrix_p(ispin)%matrix, desymm_tmp)
1218 48 : CALL copy_dbcsr_to_fm(desymm_tmp, matrix_p_tmp(iforce_eval, ispin))
1219 48 : CALL dbcsr_release(desymm_tmp)
1220 72 : CALL dbcsr_release_p(dft_control%qs_control%cdft_control%matrix_p(ispin)%matrix)
1221 : END DO
1222 24 : DEALLOCATE (dft_control%qs_control%cdft_control%matrix_p)
1223 : END IF
1224 : ! Occupation numbers
1225 446 : IF (.NOT. uniform_occupation) THEN
1226 84 : DO ispin = 1, nspins
1227 56 : IF (ncol_mo(ispin) /= SIZE(dft_control%qs_control%cdft_control%occupations(ispin)%array)) &
1228 0 : CPABORT("Array dimensions dont match.")
1229 56 : IF (force_env_qs%para_env%is_source()) THEN
1230 84 : ALLOCATE (occno_tmp(iforce_eval, ispin)%array(ncol_mo(ispin)))
1231 126 : occno_tmp(iforce_eval, ispin)%array = dft_control%qs_control%cdft_control%occupations(ispin)%array
1232 : END IF
1233 84 : DEALLOCATE (dft_control%qs_control%cdft_control%occupations(ispin)%array)
1234 : END DO
1235 28 : DEALLOCATE (dft_control%qs_control%cdft_control%occupations)
1236 : END IF
1237 : END DO
1238 : ! Create needed fm structs
1239 : CALL cp_fm_struct_create(fm_struct_wmat, nrow_global=nrow_wmat, ncol_global=ncol_wmat, &
1240 94 : context=mixed_cdft%blacs_env, para_env=force_env%para_env)
1241 : CALL cp_fm_struct_create(fm_struct_overlap, nrow_global=nrow_overlap, ncol_global=ncol_overlap, &
1242 94 : context=mixed_cdft%blacs_env, para_env=force_env%para_env)
1243 : ! Redistribute arrays with copy_general (this is not optimal for dbcsr matrices but...)
1244 : ! We use this method for the serial case (mixed_cdft%run_type == mixed_cdft_serial) as well to move the arrays to the
1245 : ! correct blacs_env, which is impossible using a simple copy of the arrays
1246 594 : ALLOCATE (mixed_wmat_tmp(nforce_eval, nvar))
1247 94 : IF (mixed_cdft%calculate_metric) &
1248 130 : ALLOCATE (mixed_matrix_p_tmp(nforce_eval, nspins))
1249 306 : DO iforce_eval = 1, nforce_eval
1250 : ! MO coefficients
1251 636 : DO ispin = 1, nspins
1252 424 : NULLIFY (fm_struct_mo)
1253 : CALL cp_fm_struct_create(fm_struct_mo, nrow_global=nrow_mo(ispin), ncol_global=ncol_mo(ispin), &
1254 424 : context=mixed_cdft%blacs_env, para_env=force_env%para_env)
1255 : CALL cp_fm_create(matrix=mixed_mo_coeff(iforce_eval, ispin), &
1256 : matrix_struct=fm_struct_mo, &
1257 : name="MO_COEFF_"//TRIM(ADJUSTL(cp_to_string(iforce_eval)))//"_" &
1258 424 : //TRIM(ADJUSTL(cp_to_string(ispin)))//"_MATRIX")
1259 : CALL cp_fm_copy_general(mo_coeff_tmp(iforce_eval, ispin), &
1260 : mixed_mo_coeff(iforce_eval, ispin), &
1261 424 : mixed_cdft%blacs_env%para_env)
1262 424 : CALL cp_fm_release(mo_coeff_tmp(iforce_eval, ispin))
1263 636 : CALL cp_fm_struct_release(fm_struct_mo)
1264 : END DO
1265 : ! Weight
1266 428 : DO ivar = 1, nvar
1267 216 : NULLIFY (w_matrix(iforce_eval, ivar)%matrix)
1268 216 : CALL dbcsr_init_p(w_matrix(iforce_eval, ivar)%matrix)
1269 : CALL cp_fm_create(matrix=mixed_wmat_tmp(iforce_eval, ivar), &
1270 : matrix_struct=fm_struct_wmat, &
1271 216 : name="WEIGHT_"//TRIM(ADJUSTL(cp_to_string(iforce_eval)))//"_MATRIX")
1272 : CALL cp_fm_copy_general(wmat_tmp(iforce_eval, ivar), &
1273 : mixed_wmat_tmp(iforce_eval, ivar), &
1274 216 : mixed_cdft%blacs_env%para_env)
1275 216 : CALL cp_fm_release(wmat_tmp(iforce_eval, ivar))
1276 : ! (fm -> dbcsr)
1277 : CALL copy_fm_to_dbcsr_bc(mixed_wmat_tmp(iforce_eval, ivar), &
1278 216 : w_matrix(iforce_eval, ivar)%matrix)
1279 428 : CALL cp_fm_release(mixed_wmat_tmp(iforce_eval, ivar))
1280 : END DO
1281 : ! Density matrix (fm -> dbcsr)
1282 306 : IF (mixed_cdft%calculate_metric) THEN
1283 90 : DO ispin = 1, nspins
1284 60 : NULLIFY (density_matrix(iforce_eval, ispin)%matrix)
1285 60 : CALL dbcsr_init_p(density_matrix(iforce_eval, ispin)%matrix)
1286 : CALL cp_fm_create(matrix=mixed_matrix_p_tmp(iforce_eval, ispin), &
1287 : matrix_struct=fm_struct_overlap, &
1288 : name="DENSITY_"//TRIM(ADJUSTL(cp_to_string(iforce_eval)))//"_"// &
1289 60 : TRIM(ADJUSTL(cp_to_string(ispin)))//"_MATRIX")
1290 : CALL cp_fm_copy_general(matrix_p_tmp(iforce_eval, ispin), &
1291 : mixed_matrix_p_tmp(iforce_eval, ispin), &
1292 60 : mixed_cdft%blacs_env%para_env)
1293 60 : CALL cp_fm_release(matrix_p_tmp(iforce_eval, ispin))
1294 : CALL copy_fm_to_dbcsr_bc(mixed_matrix_p_tmp(iforce_eval, ispin), &
1295 60 : density_matrix(iforce_eval, ispin)%matrix)
1296 90 : CALL cp_fm_release(mixed_matrix_p_tmp(iforce_eval, ispin))
1297 : END DO
1298 : END IF
1299 : END DO
1300 94 : CALL cp_fm_struct_release(fm_struct_wmat)
1301 94 : DEALLOCATE (mo_coeff_tmp, wmat_tmp, mixed_wmat_tmp)
1302 94 : IF (mixed_cdft%calculate_metric) THEN
1303 14 : DEALLOCATE (matrix_p_tmp)
1304 14 : DEALLOCATE (mixed_matrix_p_tmp)
1305 : END IF
1306 : ! Overlap (fm -> dbcsr)
1307 : CALL cp_fm_create(matrix=mixed_matrix_s_tmp, &
1308 : matrix_struct=fm_struct_overlap, &
1309 94 : name="OVERLAP_MATRIX")
1310 94 : CALL cp_fm_struct_release(fm_struct_overlap)
1311 : CALL cp_fm_copy_general(matrix_s_tmp, &
1312 : mixed_matrix_s_tmp, &
1313 94 : mixed_cdft%blacs_env%para_env)
1314 94 : CALL cp_fm_release(matrix_s_tmp)
1315 94 : CALL copy_fm_to_dbcsr_bc(mixed_matrix_s_tmp, mixed_matrix_s)
1316 94 : CALL cp_fm_release(mixed_matrix_s_tmp)
1317 : ! Occupation numbers
1318 94 : IF (.NOT. uniform_occupation) THEN
1319 42 : DO iforce_eval = 1, nforce_eval
1320 98 : DO ispin = 1, nspins
1321 168 : ALLOCATE (mixed_cdft%occupations(iforce_eval, ispin)%array(ncol_mo(ispin)))
1322 252 : mixed_cdft%occupations(iforce_eval, ispin)%array = 0.0_dp
1323 56 : IF (ASSOCIATED(occno_tmp(iforce_eval, ispin)%array)) THEN
1324 126 : mixed_cdft%occupations(iforce_eval, ispin)%array = occno_tmp(iforce_eval, ispin)%array
1325 28 : DEALLOCATE (occno_tmp(iforce_eval, ispin)%array)
1326 : END IF
1327 476 : CALL force_env%para_env%sum(mixed_cdft%occupations(iforce_eval, ispin)%array)
1328 : END DO
1329 : END DO
1330 14 : DEALLOCATE (occno_tmp)
1331 : END IF
1332 94 : DEALLOCATE (ncol_mo, nrow_mo)
1333 :
1334 282 : END SUBROUTINE mixed_cdft_redistribute_arrays
1335 : ! **************************************************************************************************
1336 : !> \brief Routine to print out the electronic coupling(s) between CDFT states.
1337 : !> \param force_env the force_env that holds the CDFT states
1338 : !> \par History
1339 : !> 11.17 created [Nico Holmberg]
1340 : ! **************************************************************************************************
1341 94 : SUBROUTINE mixed_cdft_print_couplings(force_env)
1342 : TYPE(force_env_type), POINTER :: force_env
1343 :
1344 : INTEGER :: iounit, ipermutation, istate, ivar, &
1345 : jstate, nforce_eval, npermutations, &
1346 : nvar
1347 : TYPE(cp_logger_type), POINTER :: logger
1348 : TYPE(mixed_cdft_type), POINTER :: mixed_cdft
1349 : TYPE(section_vals_type), POINTER :: force_env_section, print_section
1350 :
1351 94 : NULLIFY (print_section, mixed_cdft)
1352 :
1353 94 : logger => cp_get_default_logger()
1354 94 : CPASSERT(ASSOCIATED(force_env))
1355 : CALL force_env_get(force_env=force_env, &
1356 94 : force_env_section=force_env_section)
1357 94 : CALL get_mixed_env(force_env%mixed_env, cdft_control=mixed_cdft)
1358 94 : CPASSERT(ASSOCIATED(mixed_cdft))
1359 94 : print_section => section_vals_get_subs_vals(force_env_section, "MIXED%MIXED_CDFT%PRINT%PROGRAM_RUN_INFO")
1360 94 : iounit = cp_print_key_unit_nr(logger, print_section, '', extension='.mixedLog')
1361 : !
1362 94 : CPASSERT(ALLOCATED(mixed_cdft%results%strength))
1363 94 : CPASSERT(ALLOCATED(mixed_cdft%results%W_diagonal))
1364 94 : CPASSERT(ALLOCATED(mixed_cdft%results%S))
1365 94 : CPASSERT(ALLOCATED(mixed_cdft%results%energy))
1366 94 : nforce_eval = SIZE(force_env%sub_force_env)
1367 94 : nvar = SIZE(mixed_cdft%results%strength, 1)
1368 94 : npermutations = nforce_eval*(nforce_eval - 1)/2 ! Size of upper triangular part
1369 94 : IF (iounit > 0) THEN
1370 : WRITE (iounit, '(/,T3,A,T66)') &
1371 47 : '------------------------- CDFT coupling information --------------------------'
1372 : WRITE (iounit, '(T3,A,T66,(3X,F12.2))') &
1373 47 : 'Information at step (fs):', mixed_cdft%sim_step*mixed_cdft%sim_dt
1374 135 : DO ipermutation = 1, npermutations
1375 88 : CALL map_permutation_to_states(nforce_eval, ipermutation, istate, jstate)
1376 88 : WRITE (iounit, '(/,T3,A)') REPEAT('#', 44)
1377 88 : WRITE (iounit, '(T3,A,I3,A,I3,A)') '###### CDFT states I =', istate, ' and J = ', jstate, ' ######'
1378 88 : WRITE (iounit, '(T3,A)') REPEAT('#', 44)
1379 177 : DO ivar = 1, nvar
1380 89 : IF (ivar > 1) &
1381 1 : WRITE (iounit, '(A)') ''
1382 89 : WRITE (iounit, '(T3,A,T60,(3X,I18))') 'Atomic group:', ivar
1383 : WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
1384 89 : 'Strength of constraint I:', mixed_cdft%results%strength(ivar, istate)
1385 : WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
1386 89 : 'Strength of constraint J:', mixed_cdft%results%strength(ivar, jstate)
1387 : WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
1388 89 : 'Final value of constraint I:', mixed_cdft%results%W_diagonal(ivar, istate)
1389 : WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
1390 177 : 'Final value of constraint J:', mixed_cdft%results%W_diagonal(ivar, jstate)
1391 : END DO
1392 : WRITE (iounit, '(/,T3,A,T60,(3X,F18.12))') &
1393 88 : 'Overlap between states I and J:', mixed_cdft%results%S(istate, jstate)
1394 : WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
1395 88 : 'Charge transfer energy (J-I) (Hartree):', (mixed_cdft%results%energy(jstate) - mixed_cdft%results%energy(istate))
1396 88 : WRITE (iounit, *)
1397 88 : IF (ALLOCATED(mixed_cdft%results%rotation)) THEN
1398 86 : IF (ABS(mixed_cdft%results%rotation(ipermutation))*1.0E3_dp .GE. 0.1_dp) THEN
1399 : WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
1400 85 : 'Diabatic electronic coupling (rotation, mHartree):', &
1401 170 : ABS(mixed_cdft%results%rotation(ipermutation)*1.0E3_dp)
1402 : ELSE
1403 : WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
1404 1 : 'Diabatic electronic coupling (rotation, microHartree):', &
1405 2 : ABS(mixed_cdft%results%rotation(ipermutation)*1.0E6_dp)
1406 : END IF
1407 : END IF
1408 88 : IF (ALLOCATED(mixed_cdft%results%lowdin)) THEN
1409 10 : IF (ABS(mixed_cdft%results%lowdin(ipermutation))*1.0E3_dp .GE. 0.1_dp) THEN
1410 : WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
1411 9 : 'Diabatic electronic coupling (Lowdin, mHartree):', &
1412 18 : ABS(mixed_cdft%results%lowdin(ipermutation)*1.0E3_dp)
1413 : ELSE
1414 : WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
1415 1 : 'Diabatic electronic coupling (Lowdin, microHartree):', &
1416 2 : ABS(mixed_cdft%results%lowdin(ipermutation)*1.0E6_dp)
1417 : END IF
1418 : END IF
1419 88 : IF (ALLOCATED(mixed_cdft%results%wfn)) THEN
1420 6 : IF (mixed_cdft%results%wfn(ipermutation)*1.0E3_dp .GE. 0.1_dp) THEN
1421 : WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
1422 5 : 'Diabatic electronic coupling (wfn overlap, mHartree):', &
1423 10 : ABS(mixed_cdft%results%wfn(ipermutation)*1.0E3_dp)
1424 : ELSE
1425 : WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
1426 1 : 'Diabatic electronic coupling (wfn overlap, microHartree):', &
1427 2 : ABS(mixed_cdft%results%wfn(ipermutation)*1.0E6_dp)
1428 : END IF
1429 : END IF
1430 88 : IF (ALLOCATED(mixed_cdft%results%nonortho)) THEN
1431 : WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
1432 50 : 'Diabatic electronic coupling (nonorthogonal, Hartree):', mixed_cdft%results%nonortho(ipermutation)
1433 : END IF
1434 223 : IF (ALLOCATED(mixed_cdft%results%metric)) THEN
1435 9 : WRITE (iounit, *)
1436 9 : IF (SIZE(mixed_cdft%results%metric, 2) == 1) THEN
1437 : WRITE (iounit, '(T3,A,T66,(3X,F12.6))') &
1438 0 : 'Coupling reliability metric (0 is ideal):', mixed_cdft%results%metric(ipermutation, 1)
1439 : ELSE
1440 : WRITE (iounit, '(T3,A,T54,(3X,2F12.6))') &
1441 9 : 'Coupling reliability metric (0 is ideal):', &
1442 18 : mixed_cdft%results%metric(ipermutation, 1), mixed_cdft%results%metric(ipermutation, 2)
1443 : END IF
1444 : END IF
1445 : END DO
1446 : WRITE (iounit, '(T3,A)') &
1447 47 : '------------------------------------------------------------------------------'
1448 : END IF
1449 : CALL cp_print_key_finished_output(iounit, logger, force_env_section, &
1450 94 : "MIXED%MIXED_CDFT%PRINT%PROGRAM_RUN_INFO")
1451 :
1452 94 : END SUBROUTINE mixed_cdft_print_couplings
1453 :
1454 : ! **************************************************************************************************
1455 : !> \brief Release storage reserved for mixed CDFT matrices
1456 : !> \param force_env the force_env that holds the CDFT states
1457 : !> \par History
1458 : !> 11.17 created [Nico Holmberg]
1459 : ! **************************************************************************************************
1460 94 : SUBROUTINE mixed_cdft_release_work(force_env)
1461 : TYPE(force_env_type), POINTER :: force_env
1462 :
1463 : TYPE(mixed_cdft_type), POINTER :: mixed_cdft
1464 :
1465 94 : NULLIFY (mixed_cdft)
1466 :
1467 94 : CPASSERT(ASSOCIATED(force_env))
1468 94 : CALL get_mixed_env(force_env%mixed_env, cdft_control=mixed_cdft)
1469 94 : CPASSERT(ASSOCIATED(mixed_cdft))
1470 94 : CALL mixed_cdft_result_type_release(mixed_cdft%results)
1471 :
1472 94 : END SUBROUTINE mixed_cdft_release_work
1473 :
1474 : ! **************************************************************************************************
1475 : !> \brief Given the size of a symmetric matrix and a permutation index, returns indices (i, j) of the
1476 : !> off-diagonal element that corresponds to the permutation index. Assumes that the permutation
1477 : !> index was computed by going through the upper triangular part of the input matrix row-by-row.
1478 : !> \param n the size of the symmetric matrix
1479 : !> \param ipermutation the permutation index
1480 : !> \param i the row index corresponding to ipermutation
1481 : !> \param j the column index corresponding to ipermutation
1482 : ! **************************************************************************************************
1483 1248 : SUBROUTINE map_permutation_to_states(n, ipermutation, i, j)
1484 : INTEGER, INTENT(IN) :: n, ipermutation
1485 : INTEGER, INTENT(OUT) :: i, j
1486 :
1487 : INTEGER :: kcol, kpermutation, krow, npermutations
1488 :
1489 1248 : npermutations = n*(n - 1)/2 ! Size of upper triangular part
1490 1248 : IF (ipermutation > npermutations) &
1491 0 : CPABORT("Permutation index out of bounds")
1492 1248 : kpermutation = 0
1493 2124 : DO krow = 1, n
1494 7566 : DO kcol = krow + 1, n
1495 6690 : kpermutation = kpermutation + 1
1496 7566 : IF (kpermutation == ipermutation) THEN
1497 1248 : i = krow
1498 1248 : j = kcol
1499 1248 : RETURN
1500 : END IF
1501 : END DO
1502 : END DO
1503 :
1504 : END SUBROUTINE map_permutation_to_states
1505 :
1506 : ! **************************************************************************************************
1507 : !> \brief Determine confinement bounds along confinement dir (hardcoded to be z)
1508 : !> and determine the number of nonzero entries
1509 : !> Optionally zero entries below a given threshold
1510 : !> \param fun input 3D potential (real space)
1511 : !> \param th threshold for screening values
1512 : !> \param just_zero determines if fun should only be zeroed without returning bounds/work
1513 : !> \param bounds the confinement bounds: fun is nonzero only between these values along 3rd dimension
1514 : !> \param work an estimate of the total number of grid points where fun is nonzero
1515 : ! **************************************************************************************************
1516 34 : SUBROUTINE hfun_zero(fun, th, just_zero, bounds, work)
1517 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(INOUT) :: fun
1518 : REAL(KIND=dp), INTENT(IN) :: th
1519 : LOGICAL :: just_zero
1520 : INTEGER, OPTIONAL :: bounds(2), work
1521 :
1522 : INTEGER :: i1, i2, i3, lb, n1, n2, n3, nzeroed, &
1523 : nzeroed_total, ub
1524 : LOGICAL :: lb_final, ub_final
1525 :
1526 34 : n1 = SIZE(fun, 1)
1527 34 : n2 = SIZE(fun, 2)
1528 34 : n3 = SIZE(fun, 3)
1529 34 : nzeroed_total = 0
1530 34 : IF (.NOT. just_zero) THEN
1531 34 : CPASSERT(PRESENT(bounds))
1532 34 : CPASSERT(PRESENT(work))
1533 : lb = 1
1534 : lb_final = .FALSE.
1535 : ub_final = .FALSE.
1536 : END IF
1537 1586 : DO i3 = 1, n3
1538 1552 : IF (.NOT. just_zero) nzeroed = 0
1539 75920 : DO i2 = 1, n2
1540 1956496 : DO i1 = 1, n1
1541 1954944 : IF (fun(i1, i2, i3) < th) THEN
1542 983300 : IF (.NOT. just_zero) THEN
1543 983300 : nzeroed = nzeroed + 1
1544 983300 : nzeroed_total = nzeroed_total + 1
1545 : ELSE
1546 0 : fun(i1, i2, i3) = 0.0_dp
1547 : END IF
1548 : END IF
1549 : END DO
1550 : END DO
1551 1586 : IF (.NOT. just_zero) THEN
1552 1552 : IF (nzeroed == (n2*n1)) THEN
1553 80 : IF (.NOT. lb_final) THEN
1554 : lb = i3
1555 56 : ELSE IF (.NOT. ub_final) THEN
1556 8 : ub = i3
1557 8 : ub_final = .TRUE.
1558 : END IF
1559 : ELSE
1560 : IF (.NOT. lb_final) lb_final = .TRUE.
1561 : IF (ub_final) ub_final = .FALSE. ! Safeguard against "holes"
1562 : END IF
1563 : END IF
1564 : END DO
1565 34 : IF (.NOT. just_zero) THEN
1566 34 : IF (.NOT. ub_final) ub = n3
1567 34 : bounds(1) = lb
1568 34 : bounds(2) = ub
1569 102 : bounds = bounds - (n3/2) - 1
1570 34 : work = n3*n2*n1 - nzeroed_total
1571 : END IF
1572 :
1573 34 : END SUBROUTINE hfun_zero
1574 :
1575 : ! **************************************************************************************************
1576 : !> \brief Read input section related to block diagonalization of the mixed CDFT Hamiltonian matrix.
1577 : !> \param force_env the force_env that holds the CDFT states
1578 : !> \param blocks list of CDFT states defining the matrix blocks
1579 : !> \param ignore_excited flag that determines if excited states resulting from the block
1580 : !> diagonalization process should be ignored
1581 : !> \param nrecursion integer that determines how many steps of recursive block diagonalization
1582 : !> is performed (1 if disabled)
1583 : !> \par History
1584 : !> 01.18 created [Nico Holmberg]
1585 : ! **************************************************************************************************
1586 8 : SUBROUTINE mixed_cdft_read_block_diag(force_env, blocks, ignore_excited, nrecursion)
1587 : TYPE(force_env_type), POINTER :: force_env
1588 : TYPE(cp_1d_i_p_type), ALLOCATABLE, DIMENSION(:), &
1589 : INTENT(OUT) :: blocks
1590 : LOGICAL, INTENT(OUT) :: ignore_excited
1591 : INTEGER, INTENT(OUT) :: nrecursion
1592 :
1593 : INTEGER :: i, j, k, l, nblk, nforce_eval
1594 8 : INTEGER, DIMENSION(:), POINTER :: tmplist
1595 : LOGICAL :: do_recursive, explicit, has_duplicates
1596 : TYPE(section_vals_type), POINTER :: block_section, force_env_section
1597 :
1598 : EXTERNAL :: dsygv
1599 :
1600 8 : NULLIFY (force_env_section, block_section)
1601 0 : CPASSERT(ASSOCIATED(force_env))
1602 8 : nforce_eval = SIZE(force_env%sub_force_env)
1603 :
1604 : CALL force_env_get(force_env=force_env, &
1605 8 : force_env_section=force_env_section)
1606 8 : block_section => section_vals_get_subs_vals(force_env_section, "MIXED%MIXED_CDFT%BLOCK_DIAGONALIZE")
1607 :
1608 8 : CALL section_vals_get(block_section, explicit=explicit)
1609 8 : IF (.NOT. explicit) &
1610 : CALL cp_abort(__LOCATION__, &
1611 : "Block diagonalization of CDFT Hamiltonian was requested, but the "// &
1612 0 : "corresponding input section is missing!")
1613 :
1614 8 : CALL section_vals_val_get(block_section, "BLOCK", n_rep_val=nblk)
1615 44 : ALLOCATE (blocks(nblk))
1616 28 : DO i = 1, nblk
1617 20 : NULLIFY (blocks(i)%array)
1618 20 : CALL section_vals_val_get(block_section, "BLOCK", i_rep_val=i, i_vals=tmplist)
1619 20 : IF (SIZE(tmplist) < 1) &
1620 0 : CPABORT("Each BLOCK must contain at least 1 state.")
1621 60 : ALLOCATE (blocks(i)%array(SIZE(tmplist)))
1622 66 : blocks(i)%array(:) = tmplist(:)
1623 : END DO
1624 8 : CALL section_vals_val_get(block_section, "IGNORE_EXCITED", l_val=ignore_excited)
1625 8 : CALL section_vals_val_get(block_section, "RECURSIVE_DIAGONALIZATION", l_val=do_recursive)
1626 : ! Check that the requested states exist
1627 28 : DO i = 1, nblk
1628 66 : DO j = 1, SIZE(blocks(i)%array)
1629 38 : IF (blocks(i)%array(j) < 1 .OR. blocks(i)%array(j) > nforce_eval) &
1630 20 : CPABORT("Requested state does not exist.")
1631 : END DO
1632 : END DO
1633 : ! Check for duplicates
1634 8 : has_duplicates = .FALSE.
1635 28 : DO i = 1, nblk
1636 : ! Within same block
1637 58 : DO j = 1, SIZE(blocks(i)%array)
1638 76 : DO k = j + 1, SIZE(blocks(i)%array)
1639 56 : IF (blocks(i)%array(j) == blocks(i)%array(k)) has_duplicates = .TRUE.
1640 : END DO
1641 : END DO
1642 : ! Within different blocks
1643 46 : DO j = i + 1, nblk
1644 74 : DO k = 1, SIZE(blocks(i)%array)
1645 122 : DO l = 1, SIZE(blocks(j)%array)
1646 104 : IF (blocks(i)%array(k) == blocks(j)%array(l)) has_duplicates = .TRUE.
1647 : END DO
1648 : END DO
1649 : END DO
1650 : END DO
1651 8 : IF (has_duplicates) CPABORT("Duplicate states are not allowed.")
1652 8 : nrecursion = 1
1653 8 : IF (do_recursive) THEN
1654 2 : IF (MODULO(nblk, 2) /= 0) THEN
1655 : CALL cp_warn(__LOCATION__, &
1656 : "Number of blocks not divisible with 2. Recursive diagonalization not possible. "// &
1657 0 : "Calculation proceeds without.")
1658 0 : nrecursion = 1
1659 : ELSE
1660 2 : nrecursion = nblk/2
1661 : END IF
1662 2 : IF (nrecursion /= 1 .AND. .NOT. ignore_excited) &
1663 : CALL cp_abort(__LOCATION__, &
1664 0 : "Keyword IGNORE_EXCITED must be active for recursive diagonalization.")
1665 : END IF
1666 :
1667 32 : END SUBROUTINE mixed_cdft_read_block_diag
1668 :
1669 : ! **************************************************************************************************
1670 : !> \brief Assembles the matrix blocks from the mixed CDFT Hamiltonian.
1671 : !> \param mixed_cdft the env that holds the CDFT states
1672 : !> \param blocks list of CDFT states defining the matrix blocks
1673 : !> \param H_block list of Hamiltonian matrix blocks
1674 : !> \param S_block list of overlap matrix blocks
1675 : !> \par History
1676 : !> 01.18 created [Nico Holmberg]
1677 : ! **************************************************************************************************
1678 10 : SUBROUTINE mixed_cdft_get_blocks(mixed_cdft, blocks, H_block, S_block)
1679 : TYPE(mixed_cdft_type), POINTER :: mixed_cdft
1680 : TYPE(cp_1d_i_p_type), ALLOCATABLE, DIMENSION(:) :: blocks
1681 : TYPE(cp_2d_r_p_type), ALLOCATABLE, DIMENSION(:), &
1682 : INTENT(OUT) :: H_block, S_block
1683 :
1684 : INTEGER :: i, icol, irow, j, k, nblk
1685 :
1686 : EXTERNAL :: dsygv
1687 :
1688 10 : CPASSERT(ASSOCIATED(mixed_cdft))
1689 :
1690 10 : nblk = SIZE(blocks)
1691 98 : ALLOCATE (H_block(nblk), S_block(nblk))
1692 34 : DO i = 1, nblk
1693 24 : NULLIFY (H_block(i)%array)
1694 24 : NULLIFY (S_block(i)%array)
1695 96 : ALLOCATE (H_block(i)%array(SIZE(blocks(i)%array), SIZE(blocks(i)%array)))
1696 96 : ALLOCATE (S_block(i)%array(SIZE(blocks(i)%array), SIZE(blocks(i)%array)))
1697 24 : icol = 0
1698 70 : DO j = 1, SIZE(blocks(i)%array)
1699 46 : irow = 0
1700 46 : icol = icol + 1
1701 160 : DO k = 1, SIZE(blocks(i)%array)
1702 90 : irow = irow + 1
1703 90 : H_block(i)%array(irow, icol) = mixed_cdft%results%H(blocks(i)%array(k), blocks(i)%array(j))
1704 136 : S_block(i)%array(irow, icol) = mixed_cdft%results%S(blocks(i)%array(k), blocks(i)%array(j))
1705 : END DO
1706 : END DO
1707 : ! Check that none of the interaction energies is repulsive
1708 160 : IF (ANY(H_block(i)%array .GE. 0.0_dp)) &
1709 : CALL cp_abort(__LOCATION__, &
1710 : "At least one of the interaction energies within block "//TRIM(ADJUSTL(cp_to_string(i)))// &
1711 10 : " is repulsive.")
1712 : END DO
1713 :
1714 10 : END SUBROUTINE mixed_cdft_get_blocks
1715 :
1716 : ! **************************************************************************************************
1717 : !> \brief Diagonalizes each of the matrix blocks.
1718 : !> \param blocks list of CDFT states defining the matrix blocks
1719 : !> \param H_block list of Hamiltonian matrix blocks
1720 : !> \param S_block list of overlap matrix blocks
1721 : !> \param eigenvalues list of eigenvalues for each block
1722 : !> \par History
1723 : !> 01.18 created [Nico Holmberg]
1724 : ! **************************************************************************************************
1725 10 : SUBROUTINE mixed_cdft_diagonalize_blocks(blocks, H_block, S_block, eigenvalues)
1726 : TYPE(cp_1d_i_p_type), ALLOCATABLE, DIMENSION(:) :: blocks
1727 : TYPE(cp_2d_r_p_type), ALLOCATABLE, DIMENSION(:) :: H_block, S_block
1728 : TYPE(cp_1d_r_p_type), ALLOCATABLE, DIMENSION(:), &
1729 : INTENT(OUT) :: eigenvalues
1730 :
1731 : INTEGER :: i, info, nblk, work_array_size
1732 10 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: work
1733 10 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: H_mat_copy, S_mat_copy
1734 :
1735 : EXTERNAL :: dsygv
1736 :
1737 10 : nblk = SIZE(blocks)
1738 54 : ALLOCATE (eigenvalues(nblk))
1739 34 : DO i = 1, nblk
1740 24 : NULLIFY (eigenvalues(i)%array)
1741 72 : ALLOCATE (eigenvalues(i)%array(SIZE(blocks(i)%array)))
1742 70 : eigenvalues(i)%array = 0.0_dp
1743 : ! Workspace query
1744 24 : ALLOCATE (work(1))
1745 24 : info = 0
1746 96 : ALLOCATE (H_mat_copy(SIZE(blocks(i)%array), SIZE(blocks(i)%array)))
1747 72 : ALLOCATE (S_mat_copy(SIZE(blocks(i)%array), SIZE(blocks(i)%array)))
1748 160 : H_mat_copy(:, :) = H_block(i)%array(:, :) ! Need explicit copies because dsygv destroys original values
1749 160 : S_mat_copy(:, :) = S_block(i)%array(:, :)
1750 : CALL dsygv(1, 'V', 'U', SIZE(blocks(i)%array), H_mat_copy, SIZE(blocks(i)%array), &
1751 24 : S_mat_copy, SIZE(blocks(i)%array), eigenvalues(i)%array, work, -1, info)
1752 24 : work_array_size = NINT(work(1))
1753 24 : DEALLOCATE (H_mat_copy, S_mat_copy)
1754 : ! Allocate work array
1755 24 : DEALLOCATE (work)
1756 72 : ALLOCATE (work(work_array_size))
1757 1588 : work = 0.0_dp
1758 : ! Solve Hc = eSc
1759 24 : info = 0
1760 : CALL dsygv(1, 'V', 'U', SIZE(blocks(i)%array), H_block(i)%array, SIZE(blocks(i)%array), &
1761 24 : S_block(i)%array, SIZE(blocks(i)%array), eigenvalues(i)%array, work, work_array_size, info)
1762 24 : IF (info /= 0) THEN
1763 0 : IF (info > SIZE(blocks(i)%array)) THEN
1764 0 : CPABORT("Matrix S is not positive definite")
1765 : ELSE
1766 0 : CPABORT("Diagonalization of H matrix failed.")
1767 : END IF
1768 : END IF
1769 34 : DEALLOCATE (work)
1770 : END DO
1771 :
1772 10 : END SUBROUTINE mixed_cdft_diagonalize_blocks
1773 :
1774 : ! **************************************************************************************************
1775 : !> \brief Assembles the new block diagonalized mixed CDFT Hamiltonian and overlap matrices.
1776 : !> \param mixed_cdft the env that holds the CDFT states
1777 : !> \param blocks list of CDFT states defining the matrix blocks
1778 : !> \param H_block list of Hamiltonian matrix blocks
1779 : !> \param eigenvalues list of eigenvalues for each block
1780 : !> \param n size of the new Hamiltonian and overlap matrices
1781 : !> \param iounit the output unit
1782 : !> \par History
1783 : !> 01.18 created [Nico Holmberg]
1784 : ! **************************************************************************************************
1785 10 : SUBROUTINE mixed_cdft_assemble_block_diag(mixed_cdft, blocks, H_block, eigenvalues, &
1786 : n, iounit)
1787 : TYPE(mixed_cdft_type), POINTER :: mixed_cdft
1788 : TYPE(cp_1d_i_p_type), ALLOCATABLE, DIMENSION(:) :: blocks
1789 : TYPE(cp_2d_r_p_type), ALLOCATABLE, DIMENSION(:) :: H_block
1790 : TYPE(cp_1d_r_p_type), ALLOCATABLE, DIMENSION(:) :: eigenvalues
1791 : INTEGER :: n, iounit
1792 :
1793 : CHARACTER(LEN=20) :: ilabel, jlabel
1794 : CHARACTER(LEN=3) :: tmp
1795 : INTEGER :: i, icol, ipermutation, irow, j, k, l, &
1796 : nblk, npermutations
1797 : LOGICAL :: ignore_excited
1798 10 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: H_mat, H_offdiag, S_mat, S_offdiag
1799 :
1800 : EXTERNAL :: dsygv
1801 :
1802 60 : ALLOCATE (H_mat(n, n), S_mat(n, n))
1803 10 : nblk = SIZE(blocks)
1804 10 : ignore_excited = (nblk == n)
1805 : ! The diagonal contains the eigenvalues of each block
1806 10 : IF (iounit > 0) WRITE (iounit, '(/,T3,A)') "Eigenvalues of the block diagonalized states"
1807 126 : H_mat(:, :) = 0.0_dp
1808 126 : S_mat(:, :) = 0.0_dp
1809 10 : k = 1
1810 34 : DO i = 1, nblk
1811 24 : IF (iounit > 0) WRITE (iounit, '(T6,A,I3)') "Block", i
1812 42 : DO j = 1, SIZE(eigenvalues(i)%array)
1813 28 : H_mat(k, k) = eigenvalues(i)%array(j)
1814 28 : S_mat(k, k) = 1.0_dp
1815 28 : k = k + 1
1816 28 : IF (iounit > 0) THEN
1817 14 : IF (j == 1) THEN
1818 12 : WRITE (iounit, '(T9,A,T58,(3X,F20.14))') 'Ground state energy:', eigenvalues(i)%array(j)
1819 : ELSE
1820 : WRITE (iounit, '(T9,A,I2,A,T58,(3X,F20.14))') &
1821 2 : 'Excited state (', j - 1, ' ) energy:', eigenvalues(i)%array(j)
1822 : END IF
1823 : END IF
1824 32 : IF (ignore_excited .AND. j == 1) EXIT
1825 : END DO
1826 : END DO
1827 : ! Transform the off-diagonal blocks using the eigenvectors of each block
1828 10 : npermutations = nblk*(nblk - 1)/2
1829 10 : IF (iounit > 0) WRITE (iounit, '(/,T3,A)') "Interactions between block diagonalized states"
1830 30 : DO ipermutation = 1, npermutations
1831 20 : CALL map_permutation_to_states(nblk, ipermutation, i, j)
1832 : ! Get the untransformed off-diagonal block
1833 80 : ALLOCATE (H_offdiag(SIZE(blocks(i)%array), SIZE(blocks(j)%array)))
1834 60 : ALLOCATE (S_offdiag(SIZE(blocks(i)%array), SIZE(blocks(j)%array)))
1835 58 : icol = 0
1836 58 : DO k = 1, SIZE(blocks(j)%array)
1837 38 : irow = 0
1838 38 : icol = icol + 1
1839 134 : DO l = 1, SIZE(blocks(i)%array)
1840 76 : irow = irow + 1
1841 76 : H_offdiag(irow, icol) = mixed_cdft%results%H(blocks(i)%array(l), blocks(j)%array(k))
1842 114 : S_offdiag(irow, icol) = mixed_cdft%results%S(blocks(i)%array(l), blocks(j)%array(k))
1843 : END DO
1844 : END DO
1845 : ! Check that none of the interaction energies is repulsive
1846 134 : IF (ANY(H_offdiag .GE. 0.0_dp)) &
1847 : CALL cp_abort(__LOCATION__, &
1848 : "At least one of the interaction energies between blocks "//TRIM(ADJUSTL(cp_to_string(i)))// &
1849 0 : " and "//TRIM(ADJUSTL(cp_to_string(j)))//" is repulsive.")
1850 : ! Now transform: C_i^T * H * C_j
1851 952 : H_offdiag(:, :) = MATMUL(H_offdiag, H_block(j)%array)
1852 972 : H_offdiag(:, :) = MATMUL(TRANSPOSE(H_block(i)%array), H_offdiag)
1853 952 : S_offdiag(:, :) = MATMUL(S_offdiag, H_block(j)%array)
1854 972 : S_offdiag(:, :) = MATMUL(TRANSPOSE(H_block(i)%array), S_offdiag)
1855 : ! Make sure the transformation preserves the sign of elements in the S and H matrices
1856 : ! The S/H matrices contain only positive/negative values so that any sign flipping occurs in the
1857 : ! same elements in both matrices
1858 : ! Check for sign flipping using the S matrix
1859 30 : IF (ANY(S_offdiag .LT. 0.0_dp)) THEN
1860 58 : DO l = 1, SIZE(S_offdiag, 2)
1861 134 : DO k = 1, SIZE(S_offdiag, 1)
1862 114 : IF (S_offdiag(k, l) .LT. 0.0_dp) THEN
1863 36 : S_offdiag(k, l) = -1.0_dp*S_offdiag(k, l)
1864 36 : H_offdiag(k, l) = -1.0_dp*H_offdiag(k, l)
1865 : END IF
1866 : END DO
1867 : END DO
1868 : END IF
1869 20 : IF (ignore_excited) THEN
1870 18 : H_mat(i, j) = H_offdiag(1, 1)
1871 18 : H_mat(j, i) = H_mat(i, j)
1872 18 : S_mat(i, j) = S_offdiag(1, 1)
1873 18 : S_mat(j, i) = S_mat(i, j)
1874 : ELSE
1875 2 : irow = 1
1876 2 : icol = 1
1877 2 : DO k = 1, i - 1
1878 2 : irow = irow + SIZE(blocks(k)%array)
1879 : END DO
1880 4 : DO k = 1, j - 1
1881 4 : icol = icol + SIZE(blocks(k)%array)
1882 : END DO
1883 14 : H_mat(irow:irow + SIZE(H_offdiag, 1) - 1, icol:icol + SIZE(H_offdiag, 2) - 1) = H_offdiag(:, :)
1884 14 : H_mat(icol:icol + SIZE(H_offdiag, 2) - 1, irow:irow + SIZE(H_offdiag, 1) - 1) = TRANSPOSE(H_offdiag)
1885 14 : S_mat(irow:irow + SIZE(H_offdiag, 1) - 1, icol:icol + SIZE(H_offdiag, 2) - 1) = S_offdiag(:, :)
1886 14 : S_mat(icol:icol + SIZE(H_offdiag, 2) - 1, irow:irow + SIZE(H_offdiag, 1) - 1) = TRANSPOSE(S_offdiag)
1887 : END IF
1888 20 : IF (iounit > 0) THEN
1889 10 : WRITE (iounit, '(/,T3,A)') REPEAT('#', 39)
1890 10 : WRITE (iounit, '(T3,A,I3,A,I3,A)') '###### Blocks I =', i, ' and J = ', j, ' ######'
1891 10 : WRITE (iounit, '(T3,A)') REPEAT('#', 39)
1892 10 : WRITE (iounit, '(T3,A)') 'Interaction energies'
1893 21 : DO irow = 1, SIZE(H_offdiag, 1)
1894 20 : ilabel = "(ground state)"
1895 20 : IF (irow > 1) THEN
1896 10 : IF (ignore_excited) EXIT
1897 1 : WRITE (tmp, '(I3)') irow - 1
1898 1 : ilabel = "(excited state "//TRIM(ADJUSTL(tmp))//")"
1899 : END IF
1900 34 : DO icol = 1, SIZE(H_offdiag, 2)
1901 21 : jlabel = "(ground state)"
1902 21 : IF (icol > 1) THEN
1903 10 : IF (ignore_excited) EXIT
1904 2 : WRITE (tmp, '(I3)') icol - 1
1905 2 : jlabel = "(excited state "//TRIM(ADJUSTL(tmp))//")"
1906 : END IF
1907 24 : WRITE (iounit, '(T6,A,T58,(3X,F20.14))') TRIM(ilabel)//'-'//TRIM(jlabel)//':', H_offdiag(irow, icol)
1908 : END DO
1909 : END DO
1910 10 : WRITE (iounit, '(T3,A)') 'Overlaps'
1911 21 : DO irow = 1, SIZE(H_offdiag, 1)
1912 20 : ilabel = "(ground state)"
1913 20 : IF (irow > 1) THEN
1914 10 : IF (ignore_excited) EXIT
1915 1 : ilabel = "(excited state)"
1916 1 : WRITE (tmp, '(I3)') irow - 1
1917 1 : ilabel = "(excited state "//TRIM(ADJUSTL(tmp))//")"
1918 : END IF
1919 34 : DO icol = 1, SIZE(H_offdiag, 2)
1920 21 : jlabel = "(ground state)"
1921 21 : IF (icol > 1) THEN
1922 10 : IF (ignore_excited) EXIT
1923 2 : WRITE (tmp, '(I3)') icol - 1
1924 2 : jlabel = "(excited state "//TRIM(ADJUSTL(tmp))//")"
1925 : END IF
1926 24 : WRITE (iounit, '(T6,A,T58,(3X,F20.14))') TRIM(ilabel)//'-'//TRIM(jlabel)//':', S_offdiag(irow, icol)
1927 : END DO
1928 : END DO
1929 : END IF
1930 50 : DEALLOCATE (H_offdiag, S_offdiag)
1931 : END DO
1932 10 : CALL mixed_cdft_result_type_set(mixed_cdft%results, H=H_mat, S=S_mat)
1933 : ! Deallocate work
1934 10 : DEALLOCATE (H_mat, S_mat)
1935 :
1936 10 : END SUBROUTINE mixed_cdft_assemble_block_diag
1937 :
1938 : END MODULE mixed_cdft_utils
|