Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Definition and initialisation of the mo data type.
10 : !> \par History
11 : !> - adapted to the new QS environment data structure (02.04.2002,MK)
12 : !> - set_mo_occupation added (17.04.02,MK)
13 : !> - correct_mo_eigenvalues added (18.04.02,MK)
14 : !> - calculate_density_matrix moved from qs_scf to here (22.04.02,MK)
15 : !> - mo_set_p_type added (23.04.02,MK)
16 : !> - PRIVATE attribute set for TYPE mo_set_type (23.04.02,MK)
17 : !> - started conversion to LSD (1.2003, Joost VandeVondele)
18 : !> - Split of from qs_mo_types (07.2014, JGH)
19 : !> \author Matthias Krack (09.05.2001,MK)
20 : ! **************************************************************************************************
21 : MODULE qs_mo_io
22 :
23 : USE atomic_kind_types, ONLY: get_atomic_kind
24 : USE basis_set_types, ONLY: get_gto_basis_set,&
25 : gto_basis_set_p_type,&
26 : gto_basis_set_type
27 : USE cp_cfm_types, ONLY: cp_cfm_get_submatrix,&
28 : cp_cfm_type
29 : USE cp_dbcsr_api, ONLY: dbcsr_binary_write,&
30 : dbcsr_create,&
31 : dbcsr_p_type,&
32 : dbcsr_release,&
33 : dbcsr_type
34 : USE cp_dbcsr_contrib, ONLY: dbcsr_checksum
35 : USE cp_dbcsr_operations, ONLY: copy_dbcsr_to_fm,&
36 : copy_fm_to_dbcsr,&
37 : dbcsr_deallocate_matrix_set
38 : USE cp_dbcsr_output, ONLY: cp_dbcsr_write_sparse_matrix
39 : USE cp_files, ONLY: close_file,&
40 : open_file
41 : USE cp_fm_types, ONLY: cp_fm_get_info,&
42 : cp_fm_get_submatrix,&
43 : cp_fm_set_all,&
44 : cp_fm_set_submatrix,&
45 : cp_fm_to_fm,&
46 : cp_fm_type,&
47 : cp_fm_write_unformatted
48 : USE cp_log_handling, ONLY: cp_get_default_logger,&
49 : cp_logger_get_default_unit_nr,&
50 : cp_logger_type,&
51 : cp_to_string
52 : USE cp_output_handling, ONLY: cp_p_file,&
53 : cp_print_key_finished_output,&
54 : cp_print_key_generate_filename,&
55 : cp_print_key_should_output,&
56 : cp_print_key_unit_nr
57 : USE input_section_types, ONLY: section_vals_get_subs_vals,&
58 : section_vals_type,&
59 : section_vals_val_get
60 : USE kahan_sum, ONLY: accurate_sum
61 : USE kinds, ONLY: default_path_length,&
62 : default_string_length,&
63 : dp
64 : USE message_passing, ONLY: mp_para_env_type
65 : USE orbital_pointers, ONLY: indco,&
66 : nco,&
67 : nso
68 : USE orbital_symbols, ONLY: cgf_symbol,&
69 : sgf_symbol
70 : USE orbital_transformation_matrices, ONLY: orbtramat
71 : USE particle_types, ONLY: particle_type
72 : USE physcon, ONLY: evolt
73 : USE qs_density_matrices, ONLY: calculate_density_matrix
74 : USE qs_dftb_types, ONLY: qs_dftb_atom_type
75 : USE qs_dftb_utils, ONLY: get_dftb_atom_param
76 : USE qs_environment_types, ONLY: get_qs_env,&
77 : qs_environment_type
78 : USE qs_kind_types, ONLY: get_qs_kind,&
79 : get_qs_kind_set,&
80 : qs_kind_type
81 : USE qs_ks_types, ONLY: qs_ks_env_type
82 : USE qs_mo_methods, ONLY: calculate_subspace_eigenvalues
83 : USE qs_mo_occupation, ONLY: set_mo_occupation
84 : USE qs_mo_types, ONLY: get_mo_set,&
85 : mo_set_type
86 : USE qs_neighbor_list_types, ONLY: neighbor_list_set_p_type,&
87 : release_neighbor_list_sets
88 : USE qs_neighbor_lists, ONLY: setup_neighbor_list
89 : USE qs_overlap, ONLY: build_overlap_matrix_simple
90 : #include "./base/base_uses.f90"
91 :
92 : IMPLICIT NONE
93 :
94 : PRIVATE
95 :
96 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_mo_io'
97 :
98 : PUBLIC :: wfn_restart_file_name, &
99 : write_rt_mos_to_restart, &
100 : read_rt_mos_from_restart, &
101 : write_dm_binary_restart, &
102 : write_mo_set_to_output_unit, &
103 : write_mo_set_to_restart, &
104 : read_mo_set_from_restart, &
105 : read_mos_restart_low, &
106 : write_mo_set_low
107 :
108 : CONTAINS
109 :
110 : ! **************************************************************************************************
111 : !> \brief ...
112 : !> \param mo_array ...
113 : !> \param particle_set ...
114 : !> \param dft_section ...
115 : !> \param qs_kind_set ...
116 : !> \param matrix_ks ...
117 : ! **************************************************************************************************
118 198835 : SUBROUTINE write_mo_set_to_restart(mo_array, particle_set, dft_section, qs_kind_set, matrix_ks)
119 :
120 : TYPE(mo_set_type), DIMENSION(:), INTENT(IN) :: mo_array
121 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
122 : TYPE(section_vals_type), POINTER :: dft_section
123 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
124 : TYPE(dbcsr_p_type), DIMENSION(:), OPTIONAL, &
125 : POINTER :: matrix_ks
126 :
127 : CHARACTER(LEN=*), PARAMETER :: routineN = 'write_mo_set_to_restart'
128 : CHARACTER(LEN=30), DIMENSION(2), PARAMETER :: &
129 : keys = ["SCF%PRINT%RESTART_HISTORY", "SCF%PRINT%RESTART "]
130 :
131 : INTEGER :: handle, ikey, ires, ispin
132 : TYPE(cp_logger_type), POINTER :: logger
133 :
134 198835 : CALL timeset(routineN, handle)
135 :
136 198835 : logger => cp_get_default_logger()
137 :
138 : IF (BTEST(cp_print_key_should_output(logger%iter_info, &
139 198835 : dft_section, keys(1)), cp_p_file) .OR. &
140 : BTEST(cp_print_key_should_output(logger%iter_info, &
141 : dft_section, keys(2)), cp_p_file)) THEN
142 :
143 19734 : IF (mo_array(1)%use_mo_coeff_b) THEN
144 : ! we are using the dbcsr mo_coeff
145 : ! we copy it to the fm for anycase
146 13617 : DO ispin = 1, SIZE(mo_array)
147 7385 : CPASSERT(ASSOCIATED(mo_array(ispin)%mo_coeff_b))
148 : CALL copy_dbcsr_to_fm(mo_array(ispin)%mo_coeff_b, &
149 13617 : mo_array(ispin)%mo_coeff) !fm->dbcsr
150 : END DO
151 : END IF
152 :
153 59202 : DO ikey = 1, SIZE(keys)
154 39468 : IF (BTEST(cp_print_key_should_output(logger%iter_info, &
155 198835 : dft_section, keys(ikey)), cp_p_file)) THEN
156 : ires = cp_print_key_unit_nr(logger, dft_section, keys(ikey), &
157 : extension=".wfn", file_status="REPLACE", file_action="WRITE", &
158 19746 : do_backup=.TRUE., file_form="UNFORMATTED")
159 19746 : IF (PRESENT(matrix_ks)) THEN
160 : CALL write_mo_set_low(mo_array, particle_set=particle_set, qs_kind_set=qs_kind_set, &
161 6184 : ires=ires, matrix_ks=matrix_ks)
162 : ELSE
163 : CALL write_mo_set_low(mo_array, particle_set=particle_set, qs_kind_set=qs_kind_set, &
164 13562 : ires=ires)
165 : END IF
166 19746 : CALL cp_print_key_finished_output(ires, logger, dft_section, TRIM(keys(ikey)))
167 : END IF
168 : END DO
169 : END IF
170 :
171 198835 : CALL timestop(handle)
172 :
173 198835 : END SUBROUTINE write_mo_set_to_restart
174 :
175 : ! **************************************************************************************************
176 : !> \brief calculates density matrix from mo set and writes the density matrix
177 : !> into a binary restart file
178 : !> \param mo_array mos
179 : !> \param dft_section dft input section
180 : !> \param tmpl_matrix template dbcsr matrix
181 : !> \author Mohammad Hossein Bani-Hashemian
182 : ! **************************************************************************************************
183 11803 : SUBROUTINE write_dm_binary_restart(mo_array, dft_section, tmpl_matrix)
184 :
185 : TYPE(mo_set_type), DIMENSION(:), INTENT(IN) :: mo_array
186 : TYPE(section_vals_type), POINTER :: dft_section
187 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: tmpl_matrix
188 :
189 : CHARACTER(LEN=*), PARAMETER :: routineN = 'write_dm_binary_restart'
190 :
191 : CHARACTER(LEN=default_path_length) :: file_name, project_name
192 : INTEGER :: handle, ispin, unit_nr
193 : LOGICAL :: do_dm_restart
194 : REAL(KIND=dp) :: cs_pos
195 : TYPE(cp_logger_type), POINTER :: logger
196 : TYPE(dbcsr_type), POINTER :: matrix_p_tmp
197 :
198 11803 : CALL timeset(routineN, handle)
199 11803 : logger => cp_get_default_logger()
200 11803 : IF (logger%para_env%is_source()) THEN
201 6032 : unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
202 : ELSE
203 : unit_nr = -1
204 : END IF
205 :
206 11803 : project_name = logger%iter_info%project_name
207 11803 : CALL section_vals_val_get(dft_section, "SCF%PRINT%DM_RESTART_WRITE", l_val=do_dm_restart)
208 11803 : NULLIFY (matrix_p_tmp)
209 :
210 11803 : IF (do_dm_restart) THEN
211 0 : ALLOCATE (matrix_p_tmp)
212 0 : DO ispin = 1, SIZE(mo_array)
213 0 : CALL dbcsr_create(matrix_p_tmp, template=tmpl_matrix(ispin)%matrix, name="DM RESTART")
214 :
215 0 : IF (.NOT. ASSOCIATED(mo_array(ispin)%mo_coeff_b)) CPABORT("mo_coeff_b NOT ASSOCIATED")
216 :
217 0 : CALL copy_fm_to_dbcsr(mo_array(ispin)%mo_coeff, mo_array(ispin)%mo_coeff_b)
218 : CALL calculate_density_matrix(mo_array(ispin), matrix_p_tmp, &
219 0 : use_dbcsr=.TRUE., retain_sparsity=.FALSE.)
220 :
221 0 : WRITE (file_name, '(A,I0,A)') TRIM(project_name)//"_SCF_DM_SPIN_", ispin, "_RESTART.dm"
222 0 : cs_pos = dbcsr_checksum(matrix_p_tmp, pos=.TRUE.)
223 0 : IF (unit_nr > 0) THEN
224 0 : WRITE (unit_nr, '(T2,A,E20.8)') "Writing restart DM "//TRIM(file_name)//" with checksum: ", cs_pos
225 : END IF
226 0 : CALL dbcsr_binary_write(matrix_p_tmp, file_name)
227 :
228 0 : CALL dbcsr_release(matrix_p_tmp)
229 : END DO
230 0 : DEALLOCATE (matrix_p_tmp)
231 : END IF
232 :
233 11803 : CALL timestop(handle)
234 :
235 11803 : END SUBROUTINE write_dm_binary_restart
236 :
237 : ! **************************************************************************************************
238 : !> \brief ...
239 : !> \param mo_array ...
240 : !> \param rt_mos ...
241 : !> \param particle_set ...
242 : !> \param dft_section ...
243 : !> \param qs_kind_set ...
244 : ! **************************************************************************************************
245 468 : SUBROUTINE write_rt_mos_to_restart(mo_array, rt_mos, particle_set, dft_section, qs_kind_set)
246 :
247 : TYPE(mo_set_type), DIMENSION(:), INTENT(IN) :: mo_array
248 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: rt_mos
249 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
250 : TYPE(section_vals_type), POINTER :: dft_section
251 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
252 :
253 : CHARACTER(LEN=*), PARAMETER :: routineN = 'write_rt_mos_to_restart'
254 : CHARACTER(LEN=43), DIMENSION(2), PARAMETER :: keys = [ &
255 : "REAL_TIME_PROPAGATION%PRINT%RESTART_HISTORY", &
256 : "REAL_TIME_PROPAGATION%PRINT%RESTART "]
257 :
258 : INTEGER :: handle, ikey, ires
259 : TYPE(cp_logger_type), POINTER :: logger
260 :
261 468 : CALL timeset(routineN, handle)
262 468 : logger => cp_get_default_logger()
263 :
264 : IF (BTEST(cp_print_key_should_output(logger%iter_info, &
265 468 : dft_section, keys(1)), cp_p_file) .OR. &
266 : BTEST(cp_print_key_should_output(logger%iter_info, &
267 : dft_section, keys(2)), cp_p_file)) THEN
268 :
269 366 : DO ikey = 1, SIZE(keys)
270 :
271 244 : IF (BTEST(cp_print_key_should_output(logger%iter_info, &
272 468 : dft_section, keys(ikey)), cp_p_file)) THEN
273 : ires = cp_print_key_unit_nr(logger, dft_section, keys(ikey), &
274 : extension=".rtpwfn", file_status="REPLACE", file_action="WRITE", &
275 122 : do_backup=.TRUE., file_form="UNFORMATTED")
276 : CALL write_mo_set_low(mo_array, qs_kind_set=qs_kind_set, particle_set=particle_set, &
277 122 : ires=ires, rt_mos=rt_mos)
278 122 : CALL cp_print_key_finished_output(ires, logger, dft_section, TRIM(keys(ikey)))
279 : END IF
280 : END DO
281 : END IF
282 :
283 468 : CALL timestop(handle)
284 :
285 468 : END SUBROUTINE write_rt_mos_to_restart
286 :
287 : ! **************************************************************************************************
288 : !> \brief ...
289 : !> \param mo_array ...
290 : !> \param qs_kind_set ...
291 : !> \param particle_set ...
292 : !> \param ires ...
293 : !> \param rt_mos ...
294 : !> \param matrix_ks ...
295 : ! **************************************************************************************************
296 19876 : SUBROUTINE write_mo_set_low(mo_array, qs_kind_set, particle_set, ires, rt_mos, matrix_ks)
297 :
298 : TYPE(mo_set_type), DIMENSION(:), INTENT(IN) :: mo_array
299 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
300 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
301 : INTEGER :: ires
302 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN), &
303 : OPTIONAL :: rt_mos
304 : TYPE(dbcsr_p_type), DIMENSION(:), OPTIONAL, &
305 : POINTER :: matrix_ks
306 :
307 : CHARACTER(LEN=*), PARAMETER :: routineN = 'write_mo_set_low'
308 :
309 : INTEGER :: handle, iatom, ikind, imat, iset, &
310 : ishell, ispin, lmax, lshell, &
311 : max_block, nao, natom, nmo, nset, &
312 : nset_max, nshell_max, nspin
313 19876 : INTEGER, DIMENSION(:), POINTER :: nset_info, nshell
314 19876 : INTEGER, DIMENSION(:, :), POINTER :: l, nshell_info
315 19876 : INTEGER, DIMENSION(:, :, :), POINTER :: nso_info
316 19876 : REAL(KIND=dp), DIMENSION(:), POINTER :: mo_eigenvalues, mo_occupation_numbers
317 : TYPE(cp_fm_type), POINTER :: mo_coeff
318 : TYPE(gto_basis_set_type), POINTER :: orb_basis_set
319 : TYPE(qs_dftb_atom_type), POINTER :: dftb_parameter
320 :
321 19876 : CALL timeset(routineN, handle)
322 :
323 19876 : NULLIFY (mo_coeff)
324 : NULLIFY (mo_eigenvalues)
325 19876 : NULLIFY (mo_occupation_numbers)
326 :
327 19876 : nspin = SIZE(mo_array)
328 19876 : nao = mo_array(1)%nao
329 :
330 19876 : IF (ires > 0) THEN
331 : ! Create some info about the basis set first
332 10114 : natom = SIZE(particle_set, 1)
333 10114 : nset_max = 0
334 10114 : nshell_max = 0
335 :
336 63453 : DO iatom = 1, natom
337 53339 : NULLIFY (orb_basis_set, dftb_parameter)
338 53339 : CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
339 : CALL get_qs_kind(qs_kind_set(ikind), &
340 : basis_set=orb_basis_set, &
341 53339 : dftb_parameter=dftb_parameter)
342 116792 : IF (ASSOCIATED(orb_basis_set)) THEN
343 : CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
344 : nset=nset, &
345 : nshell=nshell, &
346 45605 : l=l)
347 45605 : nset_max = MAX(nset_max, nset)
348 131546 : DO iset = 1, nset
349 131546 : nshell_max = MAX(nshell_max, nshell(iset))
350 : END DO
351 7734 : ELSE IF (ASSOCIATED(dftb_parameter)) THEN
352 7733 : CALL get_dftb_atom_param(dftb_parameter, lmax=lmax)
353 7733 : nset_max = MAX(nset_max, 1)
354 7733 : nshell_max = MAX(nshell_max, lmax + 1)
355 : ELSE
356 : ! We assume here an atom without a basis set
357 : ! CPABORT("Unknown basis type. ")
358 : END IF
359 : END DO
360 :
361 50570 : ALLOCATE (nso_info(nshell_max, nset_max, natom))
362 369972 : nso_info(:, :, :) = 0
363 :
364 40456 : ALLOCATE (nshell_info(nset_max, natom))
365 167864 : nshell_info(:, :) = 0
366 :
367 30342 : ALLOCATE (nset_info(natom))
368 63453 : nset_info(:) = 0
369 :
370 63453 : DO iatom = 1, natom
371 53339 : NULLIFY (orb_basis_set, dftb_parameter)
372 53339 : CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
373 : CALL get_qs_kind(qs_kind_set(ikind), &
374 53339 : basis_set=orb_basis_set, dftb_parameter=dftb_parameter)
375 116792 : IF (ASSOCIATED(orb_basis_set)) THEN
376 : CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
377 : nset=nset, &
378 : nshell=nshell, &
379 45605 : l=l)
380 45605 : nset_info(iatom) = nset
381 131546 : DO iset = 1, nset
382 85941 : nshell_info(iset, iatom) = nshell(iset)
383 250716 : DO ishell = 1, nshell(iset)
384 119170 : lshell = l(ishell, iset)
385 205111 : nso_info(ishell, iset, iatom) = nso(lshell)
386 : END DO
387 : END DO
388 7734 : ELSE IF (ASSOCIATED(dftb_parameter)) THEN
389 7733 : CALL get_dftb_atom_param(dftb_parameter, lmax=lmax)
390 7733 : nset_info(iatom) = 1
391 7733 : nshell_info(1, iatom) = lmax + 1
392 18114 : DO ishell = 1, lmax + 1
393 10381 : lshell = ishell - 1
394 18114 : nso_info(ishell, 1, iatom) = nso(lshell)
395 : END DO
396 : ELSE
397 : ! We assume here an atom without a basis set
398 : ! CPABORT("Unknown basis type. ")
399 : END IF
400 : END DO
401 :
402 10114 : WRITE (ires) natom, nspin, nao, nset_max, nshell_max
403 63453 : WRITE (ires) nset_info
404 167864 : WRITE (ires) nshell_info
405 369972 : WRITE (ires) nso_info
406 :
407 10114 : DEALLOCATE (nset_info)
408 :
409 10114 : DEALLOCATE (nshell_info)
410 :
411 10114 : DEALLOCATE (nso_info)
412 : END IF
413 :
414 : ! Use the ScaLAPACK block size as a default for buffering columns
415 19876 : CALL cp_fm_get_info(mo_array(1)%mo_coeff, ncol_block=max_block)
416 43019 : DO ispin = 1, nspin
417 23143 : mo_coeff => mo_array(ispin)%mo_coeff
418 23143 : nmo = mo_array(ispin)%nmo
419 23143 : IF (nmo > 0) THEN
420 22889 : mo_eigenvalues => mo_array(ispin)%eigenvalues
421 22889 : mo_occupation_numbers => mo_array(ispin)%occupation_numbers
422 22889 : IF (PRESENT(matrix_ks)) THEN
423 : ! With OT: use the Kohn-Sham matrix for the update of the MO eigenvalues
424 : CALL calculate_subspace_eigenvalues(orbitals=mo_coeff, &
425 : ks_matrix=matrix_ks(ispin)%matrix, &
426 7251 : evals_arg=mo_eigenvalues)
427 : END IF
428 22889 : IF (ires > 0) THEN
429 11630 : WRITE (ires) nmo, &
430 11630 : mo_array(ispin)%homo, &
431 11630 : mo_array(ispin)%lfomo, &
432 23260 : mo_array(ispin)%nelectron
433 256214 : WRITE (ires) mo_eigenvalues(1:nmo), mo_occupation_numbers(1:nmo)
434 : END IF
435 : END IF
436 43019 : IF (PRESENT(rt_mos)) THEN
437 468 : DO imat = 2*ispin - 1, 2*ispin
438 468 : CALL cp_fm_write_unformatted(rt_mos(imat), ires)
439 : END DO
440 : ELSE
441 22987 : CALL cp_fm_write_unformatted(mo_coeff, ires)
442 : END IF
443 : END DO
444 :
445 19876 : CALL timestop(handle)
446 :
447 19876 : END SUBROUTINE write_mo_set_low
448 :
449 : ! **************************************************************************************************
450 : !> \brief ...
451 : !> \param filename ...
452 : !> \param exist ...
453 : !> \param section ...
454 : !> \param logger ...
455 : !> \param kp ...
456 : !> \param xas ...
457 : !> \param rtp ...
458 : ! **************************************************************************************************
459 1320 : SUBROUTINE wfn_restart_file_name(filename, exist, section, logger, kp, xas, rtp)
460 : CHARACTER(LEN=default_path_length), INTENT(OUT) :: filename
461 : LOGICAL, INTENT(OUT) :: exist
462 : TYPE(section_vals_type), POINTER :: section
463 : TYPE(cp_logger_type), POINTER :: logger
464 : LOGICAL, INTENT(IN), OPTIONAL :: kp, xas, rtp
465 :
466 : INTEGER :: n_rep_val
467 : LOGICAL :: my_kp, my_rtp, my_xas
468 : TYPE(section_vals_type), POINTER :: print_key
469 :
470 660 : my_kp = .FALSE.
471 660 : my_xas = .FALSE.
472 660 : my_rtp = .FALSE.
473 660 : IF (PRESENT(kp)) my_kp = kp
474 660 : IF (PRESENT(xas)) my_xas = xas
475 660 : IF (PRESENT(rtp)) my_rtp = rtp
476 :
477 660 : exist = .FALSE.
478 660 : CALL section_vals_val_get(section, "WFN_RESTART_FILE_NAME", n_rep_val=n_rep_val)
479 660 : IF (n_rep_val > 0) THEN
480 495 : CALL section_vals_val_get(section, "WFN_RESTART_FILE_NAME", c_val=filename)
481 : ELSE
482 165 : IF (my_xas) THEN
483 : ! try to read from the filename that is generated automatically from the printkey
484 4 : print_key => section_vals_get_subs_vals(section, "PRINT%RESTART")
485 : filename = cp_print_key_generate_filename(logger, print_key, &
486 4 : extension="", my_local=.FALSE.)
487 161 : ELSE IF (my_rtp) THEN
488 : ! try to read from the filename that is generated automatically from the printkey
489 3 : print_key => section_vals_get_subs_vals(section, "REAL_TIME_PROPAGATION%PRINT%RESTART")
490 : filename = cp_print_key_generate_filename(logger, print_key, &
491 3 : extension=".rtpwfn", my_local=.FALSE.)
492 158 : ELSE IF (my_kp) THEN
493 : ! try to read from the filename that is generated automatically from the printkey
494 8 : print_key => section_vals_get_subs_vals(section, "SCF%PRINT%RESTART")
495 : filename = cp_print_key_generate_filename(logger, print_key, &
496 8 : extension=".kp", my_local=.FALSE.)
497 : ELSE
498 : ! try to read from the filename that is generated automatically from the printkey
499 150 : print_key => section_vals_get_subs_vals(section, "SCF%PRINT%RESTART")
500 : filename = cp_print_key_generate_filename(logger, print_key, &
501 150 : extension=".wfn", my_local=.FALSE.)
502 : END IF
503 : END IF
504 660 : IF (.NOT. my_xas) THEN
505 654 : INQUIRE (FILE=filename, exist=exist)
506 : END IF
507 :
508 660 : END SUBROUTINE wfn_restart_file_name
509 :
510 : ! **************************************************************************************************
511 : !> \brief ...
512 : !> \param mo_array ...
513 : !> \param qs_kind_set ...
514 : !> \param particle_set ...
515 : !> \param para_env ...
516 : !> \param id_nr ...
517 : !> \param multiplicity ...
518 : !> \param dft_section ...
519 : !> \param natom_mismatch ...
520 : !> \param cdft ...
521 : !> \param out_unit ...
522 : ! **************************************************************************************************
523 539 : SUBROUTINE read_mo_set_from_restart(mo_array, qs_kind_set, particle_set, &
524 : para_env, id_nr, multiplicity, dft_section, natom_mismatch, &
525 : cdft, out_unit)
526 :
527 : TYPE(mo_set_type), DIMENSION(:), INTENT(INOUT) :: mo_array
528 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
529 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
530 : TYPE(mp_para_env_type), POINTER :: para_env
531 : INTEGER, INTENT(IN) :: id_nr, multiplicity
532 : TYPE(section_vals_type), POINTER :: dft_section
533 : LOGICAL, INTENT(OUT), OPTIONAL :: natom_mismatch
534 : LOGICAL, INTENT(IN), OPTIONAL :: cdft
535 : INTEGER, INTENT(IN), OPTIONAL :: out_unit
536 :
537 : CHARACTER(LEN=*), PARAMETER :: routineN = 'read_mo_set_from_restart'
538 :
539 : CHARACTER(LEN=default_path_length) :: file_name
540 : INTEGER :: handle, ispin, my_out_unit, natom, &
541 : nspin, restart_unit
542 : LOGICAL :: exist, my_cdft
543 : TYPE(cp_logger_type), POINTER :: logger
544 :
545 539 : CALL timeset(routineN, handle)
546 539 : logger => cp_get_default_logger()
547 539 : my_cdft = .FALSE.
548 539 : IF (PRESENT(cdft)) my_cdft = cdft
549 539 : my_out_unit = -1
550 539 : IF (PRESENT(out_unit)) my_out_unit = out_unit
551 :
552 539 : nspin = SIZE(mo_array)
553 539 : restart_unit = -1
554 :
555 539 : IF (para_env%is_source()) THEN
556 :
557 290 : natom = SIZE(particle_set, 1)
558 290 : CALL wfn_restart_file_name(file_name, exist, dft_section, logger)
559 290 : IF (id_nr /= 0) THEN
560 : ! Is it one of the backup files?
561 1 : file_name = TRIM(file_name)//".bak-"//ADJUSTL(cp_to_string(id_nr))
562 : END IF
563 :
564 : CALL open_file(file_name=file_name, &
565 : file_action="READ", &
566 : file_form="UNFORMATTED", &
567 : file_status="OLD", &
568 290 : unit_number=restart_unit)
569 :
570 : END IF
571 :
572 : CALL read_mos_restart_low(mo_array, para_env=para_env, qs_kind_set=qs_kind_set, &
573 : particle_set=particle_set, natom=natom, &
574 539 : rst_unit=restart_unit, multiplicity=multiplicity, natom_mismatch=natom_mismatch)
575 :
576 539 : IF (PRESENT(natom_mismatch)) THEN
577 : ! read_mos_restart_low only the io_node returns natom_mismatch, must broadcast it
578 507 : CALL para_env%bcast(natom_mismatch)
579 507 : IF (natom_mismatch) THEN
580 0 : IF (para_env%is_source()) CALL close_file(unit_number=restart_unit)
581 0 : CALL timestop(handle)
582 0 : RETURN
583 : END IF
584 : END IF
585 :
586 : ! Close restart file
587 539 : IF (para_env%is_source()) THEN
588 290 : IF (my_out_unit > 0) THEN
589 : WRITE (UNIT=my_out_unit, FMT="(T2,A)") &
590 12 : "WFN_RESTART| Restart file "//TRIM(file_name)//" read"
591 : END IF
592 290 : CALL close_file(unit_number=restart_unit)
593 : END IF
594 :
595 : ! CDFT has no real dft_section and does not need to print
596 539 : IF (.NOT. my_cdft) THEN
597 1424 : DO ispin = 1, nspin
598 : CALL write_mo_set_to_output_unit(mo_array(ispin), qs_kind_set, particle_set, &
599 1424 : dft_section, 4, 0, final_mos=.FALSE.)
600 : END DO
601 : END IF
602 :
603 539 : CALL timestop(handle)
604 :
605 : END SUBROUTINE read_mo_set_from_restart
606 :
607 : ! **************************************************************************************************
608 : !> \brief ...
609 : !> \param mo_array ...
610 : !> \param rt_mos ...
611 : !> \param qs_kind_set ...
612 : !> \param particle_set ...
613 : !> \param para_env ...
614 : !> \param id_nr ...
615 : !> \param multiplicity ...
616 : !> \param dft_section ...
617 : ! **************************************************************************************************
618 8 : SUBROUTINE read_rt_mos_from_restart(mo_array, rt_mos, qs_kind_set, particle_set, para_env, id_nr, multiplicity, dft_section)
619 :
620 : TYPE(mo_set_type), DIMENSION(:), INTENT(INOUT) :: mo_array
621 : TYPE(cp_fm_type), DIMENSION(:), POINTER :: rt_mos
622 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
623 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
624 : TYPE(mp_para_env_type), POINTER :: para_env
625 : INTEGER, INTENT(IN) :: id_nr, multiplicity
626 : TYPE(section_vals_type), POINTER :: dft_section
627 :
628 : CHARACTER(LEN=*), PARAMETER :: routineN = 'read_rt_mos_from_restart'
629 :
630 : CHARACTER(LEN=default_path_length) :: file_name
631 : INTEGER :: handle, ispin, natom, nspin, &
632 : restart_unit, unit_nr
633 : LOGICAL :: exist
634 : TYPE(cp_logger_type), POINTER :: logger
635 :
636 8 : CALL timeset(routineN, handle)
637 8 : logger => cp_get_default_logger()
638 :
639 8 : nspin = SIZE(mo_array)
640 8 : restart_unit = -1
641 :
642 8 : IF (para_env%is_source()) THEN
643 :
644 4 : natom = SIZE(particle_set, 1)
645 4 : CALL wfn_restart_file_name(file_name, exist, dft_section, logger, rtp=.TRUE.)
646 4 : IF (id_nr /= 0) THEN
647 : ! Is it one of the backup files?
648 0 : file_name = TRIM(file_name)//".bak-"//ADJUSTL(cp_to_string(id_nr))
649 : END IF
650 :
651 4 : unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
652 4 : IF (unit_nr > 0) THEN
653 4 : WRITE (unit_nr, '(T2,A)') "Read RTP restart from the file: "//TRIM(file_name)
654 : END IF
655 :
656 : CALL open_file(file_name=file_name, &
657 : file_action="READ", &
658 : file_form="UNFORMATTED", &
659 : file_status="OLD", &
660 4 : unit_number=restart_unit)
661 :
662 : END IF
663 :
664 : CALL read_mos_restart_low(mo_array, rt_mos=rt_mos, para_env=para_env, &
665 : particle_set=particle_set, qs_kind_set=qs_kind_set, natom=natom, &
666 8 : rst_unit=restart_unit, multiplicity=multiplicity)
667 :
668 : ! Close restart file
669 8 : IF (para_env%is_source()) CALL close_file(unit_number=restart_unit)
670 :
671 16 : DO ispin = 1, nspin
672 : CALL write_mo_set_to_output_unit(mo_array(ispin), qs_kind_set, particle_set, &
673 16 : dft_section, 4, 0, final_mos=.FALSE.)
674 : END DO
675 :
676 8 : CALL timestop(handle)
677 :
678 8 : END SUBROUTINE read_rt_mos_from_restart
679 :
680 : ! **************************************************************************************************
681 : !> \brief Reading the mos from apreviously defined restart file
682 : !> \param mos ...
683 : !> \param para_env ...
684 : !> \param qs_kind_set ...
685 : !> \param particle_set ...
686 : !> \param natom ...
687 : !> \param rst_unit ...
688 : !> \param multiplicity ...
689 : !> \param rt_mos ...
690 : !> \param natom_mismatch ...
691 : !> \par History
692 : !> 12.2007 created [MI]
693 : !> \author MI
694 : ! **************************************************************************************************
695 597 : SUBROUTINE read_mos_restart_low(mos, para_env, qs_kind_set, particle_set, natom, rst_unit, &
696 : multiplicity, rt_mos, natom_mismatch)
697 :
698 : TYPE(mo_set_type), DIMENSION(:), INTENT(INOUT) :: mos
699 : TYPE(mp_para_env_type), POINTER :: para_env
700 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
701 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
702 : INTEGER, INTENT(IN) :: natom, rst_unit
703 : INTEGER, INTENT(in), OPTIONAL :: multiplicity
704 : TYPE(cp_fm_type), DIMENSION(:), OPTIONAL, POINTER :: rt_mos
705 : LOGICAL, INTENT(OUT), OPTIONAL :: natom_mismatch
706 :
707 : INTEGER :: homo, homo_read, i, iatom, ikind, imat, irow, iset, iset_read, ishell, &
708 : ishell_read, iso, ispin, lfomo_read, lmax, lshell, my_mult, nao, nao_read, natom_read, &
709 : nelectron, nelectron_read, nmo, nmo_read, nnshell, nset, nset_max, nshell_max, nspin, &
710 : nspin_read, offset_read
711 597 : INTEGER, DIMENSION(:), POINTER :: nset_info, nshell
712 597 : INTEGER, DIMENSION(:, :), POINTER :: l, nshell_info
713 597 : INTEGER, DIMENSION(:, :, :), POINTER :: nso_info, offset_info
714 : LOGICAL :: minbas, natom_match, use_this
715 597 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eig_read, occ_read
716 597 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: vecbuffer, vecbuffer_read
717 : TYPE(cp_logger_type), POINTER :: logger
718 : TYPE(gto_basis_set_type), POINTER :: orb_basis_set
719 : TYPE(qs_dftb_atom_type), POINTER :: dftb_parameter
720 :
721 1194 : logger => cp_get_default_logger()
722 :
723 597 : nspin = SIZE(mos)
724 597 : nao = mos(1)%nao
725 597 : my_mult = 0
726 597 : IF (PRESENT(multiplicity)) my_mult = multiplicity
727 :
728 597 : IF (para_env%is_source()) THEN
729 319 : READ (rst_unit) natom_read, nspin_read, nao_read, nset_max, nshell_max
730 319 : IF (PRESENT(rt_mos)) THEN
731 4 : IF (nspin_read /= nspin) THEN
732 0 : CPABORT("To change nspin is not possible. ")
733 : END IF
734 : ELSE
735 : ! we should allow for restarting with different spin settings
736 315 : IF (nspin_read /= nspin) THEN
737 : WRITE (cp_logger_get_default_unit_nr(logger), *) &
738 0 : "READ RESTART : WARNING : nspin is not equal "
739 : END IF
740 : ! this case needs fixing of homo/lfomo/nelec/occupations ...
741 315 : IF (nspin_read > nspin) THEN
742 0 : CPABORT("Reducing nspin is not possible. ")
743 : END IF
744 : END IF
745 :
746 319 : natom_match = (natom_read == natom)
747 :
748 319 : IF (natom_match) THEN ! actually do the read read
749 :
750 : ! Let's make it possible to change the basis set
751 1595 : ALLOCATE (nso_info(nshell_max, nset_max, natom_read))
752 1276 : ALLOCATE (nshell_info(nset_max, natom_read))
753 957 : ALLOCATE (nset_info(natom_read))
754 1276 : ALLOCATE (offset_info(nshell_max, nset_max, natom_read))
755 :
756 319 : IF (nao_read /= nao) THEN
757 : WRITE (cp_logger_get_default_unit_nr(logger), *) &
758 1 : " READ RESTART : WARNING : DIFFERENT # AOs ", nao, nao_read
759 1 : IF (PRESENT(rt_mos)) THEN
760 0 : CPABORT("To change basis is not possible. ")
761 : END IF
762 : END IF
763 :
764 1166 : READ (rst_unit) nset_info
765 2900 : READ (rst_unit) nshell_info
766 6995 : READ (rst_unit) nso_info
767 :
768 319 : i = 1
769 1166 : DO iatom = 1, natom
770 2734 : DO iset = 1, nset_info(iatom)
771 4968 : DO ishell = 1, nshell_info(iset, iatom)
772 2553 : offset_info(ishell, iset, iatom) = i
773 4121 : i = i + nso_info(ishell, iset, iatom)
774 : END DO
775 : END DO
776 : END DO
777 :
778 957 : ALLOCATE (vecbuffer_read(1, nao_read))
779 :
780 : END IF ! natom_match
781 : END IF ! ionode
782 :
783 : ! make natom_match and natom_mismatch uniform across all nodes
784 597 : CALL para_env%bcast(natom_match)
785 597 : IF (PRESENT(natom_mismatch)) natom_mismatch = .NOT. natom_match
786 : ! handle natom_match false
787 597 : IF (.NOT. natom_match) THEN
788 0 : IF (PRESENT(natom_mismatch)) THEN
789 : WRITE (cp_logger_get_default_unit_nr(logger), *) &
790 0 : " READ RESTART : WARNING : DIFFERENT natom, returning ", natom, natom_read
791 : RETURN
792 : ELSE
793 0 : CPABORT("Incorrect number of atoms in restart file. ")
794 : END IF
795 : END IF
796 :
797 597 : CALL para_env%bcast(nspin_read)
798 :
799 1791 : ALLOCATE (vecbuffer(1, nao))
800 :
801 1612 : DO ispin = 1, nspin
802 :
803 1015 : nmo = mos(ispin)%nmo
804 1015 : homo = mos(ispin)%homo
805 5622 : mos(ispin)%eigenvalues(:) = 0.0_dp
806 5622 : mos(ispin)%occupation_numbers(:) = 0.0_dp
807 1015 : CALL cp_fm_set_all(mos(ispin)%mo_coeff, 0.0_dp)
808 :
809 1015 : IF (para_env%is_source() .AND. (nmo > 0)) THEN
810 537 : READ (rst_unit) nmo_read, homo_read, lfomo_read, nelectron_read
811 2148 : ALLOCATE (eig_read(nmo_read), occ_read(nmo_read))
812 537 : eig_read = 0.0_dp
813 537 : occ_read = 0.0_dp
814 :
815 537 : nmo = MIN(nmo, nmo_read)
816 : IF (nmo_read < nmo) THEN
817 : CALL cp_warn(__LOCATION__, &
818 : "The number of MOs on the restart unit is smaller than the number of "// &
819 : "the allocated MOs. The MO set will be padded with zeros!")
820 : END IF
821 537 : IF (nmo_read > nmo) THEN
822 : CALL cp_warn(__LOCATION__, &
823 : "The number of MOs on the restart unit is greater than the number of "// &
824 6 : "the allocated MOs. The read MO set will be truncated!")
825 : END IF
826 :
827 537 : READ (rst_unit) eig_read(1:nmo_read), occ_read(1:nmo_read)
828 2878 : mos(ispin)%eigenvalues(1:nmo) = eig_read(1:nmo)
829 2878 : mos(ispin)%occupation_numbers(1:nmo) = occ_read(1:nmo)
830 537 : DEALLOCATE (eig_read, occ_read)
831 :
832 537 : mos(ispin)%homo = homo_read
833 537 : mos(ispin)%lfomo = lfomo_read
834 537 : IF (MIN(homo_read, homo) > nmo) THEN
835 0 : IF (nelectron_read == mos(ispin)%nelectron) THEN
836 : CALL cp_warn(__LOCATION__, &
837 : "The number of occupied MOs on the restart unit is larger than "// &
838 0 : "the allocated MOs. The read MO set will be truncated and the occupation numbers recalculated!")
839 0 : CALL set_mo_occupation(mo_set=mos(ispin))
840 : ELSE
841 : ! can not make this a warning i.e. homo must be smaller than nmo
842 : ! otherwise e.g. set_mo_occupation will go out of bounds
843 0 : CPABORT("Number of occupied MOs on restart unit larger than allocated MOs. ")
844 : END IF
845 : END IF
846 : END IF
847 :
848 1015 : CALL para_env%bcast(nmo)
849 1015 : CALL para_env%bcast(mos(ispin)%homo)
850 1015 : CALL para_env%bcast(mos(ispin)%lfomo)
851 1015 : CALL para_env%bcast(mos(ispin)%nelectron)
852 10229 : CALL para_env%bcast(mos(ispin)%eigenvalues)
853 10229 : CALL para_env%bcast(mos(ispin)%occupation_numbers)
854 :
855 1015 : IF (PRESENT(rt_mos)) THEN
856 24 : DO imat = 2*ispin - 1, 2*ispin
857 40 : DO i = 1, nmo
858 16 : IF (para_env%is_source()) THEN
859 168 : READ (rst_unit) vecbuffer
860 : ELSE
861 88 : vecbuffer(1, :) = 0.0_dp
862 : END IF
863 656 : CALL para_env%bcast(vecbuffer)
864 : CALL cp_fm_set_submatrix(rt_mos(imat), &
865 32 : vecbuffer, 1, i, nao, 1, transpose=.TRUE.)
866 : END DO
867 : END DO
868 : ELSE
869 5582 : DO i = 1, nmo
870 4575 : IF (para_env%is_source()) THEN
871 152709 : READ (rst_unit) vecbuffer_read
872 : ! now, try to assign the read to the real vector
873 : ! in case the basis set changed this involves some guessing
874 2337 : irow = 1
875 10434 : DO iatom = 1, natom
876 8097 : NULLIFY (orb_basis_set, dftb_parameter, l, nshell)
877 8097 : CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
878 : CALL get_qs_kind(qs_kind_set(ikind), &
879 8097 : basis_set=orb_basis_set, dftb_parameter=dftb_parameter)
880 8097 : IF (ASSOCIATED(orb_basis_set)) THEN
881 : CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
882 : nset=nset, &
883 : nshell=nshell, &
884 8049 : l=l)
885 8049 : minbas = .FALSE.
886 48 : ELSE IF (ASSOCIATED(dftb_parameter)) THEN
887 48 : CALL get_dftb_atom_param(dftb_parameter, lmax=lmax)
888 48 : nset = 1
889 48 : minbas = .TRUE.
890 : ELSE
891 : ! assume an atom without basis set
892 : ! CPABORT("Unknown basis set type. ")
893 0 : nset = 0
894 : END IF
895 :
896 8097 : use_this = .TRUE.
897 8097 : iset_read = 1
898 37303 : DO iset = 1, nset
899 18772 : ishell_read = 1
900 18772 : IF (minbas) THEN
901 48 : nnshell = lmax + 1
902 : ELSE
903 18724 : nnshell = nshell(iset)
904 : END IF
905 60423 : DO ishell = 1, nnshell
906 33554 : IF (minbas) THEN
907 72 : lshell = ishell - 1
908 : ELSE
909 33482 : lshell = l(ishell, iset)
910 : END IF
911 33554 : IF (iset_read > nset_info(iatom)) use_this = .FALSE.
912 : IF (use_this) THEN ! avoids out of bound access of the lower line if false
913 33530 : IF (nso(lshell) == nso_info(ishell_read, iset_read, iatom)) THEN
914 33530 : offset_read = offset_info(ishell_read, iset_read, iatom)
915 33530 : ishell_read = ishell_read + 1
916 33530 : IF (ishell_read > nshell_info(iset, iatom)) THEN
917 18768 : ishell_read = 1
918 18768 : iset_read = iset_read + 1
919 : END IF
920 : ELSE
921 : use_this = .FALSE.
922 : END IF
923 : END IF
924 108884 : DO iso = 1, nso(lshell)
925 75330 : IF (use_this) THEN
926 75186 : IF (offset_read - 1 + iso < 1 .OR. offset_read - 1 + iso > nao_read) THEN
927 0 : vecbuffer(1, irow) = 0.0_dp
928 : ELSE
929 75186 : vecbuffer(1, irow) = vecbuffer_read(1, offset_read - 1 + iso)
930 : END IF
931 : ELSE
932 144 : vecbuffer(1, irow) = 0.0_dp
933 : END IF
934 108884 : irow = irow + 1
935 : END DO
936 52326 : use_this = .TRUE.
937 : END DO
938 : END DO
939 : END DO
940 :
941 : ELSE
942 :
943 76074 : vecbuffer(1, :) = 0.0_dp
944 :
945 : END IF
946 :
947 601239 : CALL para_env%bcast(vecbuffer)
948 : CALL cp_fm_set_submatrix(mos(ispin)%mo_coeff, &
949 5582 : vecbuffer, 1, i, nao, 1, transpose=.TRUE.)
950 : END DO
951 : END IF
952 : ! Skip extra MOs if there any
953 1015 : IF (para_env%is_source()) THEN
954 : !ignore nmo = 0
955 542 : IF (nmo > 0) THEN
956 558 : DO i = nmo + 1, nmo_read
957 1544 : READ (rst_unit) vecbuffer_read
958 : END DO
959 : END IF
960 : END IF
961 :
962 1612 : IF (.NOT. PRESENT(rt_mos)) THEN
963 1007 : IF (ispin == 1 .AND. nspin_read < nspin) THEN
964 :
965 0 : mos(ispin + 1)%homo = mos(ispin)%homo
966 0 : mos(ispin + 1)%lfomo = mos(ispin)%lfomo
967 0 : nelectron = mos(ispin)%nelectron
968 0 : IF (my_mult /= 1) THEN
969 : CALL cp_abort(__LOCATION__, &
970 0 : "Restarting an LSD calculation from an LDA wfn only works for multiplicity=1 (singlets).")
971 : END IF
972 0 : IF (mos(ispin + 1)%nelectron < 0) THEN
973 0 : CPABORT("LSD: too few electrons for this multiplisity. ")
974 : END IF
975 0 : mos(ispin + 1)%eigenvalues = mos(ispin)%eigenvalues
976 0 : mos(ispin)%occupation_numbers = mos(ispin)%occupation_numbers/2.0_dp
977 0 : mos(ispin + 1)%occupation_numbers = mos(ispin)%occupation_numbers
978 0 : CALL cp_fm_to_fm(mos(ispin)%mo_coeff, mos(ispin + 1)%mo_coeff)
979 0 : EXIT
980 : END IF
981 : END IF
982 : END DO ! ispin
983 :
984 597 : DEALLOCATE (vecbuffer)
985 :
986 597 : IF (para_env%is_source()) THEN
987 319 : DEALLOCATE (vecbuffer_read)
988 319 : DEALLOCATE (offset_info)
989 319 : DEALLOCATE (nso_info)
990 319 : DEALLOCATE (nshell_info)
991 319 : DEALLOCATE (nset_info)
992 : END IF
993 :
994 1194 : END SUBROUTINE read_mos_restart_low
995 :
996 : ! **************************************************************************************************
997 : !> \brief Write MO information to output file (eigenvalues, occupation numbers, coefficients)
998 : !> \param mo_set ...
999 : !> \param qs_kind_set ...
1000 : !> \param particle_set ...
1001 : !> \param dft_section ...
1002 : !> \param before Digits before the dot
1003 : !> \param kpoint An integer that labels the current k point, e.g. its index
1004 : !> \param final_mos ...
1005 : !> \param spin ...
1006 : !> \param solver_method ...
1007 : !> \param rtp ...
1008 : !> \param cpart ...
1009 : !> \param sim_step ...
1010 : !> \param umo_set ...
1011 : !> \param qs_env ...
1012 : !> \param para_env_inter_kp ...
1013 : !> \date 15.05.2001
1014 : !> \par History:
1015 : !> - Optionally print Cartesian MOs (20.04.2005, MK)
1016 : !> - Revise printout of MO information (05.05.2021, MK)
1017 : !> \par Variables
1018 : !> - after : Number of digits after point.
1019 : !> - before: Number of digits before point.
1020 : !> \author Matthias Krack (MK)
1021 : !> \version 1.1
1022 : ! **************************************************************************************************
1023 6787 : SUBROUTINE write_mo_set_to_output_unit(mo_set, qs_kind_set, particle_set, &
1024 : dft_section, before, kpoint, final_mos, spin, &
1025 : solver_method, rtp, cpart, sim_step, umo_set, qs_env, &
1026 : para_env_inter_kp)
1027 :
1028 : TYPE(mo_set_type), INTENT(IN), OPTIONAL :: mo_set
1029 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
1030 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1031 : TYPE(section_vals_type), POINTER :: dft_section
1032 : INTEGER, INTENT(IN) :: before, kpoint
1033 : LOGICAL, INTENT(IN), OPTIONAL :: final_mos
1034 : CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: spin
1035 : CHARACTER(LEN=2), INTENT(IN), OPTIONAL :: solver_method
1036 : LOGICAL, INTENT(IN), OPTIONAL :: rtp
1037 : INTEGER, INTENT(IN), OPTIONAL :: cpart, sim_step
1038 : TYPE(mo_set_type), INTENT(IN), OPTIONAL :: umo_set
1039 : TYPE(qs_environment_type), OPTIONAL, POINTER :: qs_env
1040 : TYPE(mp_para_env_type), OPTIONAL, POINTER :: para_env_inter_kp
1041 :
1042 : CHARACTER(LEN=12) :: symbol
1043 6787 : CHARACTER(LEN=12), DIMENSION(:), POINTER :: bcgf_symbol
1044 : CHARACTER(LEN=14) :: fmtstr5
1045 : CHARACTER(LEN=15) :: energy_str, orbital_str, step_string
1046 : CHARACTER(LEN=2) :: element_symbol, my_solver_method
1047 : CHARACTER(LEN=2*default_string_length) :: name
1048 : CHARACTER(LEN=21) :: vector_str
1049 : CHARACTER(LEN=22) :: fmtstr4
1050 : CHARACTER(LEN=24) :: fmtstr2
1051 : CHARACTER(LEN=25) :: fmtstr1
1052 : CHARACTER(LEN=29) :: fmtstr6
1053 : CHARACTER(LEN=4) :: reim
1054 : CHARACTER(LEN=40) :: fmtstr3
1055 6787 : CHARACTER(LEN=6), DIMENSION(:), POINTER :: bsgf_symbol
1056 6787 : COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: cmo_coeff_buf
1057 : INTEGER :: after, first_mo, from, homo, iatom, icgf, ico, icol, ikind, imo, irow, iset, &
1058 : isgf, ishell, iso, iw, jcol, last_mo, left, lmax, lshell, nao, natom, ncgf, ncol, nkind, &
1059 : nmo, nmo_local, nset, nsgf, numo, right, scf_step, to, width
1060 6787 : INTEGER, DIMENSION(:), POINTER :: mo_index_range, nshell
1061 6787 : INTEGER, DIMENSION(:, :), POINTER :: l
1062 : LOGICAL :: ionode, my_final, my_rtp, omit_headers, print_cartesian, print_cartesian_overlap, &
1063 : print_eigvals, print_eigvecs, print_occup, should_output
1064 : REAL(KIND=dp) :: chemical_potential, gap, maxocc
1065 6787 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: mo_eigenvalues, mo_occupation_numbers
1066 6787 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: cmatrix, smatrix
1067 6787 : REAL(KIND=dp), DIMENSION(:), POINTER :: eigenvalues, occupation_numbers
1068 : TYPE(cp_cfm_type), POINTER :: cmo_coeff
1069 : TYPE(cp_fm_type), POINTER :: mo_coeff, umo_coeff
1070 : TYPE(cp_logger_type), POINTER :: logger
1071 6787 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: sro
1072 6787 : TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER :: orb_basis_set_list
1073 : TYPE(gto_basis_set_type), POINTER :: orb_basis_set, orbbasis
1074 : TYPE(mp_para_env_type), POINTER :: para_env
1075 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
1076 6787 : POINTER :: sro_list
1077 : TYPE(qs_dftb_atom_type), POINTER :: dftb_parameter
1078 : TYPE(qs_kind_type), POINTER :: qs_kind
1079 : TYPE(qs_ks_env_type), POINTER :: ks_env
1080 :
1081 6787 : NULLIFY (bcgf_symbol)
1082 6787 : NULLIFY (bsgf_symbol)
1083 6787 : NULLIFY (logger)
1084 6787 : NULLIFY (mo_index_range)
1085 6787 : NULLIFY (nshell)
1086 6787 : NULLIFY (mo_coeff)
1087 6787 : NULLIFY (cmo_coeff)
1088 :
1089 13574 : logger => cp_get_default_logger()
1090 6787 : ionode = logger%para_env%is_source()
1091 6787 : CALL section_vals_val_get(dft_section, "PRINT%MO%EIGENVALUES", l_val=print_eigvals)
1092 6787 : CALL section_vals_val_get(dft_section, "PRINT%MO%EIGENVECTORS", l_val=print_eigvecs)
1093 6787 : CALL section_vals_val_get(dft_section, "PRINT%MO%OCCUPATION_NUMBERS", l_val=print_occup)
1094 6787 : CALL section_vals_val_get(dft_section, "PRINT%MO%CARTESIAN", l_val=print_cartesian)
1095 6787 : CALL section_vals_val_get(dft_section, "PRINT%MO%MO_INDEX_RANGE", i_vals=mo_index_range)
1096 6787 : CALL section_vals_val_get(dft_section, "PRINT%MO%NDIGITS", i_val=after)
1097 6787 : CALL section_vals_val_get(dft_section, "PRINT%MO%CARTESIAN_OVERLAP", l_val=print_cartesian_overlap)
1098 6787 : after = MIN(MAX(after, 1), 16)
1099 :
1100 : ! Do we print the final MO information after SCF convergence is reached (default: no)
1101 6787 : IF (PRESENT(final_mos)) THEN
1102 6779 : my_final = final_mos
1103 : ELSE
1104 : my_final = .FALSE.
1105 : END IF
1106 :
1107 : ! complex MOS for RTP, no eigenvalues
1108 6787 : my_rtp = .FALSE.
1109 6787 : IF (PRESENT(rtp)) THEN
1110 8 : my_rtp = rtp
1111 : ! print the first time step if MO print required
1112 : should_output = BTEST(cp_print_key_should_output(logger%iter_info, dft_section, &
1113 : "PRINT%MO"), cp_p_file) &
1114 8 : .OR. (sim_step == 1)
1115 : ELSE
1116 : should_output = BTEST(cp_print_key_should_output(logger%iter_info, dft_section, &
1117 7706 : "PRINT%MO"), cp_p_file) .OR. my_final
1118 : END IF
1119 :
1120 6787 : IF ((.NOT. should_output) .OR. (.NOT. (print_eigvals .OR. print_eigvecs .OR. print_occup))) RETURN
1121 :
1122 5840 : IF (my_rtp) THEN
1123 8 : CPASSERT(PRESENT(sim_step))
1124 8 : CPASSERT(PRESENT(cpart))
1125 8 : scf_step = sim_step
1126 8 : IF (cpart == 0) THEN
1127 4 : reim = "IMAG"
1128 : ELSE
1129 4 : reim = "REAL"
1130 : END IF
1131 8 : print_eigvals = .FALSE.
1132 : ELSE
1133 5832 : scf_step = MAX(0, logger%iter_info%iteration(logger%iter_info%n_rlevel) - 1)
1134 : END IF
1135 :
1136 5840 : IF (.NOT. my_final) THEN
1137 4536 : IF (.NOT. my_rtp) THEN
1138 4528 : step_string = " AFTER SCF STEP"
1139 : ELSE
1140 8 : step_string = " AFTER RTP STEP"
1141 : END IF
1142 : END IF
1143 :
1144 5840 : IF (PRESENT(solver_method)) THEN
1145 5682 : my_solver_method = solver_method
1146 : ELSE
1147 : ! Traditional diagonalization is assumed as default solver method
1148 158 : my_solver_method = "TD"
1149 : END IF
1150 :
1151 : ! Retrieve MO information
1152 5840 : IF (PRESENT(para_env_inter_kp)) THEN
1153 590 : CPASSERT(ASSOCIATED(para_env_inter_kp))
1154 590 : CPASSERT(.NOT. PRESENT(umo_set))
1155 590 : nmo_local = 0
1156 590 : homo = 0
1157 590 : maxocc = 0.0_dp
1158 590 : chemical_potential = 0.0_dp
1159 590 : NULLIFY (cmo_coeff, eigenvalues, occupation_numbers, mo_coeff)
1160 590 : IF (PRESENT(mo_set)) THEN
1161 : CALL get_mo_set(mo_set=mo_set, eigenvalues=eigenvalues, &
1162 : occupation_numbers=occupation_numbers, mo_coeff=mo_coeff, &
1163 : homo=homo, maxocc=maxocc, mu=chemical_potential, nmo=nmo_local, &
1164 586 : cmo_coeff=cmo_coeff)
1165 : END IF
1166 590 : nmo = nmo_local
1167 590 : CALL para_env_inter_kp%max(nmo)
1168 590 : CALL para_env_inter_kp%sum(homo)
1169 590 : CALL para_env_inter_kp%sum(maxocc)
1170 590 : CALL para_env_inter_kp%sum(chemical_potential)
1171 2360 : ALLOCATE (mo_eigenvalues(nmo), mo_occupation_numbers(nmo))
1172 590 : mo_eigenvalues = 0.0_dp
1173 590 : mo_occupation_numbers = 0.0_dp
1174 590 : IF (nmo_local > 0 .AND. PRESENT(mo_set)) THEN
1175 6688 : mo_eigenvalues(1:nmo_local) = eigenvalues(1:nmo_local)
1176 6688 : mo_occupation_numbers(1:nmo_local) = occupation_numbers(1:nmo_local)
1177 : END IF
1178 590 : CALL para_env_inter_kp%sum(mo_eigenvalues)
1179 590 : CALL para_env_inter_kp%sum(mo_occupation_numbers)
1180 590 : IF (print_eigvecs) THEN
1181 8 : CALL get_qs_kind_set(qs_kind_set, nsgf=nao)
1182 32 : ALLOCATE (smatrix(nao, nmo))
1183 8 : smatrix = 0.0_dp
1184 8 : IF (nmo_local > 0 .AND. PRESENT(mo_set)) THEN
1185 4 : IF (ASSOCIATED(cmo_coeff)) THEN
1186 16 : ALLOCATE (cmo_coeff_buf(nao, nmo_local))
1187 4 : CALL cp_cfm_get_submatrix(cmo_coeff, cmo_coeff_buf)
1188 : ! Preserve the legacy text output by printing only the real part.
1189 21028 : smatrix(:, 1:nmo_local) = REAL(cmo_coeff_buf, KIND=dp)
1190 4 : DEALLOCATE (cmo_coeff_buf)
1191 : ELSE
1192 0 : CALL cp_fm_get_submatrix(mo_coeff, smatrix(:, 1:nmo_local))
1193 : END IF
1194 : END IF
1195 16 : CALL para_env_inter_kp%sum(smatrix)
1196 : END IF
1197 590 : numo = 0
1198 : ELSE
1199 5250 : CPASSERT(PRESENT(mo_set))
1200 : CALL get_mo_set(mo_set=mo_set, &
1201 : mo_coeff=mo_coeff, &
1202 : eigenvalues=eigenvalues, &
1203 : occupation_numbers=occupation_numbers, &
1204 : homo=homo, &
1205 : maxocc=maxocc, &
1206 : nao=nao, &
1207 : nmo=nmo, &
1208 5250 : mu=chemical_potential)
1209 5250 : IF (PRESENT(umo_set)) THEN
1210 : CALL get_mo_set(mo_set=umo_set, &
1211 : mo_coeff=umo_coeff, &
1212 20 : nmo=numo)
1213 20 : nmo = nmo + numo
1214 : ELSE
1215 5230 : numo = 0
1216 : END IF
1217 20904 : ALLOCATE (mo_eigenvalues(nmo), mo_occupation_numbers(nmo))
1218 43742 : mo_eigenvalues(1:nmo - numo) = eigenvalues(1:nmo - numo)
1219 5250 : mo_occupation_numbers = 0.0_dp
1220 43742 : mo_occupation_numbers(1:nmo - numo) = occupation_numbers(1:nmo - numo)
1221 10500 : IF (numo > 0) THEN
1222 20 : CALL get_mo_set(mo_set=umo_set, eigenvalues=eigenvalues)
1223 130 : mo_eigenvalues(nmo - numo + 1:nmo) = eigenvalues(1:numo)
1224 : END IF
1225 : END IF
1226 :
1227 5840 : IF (print_eigvecs) THEN
1228 3482 : IF (.NOT. ALLOCATED(smatrix)) THEN
1229 13848 : ALLOCATE (smatrix(nao, nmo))
1230 3474 : CALL cp_fm_get_submatrix(mo_coeff, smatrix(1:nao, 1:nmo - numo))
1231 3474 : IF (numo > 0) THEN
1232 14 : CALL cp_fm_get_submatrix(umo_coeff, smatrix(1:nao, nmo - numo + 1:nmo))
1233 : END IF
1234 : END IF
1235 3482 : IF (.NOT. ionode) THEN
1236 1741 : DEALLOCATE (smatrix)
1237 : END IF
1238 : END IF
1239 :
1240 5840 : IF (PRESENT(qs_env)) THEN
1241 5682 : IF (ASSOCIATED(qs_env) .AND. my_final .AND. print_cartesian_overlap) THEN
1242 2 : NULLIFY (qs_kind_set)
1243 2 : CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set)
1244 2 : nkind = SIZE(qs_kind_set)
1245 :
1246 2 : IF (BTEST(cp_print_key_should_output(logger%iter_info, &
1247 : qs_env%input, "DFT%PRINT%AO_MATRICES/OVERLAP"), cp_p_file)) THEN
1248 8 : ALLOCATE (orb_basis_set_list(nkind))
1249 4 : DO ikind = 1, nkind
1250 2 : qs_kind => qs_kind_set(ikind)
1251 2 : NULLIFY (orb_basis_set_list(ikind)%gto_basis_set)
1252 2 : NULLIFY (orbbasis)
1253 2 : CALL get_qs_kind(qs_kind=qs_kind, basis_set=orbbasis, basis_type="ORB")
1254 4 : IF (ASSOCIATED(orbbasis)) orb_basis_set_list(ikind)%gto_basis_set => orbbasis
1255 : END DO
1256 2 : NULLIFY (sro_list)
1257 2 : CALL setup_neighbor_list(sro_list, orb_basis_set_list, qs_env=qs_env)
1258 2 : NULLIFY (sro)
1259 2 : NULLIFY (para_env)
1260 2 : CALL get_qs_env(qs_env, ks_env=ks_env, para_env=para_env)
1261 : CALL build_overlap_matrix_simple(ks_env, sro, &
1262 2 : orb_basis_set_list, orb_basis_set_list, sro_list, .TRUE.)
1263 2 : CALL release_neighbor_list_sets(sro_list)
1264 :
1265 : iw = cp_print_key_unit_nr(logger, qs_env%input, "DFT%PRINT%AO_MATRICES/OVERLAP", &
1266 2 : extension=".Log")
1267 2 : CALL section_vals_val_get(qs_env%input, "DFT%PRINT%AO_MATRICES%OMIT_HEADERS", l_val=omit_headers)
1268 2 : CALL section_vals_val_get(qs_env%input, "DFT%PRINT%AO_MATRICES%NDIGITS", i_val=after)
1269 2 : after = MIN(MAX(after, 1), 16)
1270 2 : IF (ASSOCIATED(sro)) THEN
1271 : CALL cp_dbcsr_write_sparse_matrix(sro(1)%matrix, 4, after, qs_env, para_env, &
1272 : output_unit=iw, omit_headers=omit_headers, &
1273 2 : cartesian_basis=.TRUE.)
1274 : END IF
1275 : CALL cp_print_key_finished_output(iw, logger, qs_env%input, &
1276 2 : "DFT%PRINT%AO_MATRICES/OVERLAP")
1277 2 : IF (ASSOCIATED(sro)) CALL dbcsr_deallocate_matrix_set(sro)
1278 4 : DEALLOCATE (orb_basis_set_list)
1279 : END IF
1280 : END IF
1281 : END IF
1282 :
1283 : iw = cp_print_key_unit_nr(logger, dft_section, "PRINT%MO", &
1284 : ignore_should_output=should_output, &
1285 5840 : extension=".MOLog")
1286 :
1287 5840 : IF (iw > 0) THEN
1288 :
1289 2920 : natom = SIZE(particle_set)
1290 2920 : CALL get_qs_kind_set(qs_kind_set, ncgf=ncgf, nsgf=nsgf)
1291 :
1292 : ! Definition of the variable formats
1293 :
1294 2920 : fmtstr1 = "(T2,A,21X, ( X,I5, X))"
1295 2920 : fmtstr2 = "(T2,A,21X, (1X,F . ))"
1296 2920 : fmtstr3 = "(T2,A,I5,1X,I5,1X,A,1X,A6, (1X,F . ))"
1297 :
1298 2920 : width = before + after + 3
1299 2920 : ncol = INT(56/width)
1300 :
1301 2920 : right = MAX((after - 2), 1)
1302 2920 : left = width - right - 5
1303 :
1304 2920 : WRITE (UNIT=fmtstr1(11:12), FMT="(I2)") ncol
1305 2920 : WRITE (UNIT=fmtstr1(14:15), FMT="(I2)") left
1306 2920 : WRITE (UNIT=fmtstr1(21:22), FMT="(I2)") right
1307 :
1308 2920 : WRITE (UNIT=fmtstr2(11:12), FMT="(I2)") ncol
1309 2920 : WRITE (UNIT=fmtstr2(18:19), FMT="(I2)") width - 1
1310 2920 : WRITE (UNIT=fmtstr2(21:22), FMT="(I2)") after
1311 :
1312 2920 : WRITE (UNIT=fmtstr3(27:28), FMT="(I2)") ncol
1313 2920 : WRITE (UNIT=fmtstr3(34:35), FMT="(I2)") width - 1
1314 2920 : WRITE (UNIT=fmtstr3(37:38), FMT="(I2)") after
1315 :
1316 2920 : IF (my_final .OR. (my_solver_method == "TD")) THEN
1317 2920 : energy_str = "EIGENVALUES"
1318 2920 : vector_str = "EIGENVECTORS"
1319 : ELSE
1320 0 : energy_str = "ENERGIES"
1321 0 : vector_str = "COEFFICIENTS"
1322 : END IF
1323 :
1324 2920 : IF (my_rtp) THEN
1325 4 : energy_str = "ZEROS"
1326 4 : vector_str = TRIM(reim)//" RTP COEFFICIENTS"
1327 : END IF
1328 :
1329 2920 : IF (print_eigvecs) THEN
1330 :
1331 1741 : IF (print_cartesian) THEN
1332 :
1333 100 : orbital_str = "CARTESIAN"
1334 :
1335 400 : ALLOCATE (cmatrix(ncgf, ncgf))
1336 100 : cmatrix = 0.0_dp
1337 :
1338 : ! Transform spherical MOs to Cartesian MOs
1339 100 : icgf = 1
1340 100 : isgf = 1
1341 330 : DO iatom = 1, natom
1342 230 : NULLIFY (orb_basis_set, dftb_parameter)
1343 230 : CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
1344 : CALL get_qs_kind(qs_kind_set(ikind), &
1345 : basis_set=orb_basis_set, &
1346 230 : dftb_parameter=dftb_parameter)
1347 560 : IF (ASSOCIATED(orb_basis_set)) THEN
1348 : CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
1349 : nset=nset, &
1350 : nshell=nshell, &
1351 194 : l=l)
1352 614 : DO iset = 1, nset
1353 1196 : DO ishell = 1, nshell(iset)
1354 582 : lshell = l(ishell, iset)
1355 : CALL dgemm("T", "N", nco(lshell), nmo, nso(lshell), 1.0_dp, &
1356 : orbtramat(lshell)%c2s, nso(lshell), &
1357 : smatrix(isgf, 1), nsgf, 0.0_dp, &
1358 582 : cmatrix(icgf, 1), ncgf)
1359 582 : icgf = icgf + nco(lshell)
1360 1002 : isgf = isgf + nso(lshell)
1361 : END DO
1362 : END DO
1363 36 : ELSE IF (ASSOCIATED(dftb_parameter)) THEN
1364 36 : CALL get_dftb_atom_param(dftb_parameter, lmax=lmax)
1365 90 : DO ishell = 1, lmax + 1
1366 54 : lshell = ishell - 1
1367 : CALL dgemm("T", "N", nco(lshell), nsgf, nso(lshell), 1.0_dp, &
1368 : orbtramat(lshell)%c2s, nso(lshell), &
1369 : smatrix(isgf, 1), nsgf, 0.0_dp, &
1370 54 : cmatrix(icgf, 1), ncgf)
1371 54 : icgf = icgf + nco(lshell)
1372 90 : isgf = isgf + nso(lshell)
1373 : END DO
1374 : ELSE
1375 : ! assume atom without basis set
1376 : ! CPABORT("Unknown basis set type")
1377 : END IF
1378 : END DO ! iatom
1379 :
1380 : ELSE
1381 :
1382 1641 : orbital_str = "SPHERICAL"
1383 :
1384 : END IF ! print_cartesian
1385 :
1386 : name = TRIM(energy_str)//", OCCUPATION NUMBERS, AND "// &
1387 1741 : TRIM(orbital_str)//" "//TRIM(vector_str)
1388 :
1389 1741 : IF (.NOT. my_final) THEN
1390 1396 : WRITE (UNIT=name, FMT="(A,1X,I0)") TRIM(name)//step_string, scf_step
1391 : END IF
1392 :
1393 1179 : ELSE IF (print_occup .OR. print_eigvals) THEN
1394 1179 : name = TRIM(energy_str)//" AND OCCUPATION NUMBERS"
1395 :
1396 1179 : IF (.NOT. my_final) THEN
1397 872 : WRITE (UNIT=name, FMT="(A,1X,I0)") TRIM(name)//step_string, scf_step
1398 : END IF
1399 : END IF ! print_eigvecs
1400 :
1401 : ! Print headline
1402 2920 : IF (PRESENT(spin) .AND. (kpoint > 0)) THEN
1403 : WRITE (UNIT=iw, FMT="(/,T2,A,I0)") &
1404 0 : "MO| "//TRIM(spin)//" "//TRIM(name)//" FOR K POINT ", kpoint
1405 : ELSE IF (PRESENT(spin)) THEN
1406 : WRITE (UNIT=iw, FMT="(/,T2,A)") &
1407 476 : "MO| "//TRIM(spin)//" "//TRIM(name)
1408 2444 : ELSE IF (kpoint > 0) THEN
1409 : WRITE (UNIT=iw, FMT="(/,T2,A,I0)") &
1410 295 : "MO| "//TRIM(name)//" FOR K POINT ", kpoint
1411 : ELSE
1412 : WRITE (UNIT=iw, FMT="(/,T2,A)") &
1413 2149 : "MO| "//TRIM(name)
1414 : END IF
1415 :
1416 : ! Check if only a subset of the MOs has to be printed
1417 3186 : IF (ALL(mo_index_range > 0)) THEN
1418 133 : IF (mo_index_range(2) > nmo) THEN
1419 : CALL cp_warn(__LOCATION__, &
1420 7 : "The last orbital index is larger than the number of orbitals.")
1421 : END IF
1422 133 : IF (mo_index_range(1) > mo_index_range(2)) THEN
1423 : CALL cp_warn(__LOCATION__, &
1424 0 : "The first orbital index is larger than the last orbital index.")
1425 : END IF
1426 133 : first_mo = MIN(MAX(1, mo_index_range(1)), nmo)
1427 133 : last_mo = MIN(MAX(first_mo, mo_index_range(2)), nmo)
1428 2787 : ELSE IF (mo_index_range(2) < 0) THEN
1429 0 : IF (mo_index_range(1) > nmo) THEN
1430 : CALL cp_warn(__LOCATION__, &
1431 0 : "The first orbital index is larger than the number of orbitals.")
1432 : END IF
1433 0 : first_mo = MIN(MAX(1, mo_index_range(1)), nmo)
1434 0 : last_mo = nmo
1435 : ELSE
1436 2787 : first_mo = 1
1437 2787 : last_mo = nmo
1438 : END IF
1439 :
1440 2920 : IF (print_eigvecs) THEN
1441 :
1442 : ! Print full MO information
1443 :
1444 3740 : DO icol = first_mo, last_mo, ncol
1445 :
1446 1999 : from = icol
1447 1999 : to = MIN((from + ncol - 1), last_mo)
1448 :
1449 1999 : WRITE (UNIT=iw, FMT="(T2,A)") "MO|"
1450 : WRITE (UNIT=iw, FMT=fmtstr1) &
1451 9426 : "MO|", (jcol, jcol=from, to)
1452 : WRITE (UNIT=iw, FMT=fmtstr2) &
1453 1999 : "MO|", (mo_eigenvalues(jcol), jcol=from, to)
1454 1999 : WRITE (UNIT=iw, FMT="(T2,A)") "MO|"
1455 : WRITE (UNIT=iw, FMT=fmtstr2) &
1456 1999 : "MO|", (mo_occupation_numbers(jcol), jcol=from, to)
1457 1999 : WRITE (UNIT=iw, FMT="(T2,A)") "MO|"
1458 :
1459 1999 : irow = 1
1460 :
1461 8418 : DO iatom = 1, natom
1462 :
1463 4678 : IF (iatom /= 1) WRITE (UNIT=iw, FMT="(T2,A)") "MO|"
1464 :
1465 4678 : NULLIFY (orb_basis_set, dftb_parameter)
1466 : CALL get_atomic_kind(particle_set(iatom)%atomic_kind, &
1467 4678 : element_symbol=element_symbol, kind_number=ikind)
1468 : CALL get_qs_kind(qs_kind_set(ikind), &
1469 : basis_set=orb_basis_set, &
1470 4678 : dftb_parameter=dftb_parameter)
1471 :
1472 11355 : IF (print_cartesian) THEN
1473 :
1474 894 : IF (ASSOCIATED(orb_basis_set)) THEN
1475 : CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
1476 : nset=nset, &
1477 : nshell=nshell, &
1478 : l=l, &
1479 822 : cgf_symbol=bcgf_symbol)
1480 :
1481 822 : icgf = 1
1482 3042 : DO iset = 1, nset
1483 5424 : DO ishell = 1, nshell(iset)
1484 2382 : lshell = l(ishell, iset)
1485 11670 : DO ico = 1, nco(lshell)
1486 : WRITE (UNIT=iw, FMT=fmtstr3) &
1487 7068 : "MO|", irow, iatom, ADJUSTR(element_symbol), bcgf_symbol(icgf), &
1488 14136 : (cmatrix(irow, jcol), jcol=from, to)
1489 7068 : icgf = icgf + 1
1490 9450 : irow = irow + 1
1491 : END DO
1492 : END DO
1493 : END DO
1494 72 : ELSE IF (ASSOCIATED(dftb_parameter)) THEN
1495 72 : CALL get_dftb_atom_param(dftb_parameter, lmax=lmax)
1496 72 : icgf = 1
1497 180 : DO ishell = 1, lmax + 1
1498 108 : lshell = ishell - 1
1499 360 : DO ico = 1, nco(lshell)
1500 180 : symbol = cgf_symbol(1, indco(1:3, icgf))
1501 180 : symbol(1:2) = " "
1502 : WRITE (UNIT=iw, FMT=fmtstr3) &
1503 180 : "MO|", irow, iatom, ADJUSTR(element_symbol), symbol, &
1504 360 : (cmatrix(irow, jcol), jcol=from, to)
1505 180 : icgf = icgf + 1
1506 288 : irow = irow + 1
1507 : END DO
1508 : END DO
1509 : ELSE
1510 : ! assume atom without basis set
1511 : ! CPABORT("Unknown basis set type")
1512 : END IF
1513 :
1514 : ELSE
1515 :
1516 3784 : IF (ASSOCIATED(orb_basis_set)) THEN
1517 : CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
1518 : nset=nset, &
1519 : nshell=nshell, &
1520 : l=l, &
1521 3784 : sgf_symbol=bsgf_symbol)
1522 3784 : isgf = 1
1523 10858 : DO iset = 1, nset
1524 19902 : DO ishell = 1, nshell(iset)
1525 9044 : lshell = l(ishell, iset)
1526 37608 : DO iso = 1, nso(lshell)
1527 : WRITE (UNIT=iw, FMT=fmtstr3) &
1528 21490 : "MO|", irow, iatom, ADJUSTR(element_symbol), bsgf_symbol(isgf), &
1529 42980 : (smatrix(irow, jcol), jcol=from, to)
1530 21490 : isgf = isgf + 1
1531 30534 : irow = irow + 1
1532 : END DO
1533 : END DO
1534 : END DO
1535 0 : ELSE IF (ASSOCIATED(dftb_parameter)) THEN
1536 0 : CALL get_dftb_atom_param(dftb_parameter, lmax=lmax)
1537 0 : isgf = 1
1538 0 : DO ishell = 1, lmax + 1
1539 0 : lshell = ishell - 1
1540 0 : DO iso = 1, nso(lshell)
1541 0 : symbol = sgf_symbol(1, lshell, -lshell + iso - 1)
1542 0 : symbol(1:2) = " "
1543 : WRITE (UNIT=iw, FMT=fmtstr3) &
1544 0 : "MO|", irow, iatom, ADJUSTR(element_symbol), symbol, &
1545 0 : (smatrix(irow, jcol), jcol=from, to)
1546 0 : isgf = isgf + 1
1547 0 : irow = irow + 1
1548 : END DO
1549 : END DO
1550 : ELSE
1551 : ! assume atom without basis set
1552 : ! CPABORT("Unknown basis set type")
1553 : END IF
1554 :
1555 : END IF ! print_cartesian
1556 :
1557 : END DO ! iatom
1558 :
1559 : END DO ! icol
1560 :
1561 1741 : WRITE (UNIT=iw, FMT="(T2,A)") "MO|"
1562 :
1563 : ! Release work storage
1564 :
1565 1741 : IF (print_cartesian) THEN
1566 100 : DEALLOCATE (cmatrix)
1567 : END IF
1568 1741 : DEALLOCATE (smatrix)
1569 :
1570 1179 : ELSE IF (print_occup .OR. print_eigvals) THEN
1571 :
1572 1179 : WRITE (UNIT=iw, FMT="(T2,A)") "MO|"
1573 1179 : fmtstr4 = "(T2,A,I7,3(1X,F22. ))"
1574 1179 : WRITE (UNIT=fmtstr4(19:20), FMT="(I2)") after
1575 1179 : IF (my_final .OR. (my_solver_method == "TD")) THEN
1576 : WRITE (UNIT=iw, FMT="(A)") &
1577 1179 : " MO| Index Eigenvalue [a.u.] Eigenvalue [eV] Occupation"
1578 : ELSE
1579 : WRITE (UNIT=iw, FMT="(A)") &
1580 0 : " MO| Index Energy [a.u.] Energy [eV] Occupation"
1581 : END IF
1582 16222 : DO imo = first_mo, last_mo
1583 : WRITE (UNIT=iw, FMT=fmtstr4) &
1584 15043 : "MO|", imo, mo_eigenvalues(imo), &
1585 15043 : mo_eigenvalues(imo)*evolt, &
1586 31265 : mo_occupation_numbers(imo)
1587 : END DO
1588 1179 : fmtstr5 = "(A,T59,F22. )"
1589 1179 : WRITE (UNIT=fmtstr5(12:13), FMT="(I2)") after
1590 : WRITE (UNIT=iw, FMT=fmtstr5) &
1591 1179 : " MO| Sum:", accurate_sum(mo_occupation_numbers(:))
1592 :
1593 : END IF ! print_eigvecs
1594 :
1595 2920 : IF (.NOT. my_rtp) THEN
1596 2916 : fmtstr6 = "(A,T18,F17. ,A,T41,F17. ,A)"
1597 2916 : WRITE (UNIT=fmtstr6(12:13), FMT="(I2)") after
1598 2916 : WRITE (UNIT=fmtstr6(25:26), FMT="(I2)") after
1599 : WRITE (UNIT=iw, FMT=fmtstr6) &
1600 2916 : " MO| E(Fermi):", chemical_potential, " a.u.", chemical_potential*evolt, " eV"
1601 : END IF
1602 2920 : IF ((homo > 0) .AND. .NOT. my_rtp) THEN
1603 2892 : IF ((mo_occupation_numbers(homo) == maxocc) .AND. (last_mo > homo)) THEN
1604 : gap = mo_eigenvalues(homo + 1) - &
1605 344 : mo_eigenvalues(homo)
1606 : WRITE (UNIT=iw, FMT=fmtstr6) &
1607 344 : " MO| Band gap:", gap, " a.u.", gap*evolt, " eV"
1608 : END IF
1609 : END IF
1610 2920 : WRITE (UNIT=iw, FMT="(A)") ""
1611 :
1612 : END IF ! iw
1613 :
1614 5840 : IF (ALLOCATED(mo_eigenvalues)) DEALLOCATE (mo_eigenvalues)
1615 5840 : IF (ALLOCATED(mo_occupation_numbers)) DEALLOCATE (mo_occupation_numbers)
1616 :
1617 : CALL cp_print_key_finished_output(iw, logger, dft_section, "PRINT%MO", &
1618 5840 : ignore_should_output=should_output)
1619 :
1620 13574 : END SUBROUTINE write_mo_set_to_output_unit
1621 :
1622 : END MODULE qs_mo_io
|