Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2025 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Does all kind of post scf calculations for semi-empirical
10 : !> \par History
11 : !> Started printing preliminary stuff for MO_CUBES and MO requires some
12 : !> more work to complete all other functionalities
13 : !> - Revise MO information printout (10.05.2021, MK)
14 : !> \author Teodoro Laino (07.2008)
15 : ! **************************************************************************************************
16 : MODULE qs_scf_post_se
17 :
18 : USE ai_moments, ONLY: moment
19 : USE atomic_kind_types, ONLY: atomic_kind_type,&
20 : get_atomic_kind
21 : USE basis_set_types, ONLY: gto_basis_set_type
22 : USE cell_types, ONLY: cell_type,&
23 : pbc
24 : USE cp_control_types, ONLY: dft_control_type
25 : USE cp_dbcsr_api, ONLY: dbcsr_get_block_p,&
26 : dbcsr_p_type
27 : USE cp_dbcsr_output, ONLY: cp_dbcsr_write_sparse_matrix
28 : USE cp_log_handling, ONLY: cp_get_default_logger,&
29 : cp_logger_get_default_io_unit,&
30 : cp_logger_type
31 : USE cp_output_handling, ONLY: cp_p_file,&
32 : cp_print_key_finished_output,&
33 : cp_print_key_should_output,&
34 : cp_print_key_unit_nr
35 : USE cp_result_methods, ONLY: cp_results_erase,&
36 : put_results
37 : USE cp_result_types, ONLY: cp_result_type
38 : USE eeq_method, ONLY: eeq_print
39 : USE input_section_types, ONLY: section_get_ival,&
40 : section_vals_get,&
41 : section_vals_get_subs_vals,&
42 : section_vals_type,&
43 : section_vals_val_get
44 : USE kinds, ONLY: default_string_length,&
45 : dp
46 : USE mathconstants, ONLY: twopi,&
47 : z_one,&
48 : z_zero
49 : USE message_passing, ONLY: mp_para_env_type
50 : USE moments_utils, ONLY: get_reference_point
51 : USE orbital_pointers, ONLY: coset,&
52 : ncoset
53 : USE particle_list_types, ONLY: particle_list_type
54 : USE particle_types, ONLY: particle_type
55 : USE physcon, ONLY: debye
56 : USE qs_environment_types, ONLY: get_qs_env,&
57 : qs_environment_type
58 : USE qs_kind_types, ONLY: get_qs_kind,&
59 : qs_kind_type
60 : USE qs_ks_methods, ONLY: qs_ks_update_qs_env
61 : USE qs_ks_types, ONLY: qs_ks_did_change
62 : USE qs_rho_types, ONLY: qs_rho_get,&
63 : qs_rho_type
64 : USE qs_scf_output, ONLY: qs_scf_write_mos
65 : USE qs_scf_types, ONLY: qs_scf_env_type
66 : USE qs_subsys_types, ONLY: qs_subsys_get,&
67 : qs_subsys_type
68 : USE semi_empirical_types, ONLY: get_se_param,&
69 : semi_empirical_type
70 : #include "./base/base_uses.f90"
71 :
72 : IMPLICIT NONE
73 : PRIVATE
74 :
75 : ! Global parameters
76 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_scf_post_se'
77 : PUBLIC :: scf_post_calculation_se
78 :
79 : CONTAINS
80 :
81 : ! **************************************************************************************************
82 : !> \brief collects possible post - scf calculations and prints info / computes properties.
83 : !> specific for Semi-empirical calculations
84 : !> \param qs_env the qs_env in which the qs_env lives
85 : !> \par History
86 : !> 07.2008 created [tlaino] - Split from qs_scf_post (general)
87 : !> \author tlaino
88 : !> \note
89 : !> this function changes mo_eigenvectors and mo_eigenvalues, depending on the print keys.
90 : !> In particular, MO_CUBES causes the MOs to be rotated to make them eigenstates of the KS
91 : !> matrix, and mo_eigenvalues is updated accordingly. This can, for unconverged wavefunctions,
92 : !> change afterwards slightly the forces (hence small numerical differences between MD
93 : !> with and without the debug print level). Ideally this should not happen...
94 : ! **************************************************************************************************
95 7360 : SUBROUTINE scf_post_calculation_se(qs_env)
96 :
97 : TYPE(qs_environment_type), POINTER :: qs_env
98 :
99 : CHARACTER(len=*), PARAMETER :: routineN = 'scf_post_calculation_se'
100 :
101 : INTEGER :: handle, output_unit
102 : LOGICAL :: explicit, my_localized_wfn
103 : TYPE(cp_logger_type), POINTER :: logger
104 : TYPE(mp_para_env_type), POINTER :: para_env
105 : TYPE(particle_list_type), POINTER :: particles
106 : TYPE(qs_rho_type), POINTER :: rho
107 : TYPE(qs_subsys_type), POINTER :: subsys
108 : TYPE(section_vals_type), POINTER :: input, print_key, wfn_mix_section
109 :
110 3680 : CALL timeset(routineN, handle)
111 :
112 : ! Writes the data that is already available in qs_env
113 3680 : CALL write_available_results(qs_env)
114 :
115 3680 : my_localized_wfn = .FALSE.
116 3680 : NULLIFY (rho, subsys, particles, input, print_key, para_env)
117 :
118 3680 : logger => cp_get_default_logger()
119 3680 : output_unit = cp_logger_get_default_io_unit(logger)
120 :
121 3680 : CPASSERT(ASSOCIATED(qs_env))
122 : ! Here we start with data that needs a postprocessing...
123 : CALL get_qs_env(qs_env, &
124 : rho=rho, &
125 : input=input, &
126 : subsys=subsys, &
127 3680 : para_env=para_env)
128 3680 : CALL qs_subsys_get(subsys, particles=particles)
129 :
130 : ! Compute Atomic Charges
131 3680 : CALL qs_scf_post_charges(input, logger, qs_env, rho, para_env)
132 :
133 : ! Moments of charge distribution
134 3680 : CALL qs_scf_post_moments(input, logger, qs_env)
135 :
136 : ! MO_CUBES
137 : print_key => section_vals_get_subs_vals(section_vals=input, &
138 3680 : subsection_name="DFT%PRINT%MO_CUBES")
139 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
140 4 : CPWARN("Printing of MO cube files not implemented for Semi-Empirical method.")
141 : END IF
142 :
143 : ! STM
144 : print_key => section_vals_get_subs_vals(section_vals=input, &
145 3680 : subsection_name="DFT%PRINT%STM")
146 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
147 4 : CPWARN("STM not implemented for Semi-Empirical method.")
148 : END IF
149 :
150 : ! DFT+U
151 : print_key => section_vals_get_subs_vals(section_vals=input, &
152 3680 : subsection_name="DFT%PRINT%PLUS_U")
153 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
154 4 : CPWARN("DFT+U not available for Semi-Empirical method.")
155 : END IF
156 :
157 : ! Kinetic Energy
158 : print_key => section_vals_get_subs_vals(section_vals=input, &
159 3680 : subsection_name="DFT%PRINT%KINETIC_ENERGY")
160 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
161 4 : CPWARN("Kinetic energy not available for Semi-Empirical method.")
162 : END IF
163 :
164 : ! Wavefunction mixing
165 3680 : wfn_mix_section => section_vals_get_subs_vals(input, "DFT%PRINT%WFN_MIX")
166 3680 : CALL section_vals_get(wfn_mix_section, explicit=explicit)
167 3680 : IF (explicit .AND. .NOT. qs_env%run_rtp) THEN
168 0 : CPWARN("Wavefunction mixing not implemented for Semi-Empirical method.")
169 : END IF
170 :
171 : ! Print coherent X-ray diffraction spectrum
172 : print_key => section_vals_get_subs_vals(section_vals=input, &
173 3680 : subsection_name="DFT%PRINT%XRAY_DIFFRACTION_SPECTRUM")
174 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
175 4 : CPWARN("XRAY_DIFFRACTION_SPECTRUM not implemented for Semi-Empirical calculations!")
176 : END IF
177 :
178 : ! Calculation of Electric Field Gradients
179 : print_key => section_vals_get_subs_vals(section_vals=input, &
180 3680 : subsection_name="DFT%PRINT%ELECTRIC_FIELD_GRADIENT")
181 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
182 4 : CPWARN("ELECTRIC_FIELD_GRADIENT not implemented for Semi-Empirical calculations!")
183 : END IF
184 :
185 : ! Calculation of EPR Hyperfine Coupling Tensors
186 : print_key => section_vals_get_subs_vals(section_vals=input, &
187 3680 : subsection_name="DFT%PRINT%HYPERFINE_COUPLING_TENSOR")
188 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), &
189 : cp_p_file)) THEN
190 4 : CPWARN("HYPERFINE_COUPLING_TENSOR not implemented for Semi-Empirical calculations!")
191 : END IF
192 :
193 3680 : CALL timestop(handle)
194 :
195 3680 : END SUBROUTINE scf_post_calculation_se
196 :
197 : ! **************************************************************************************************
198 : !> \brief Computes and prints electric dipole moments
199 : !> We use the approximation for NDDO from
200 : !> Pople and Beveridge, Approximate Molecular Orbital Theory,
201 : !> Mc Graw Hill 1970
202 : !> mu = \sum_A [ Q_A * R_a + Tr(P_A*D_A) ]
203 : !> \param input ...
204 : !> \param logger ...
205 : !> \param qs_env the qs_env in which the qs_env lives
206 : ! **************************************************************************************************
207 3680 : SUBROUTINE qs_scf_post_moments(input, logger, qs_env)
208 : TYPE(section_vals_type), POINTER :: input
209 : TYPE(cp_logger_type), POINTER :: logger
210 : TYPE(qs_environment_type), POINTER :: qs_env
211 :
212 : CHARACTER(LEN=default_string_length) :: description, dipole_type
213 : COMPLEX(KIND=dp) :: dzeta, zeta
214 : COMPLEX(KIND=dp), DIMENSION(3) :: dggamma, dzphase, ggamma, zphase
215 : INTEGER :: i, iat, iatom, ikind, ix, j, nat, natom, &
216 : natorb, nkind, nspin, reference, &
217 : unit_nr
218 : LOGICAL :: do_berry, found
219 : REAL(KIND=dp) :: charge_tot, ci(3), dci(3), dipole(3), dipole_deriv(3), drcc(3), dria(3), &
220 : dtheta, gvec(3), q, rcc(3), ria(3), tcharge(2), theta, tmp(3), via(3), zeff
221 3680 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: ncharge
222 3680 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: mom
223 3680 : REAL(KIND=dp), DIMENSION(:), POINTER :: ref_point
224 3680 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: pblock
225 3680 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
226 : TYPE(cell_type), POINTER :: cell
227 : TYPE(cp_result_type), POINTER :: results
228 3680 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_p
229 : TYPE(dft_control_type), POINTER :: dft_control
230 : TYPE(gto_basis_set_type), POINTER :: basis_set
231 3680 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
232 3680 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
233 : TYPE(qs_rho_type), POINTER :: rho
234 : TYPE(section_vals_type), POINTER :: print_key
235 : TYPE(semi_empirical_type), POINTER :: se_kind
236 :
237 3680 : NULLIFY (results)
238 7360 : print_key => section_vals_get_subs_vals(input, "DFT%PRINT%MOMENTS")
239 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
240 : ! Dipole Moments
241 : unit_nr = cp_print_key_unit_nr(logger, input, "DFT%PRINT%MOMENTS", &
242 26 : extension=".data", middle_name="se_dipole", log_filename=.FALSE.)
243 :
244 : ! Reference point
245 26 : reference = section_get_ival(print_key, keyword_name="REFERENCE")
246 26 : NULLIFY (ref_point)
247 26 : description = '[DIPOLE]'
248 26 : CALL section_vals_val_get(print_key, "REF_POINT", r_vals=ref_point)
249 26 : CALL section_vals_val_get(print_key, "PERIODIC", l_val=do_berry)
250 : CALL get_reference_point(rcc, drcc, qs_env=qs_env, reference=reference, &
251 26 : ref_point=ref_point)
252 : !
253 26 : NULLIFY (particle_set)
254 : CALL get_qs_env(qs_env=qs_env, &
255 : rho=rho, &
256 : cell=cell, &
257 : atomic_kind_set=atomic_kind_set, &
258 : natom=natom, &
259 : qs_kind_set=qs_kind_set, &
260 : particle_set=particle_set, &
261 : results=results, &
262 26 : dft_control=dft_control)
263 :
264 26 : CALL qs_rho_get(rho, rho_ao=matrix_p)
265 26 : nspin = SIZE(matrix_p)
266 26 : nkind = SIZE(atomic_kind_set)
267 : ! net charges
268 78 : ALLOCATE (ncharge(natom))
269 238 : ncharge = 0.0_dp
270 82 : DO ikind = 1, nkind
271 56 : CALL get_atomic_kind(atomic_kind_set(ikind), natom=nat)
272 56 : CALL get_qs_kind(qs_kind_set(ikind), se_parameter=se_kind)
273 56 : CALL get_se_param(se_kind, zeff=zeff, natorb=natorb)
274 350 : DO iatom = 1, nat
275 212 : iat = atomic_kind_set(ikind)%atom_list(iatom)
276 212 : tcharge = 0.0_dp
277 424 : DO i = 1, nspin
278 : CALL dbcsr_get_block_p(matrix=matrix_p(i)%matrix, row=iat, col=iat, &
279 212 : block=pblock, found=found)
280 424 : IF (found) THEN
281 455 : DO j = 1, natorb
282 455 : tcharge(i) = tcharge(i) + pblock(j, j)
283 : END DO
284 : END IF
285 : END DO
286 692 : ncharge(iat) = zeff - SUM(tcharge)
287 : END DO
288 : END DO
289 : ! Contributions from net atomic charges
290 : ! Dipole deriv will be the derivative of the Dipole(dM/dt=\sum e_j v_j)
291 26 : dipole_deriv = 0.0_dp
292 26 : dipole = 0.0_dp
293 26 : IF (do_berry) THEN
294 4 : dipole_type = "periodic (Berry phase)"
295 16 : rcc = pbc(rcc, cell)
296 4 : charge_tot = 0._dp
297 150 : charge_tot = SUM(ncharge)
298 64 : ria = twopi*MATMUL(cell%h_inv, rcc)
299 16 : zphase = CMPLX(COS(ria), SIN(ria), dp)**charge_tot
300 :
301 64 : dria = twopi*MATMUL(cell%h_inv, drcc)
302 16 : dzphase = charge_tot*CMPLX(-SIN(ria), COS(ria), dp)**(charge_tot - 1.0_dp)*dria
303 :
304 16 : ggamma = z_one
305 4 : dggamma = z_zero
306 16 : DO ikind = 1, SIZE(atomic_kind_set)
307 12 : CALL get_atomic_kind(atomic_kind_set(ikind), natom=nat)
308 162 : DO i = 1, nat
309 146 : iat = atomic_kind_set(ikind)%atom_list(i)
310 584 : ria = particle_set(iat)%r(:)
311 584 : ria = pbc(ria, cell)
312 584 : via = particle_set(iat)%v(:)
313 146 : q = ncharge(iat)
314 596 : DO j = 1, 3
315 1752 : gvec = twopi*cell%h_inv(j, :)
316 1752 : theta = SUM(ria(:)*gvec(:))
317 1752 : dtheta = SUM(via(:)*gvec(:))
318 438 : zeta = CMPLX(COS(theta), SIN(theta), KIND=dp)**(-q)
319 438 : dzeta = -q*CMPLX(-SIN(theta), COS(theta), KIND=dp)**(-q - 1.0_dp)*dtheta
320 438 : dggamma(j) = dggamma(j)*zeta + ggamma(j)*dzeta
321 584 : ggamma(j) = ggamma(j)*zeta
322 : END DO
323 : END DO
324 : END DO
325 16 : dggamma = dggamma*zphase + ggamma*dzphase
326 16 : ggamma = ggamma*zphase
327 16 : IF (ALL(REAL(ggamma, KIND=dp) /= 0.0_dp)) THEN
328 16 : tmp = AIMAG(ggamma)/REAL(ggamma, KIND=dp)
329 16 : ci = ATAN(tmp)
330 : dci = (1.0_dp/(1.0_dp + tmp**2))* &
331 : (AIMAG(dggamma)*REAL(ggamma, KIND=dp) - AIMAG(ggamma)* &
332 16 : REAL(dggamma, KIND=dp))/(REAL(ggamma, KIND=dp))**2
333 64 : dipole = MATMUL(cell%hmat, ci)/twopi
334 64 : dipole_deriv = MATMUL(cell%hmat, dci)/twopi
335 : END IF
336 : ELSE
337 22 : dipole_type = "non-periodic"
338 88 : DO i = 1, natom
339 : ! no pbc(particle_set(i)%r(:),cell) so that the total dipole is the sum of the molecular dipoles
340 264 : ria = particle_set(i)%r(:)
341 66 : q = ncharge(i)
342 264 : dipole = dipole - q*(ria - rcc)
343 286 : dipole_deriv(:) = dipole_deriv(:) - q*(particle_set(i)%v(:) - drcc)
344 : END DO
345 : END IF
346 : ! Contributions from atomic polarization
347 : ! No contribution to dipole derivatives
348 82 : DO ikind = 1, nkind
349 56 : CALL get_atomic_kind(atomic_kind_set(ikind), natom=nat)
350 56 : CALL get_qs_kind(qs_kind_set(ikind), basis_set=basis_set)
351 56 : CALL get_qs_kind(qs_kind_set(ikind), se_parameter=se_kind)
352 56 : CALL get_se_param(se_kind, natorb=natorb)
353 280 : ALLOCATE (mom(natorb, natorb, 3))
354 2180 : mom = 0.0_dp
355 56 : CALL atomic_moments(mom, basis_set)
356 268 : DO iatom = 1, nat
357 212 : iat = atomic_kind_set(ikind)%atom_list(iatom)
358 480 : DO i = 1, nspin
359 : CALL dbcsr_get_block_p(matrix=matrix_p(i)%matrix, row=iat, col=iat, &
360 212 : block=pblock, found=found)
361 424 : IF (found) THEN
362 139 : CPASSERT(natorb == SIZE(pblock, 1))
363 139 : ix = coset(1, 0, 0) - 1
364 1479 : dipole(1) = dipole(1) + SUM(pblock*mom(:, :, ix))
365 139 : ix = coset(0, 1, 0) - 1
366 1479 : dipole(2) = dipole(2) + SUM(pblock*mom(:, :, ix))
367 139 : ix = coset(0, 0, 1) - 1
368 1479 : dipole(3) = dipole(3) + SUM(pblock*mom(:, :, ix))
369 : END IF
370 : END DO
371 : END DO
372 194 : DEALLOCATE (mom)
373 : END DO
374 26 : CALL cp_results_erase(results=results, description=description)
375 : CALL put_results(results=results, description=description, &
376 26 : values=dipole(1:3))
377 26 : IF (unit_nr > 0) THEN
378 : WRITE (unit_nr, '(/,T2,A,T31,A50)') &
379 24 : 'SE_DIPOLE| Dipole type', ADJUSTR(TRIM(dipole_type))
380 : WRITE (unit_nr, '(T2,A,T30,3(1X,F16.8))') &
381 24 : 'SE_DIPOLE| Moment [a.u.]', dipole(1:3)
382 : WRITE (unit_nr, '(T2,A,T30,3(1X,F16.8))') &
383 96 : 'SE_DIPOLE| Moment [Debye]', dipole(1:3)*debye
384 : WRITE (unit_nr, '(T2,A,T30,3(1X,F16.8))') &
385 24 : 'SE_DIPOLE| Derivative [a.u.]', dipole_deriv(1:3)
386 : END IF
387 52 : CALL cp_print_key_finished_output(unit_nr, logger, print_key)
388 : END IF
389 :
390 7360 : END SUBROUTINE qs_scf_post_moments
391 :
392 : ! **************************************************************************************************
393 : !> \brief Computes the dipole integrals for an atom (a|x|b), a,b on atom A
394 : !> \param mom ...
395 : !> \param basis_set ...
396 : ! **************************************************************************************************
397 56 : SUBROUTINE atomic_moments(mom, basis_set)
398 : REAL(KIND=dp), DIMENSION(:, :, :) :: mom
399 : TYPE(gto_basis_set_type), POINTER :: basis_set
400 :
401 : INTEGER :: i, iset, jset, ncoa, ncob, nm, nset, &
402 : sgfa, sgfb
403 56 : INTEGER, DIMENSION(:), POINTER :: la_max, la_min, npgf, nsgf
404 56 : INTEGER, DIMENSION(:, :), POINTER :: first_sgf
405 56 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: work
406 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: mab
407 : REAL(KIND=dp), DIMENSION(3) :: rac, rbc
408 56 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: rpgf, sphi, zet
409 :
410 56 : rac = 0.0_dp
411 56 : rbc = 0.0_dp
412 :
413 56 : first_sgf => basis_set%first_sgf
414 56 : la_max => basis_set%lmax
415 56 : la_min => basis_set%lmin
416 56 : npgf => basis_set%npgf
417 56 : nset = basis_set%nset
418 56 : nsgf => basis_set%nsgf_set
419 56 : rpgf => basis_set%pgf_radius
420 56 : sphi => basis_set%sphi
421 56 : zet => basis_set%zet
422 :
423 56 : nm = 0
424 142 : DO iset = 1, nset
425 86 : ncoa = npgf(iset)*ncoset(la_max(iset))
426 142 : nm = MAX(nm, ncoa)
427 : END DO
428 448 : ALLOCATE (mab(nm, nm, 4), work(nm, nm))
429 :
430 142 : DO iset = 1, nset
431 86 : ncoa = npgf(iset)*ncoset(la_max(iset))
432 86 : sgfa = first_sgf(1, iset)
433 288 : DO jset = 1, nset
434 146 : ncob = npgf(jset)*ncoset(la_max(jset))
435 146 : sgfb = first_sgf(1, jset)
436 : !*** Calculate the primitive integrals ***
437 : CALL moment(la_max(iset), npgf(iset), zet(:, iset), rpgf(:, iset), la_min(iset), &
438 146 : la_max(jset), npgf(jset), zet(:, jset), rpgf(:, jset), 1, rac, rbc, mab)
439 : !*** Contraction step ***
440 670 : DO i = 1, 3
441 : CALL dgemm("N", "N", ncoa, nsgf(jset), ncob, 1.0_dp, mab(1, 1, i), SIZE(mab, 1), &
442 438 : sphi(1, sgfb), SIZE(sphi, 1), 0.0_dp, work(1, 1), SIZE(work, 1))
443 : CALL dgemm("T", "N", nsgf(iset), nsgf(jset), ncoa, 1.0_dp, sphi(1, sgfa), SIZE(sphi, 1), &
444 584 : work(1, 1), SIZE(work, 1), 1.0_dp, mom(sgfa, sgfb, i), SIZE(mom, 1))
445 : END DO
446 : END DO
447 : END DO
448 56 : DEALLOCATE (mab, work)
449 :
450 56 : END SUBROUTINE atomic_moments
451 : ! **************************************************************************************************
452 : !> \brief Computes and Prints Atomic Charges with several methods
453 : !> \param input ...
454 : !> \param logger ...
455 : !> \param qs_env the qs_env in which the qs_env lives
456 : !> \param rho ...
457 : !> \param para_env ...
458 : ! **************************************************************************************************
459 3680 : SUBROUTINE qs_scf_post_charges(input, logger, qs_env, rho, para_env)
460 : TYPE(section_vals_type), POINTER :: input
461 : TYPE(cp_logger_type), POINTER :: logger
462 : TYPE(qs_environment_type), POINTER :: qs_env
463 : TYPE(qs_rho_type), POINTER :: rho
464 : TYPE(mp_para_env_type), POINTER :: para_env
465 :
466 : CHARACTER(LEN=2) :: aname
467 : INTEGER :: i, iat, iatom, ikind, j, nat, natom, &
468 : natorb, nkind, nspin, unit_nr
469 : LOGICAL :: found
470 : REAL(KIND=dp) :: npe, zeff
471 3680 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: mcharge
472 3680 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: charges
473 3680 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: pblock
474 3680 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
475 3680 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_p
476 : TYPE(dft_control_type), POINTER :: dft_control
477 3680 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
478 3680 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
479 : TYPE(section_vals_type), POINTER :: print_key
480 : TYPE(semi_empirical_type), POINTER :: se_kind
481 :
482 3680 : NULLIFY (particle_set)
483 : CALL get_qs_env(qs_env=qs_env, &
484 : atomic_kind_set=atomic_kind_set, &
485 : natom=natom, &
486 : qs_kind_set=qs_kind_set, &
487 : particle_set=particle_set, &
488 3680 : dft_control=dft_control)
489 :
490 : ! Compute the mulliken charges
491 3680 : print_key => section_vals_get_subs_vals(input, "DFT%PRINT%MULLIKEN")
492 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
493 2866 : unit_nr = cp_print_key_unit_nr(logger, input, "DFT%PRINT%MULLIKEN", extension=".mulliken", log_filename=.FALSE.)
494 2866 : CALL qs_rho_get(rho, rho_ao=matrix_p)
495 2866 : nspin = SIZE(matrix_p)
496 2866 : npe = REAL(para_env%num_pe, KIND=dp)
497 17196 : ALLOCATE (charges(natom, nspin), mcharge(natom))
498 17342 : charges = 0.0_dp
499 14134 : mcharge = 0.0_dp
500 : ! calculate atomic charges
501 2866 : nkind = SIZE(atomic_kind_set)
502 8810 : DO ikind = 1, nkind
503 5944 : CALL get_atomic_kind(atomic_kind_set(ikind), natom=nat)
504 5944 : CALL get_qs_kind(qs_kind_set(ikind), se_parameter=se_kind)
505 5944 : CALL get_se_param(se_kind, zeff=zeff, natorb=natorb)
506 26022 : DO iatom = 1, nat
507 11268 : iat = atomic_kind_set(ikind)%atom_list(iatom)
508 22794 : DO i = 1, nspin
509 : CALL dbcsr_get_block_p(matrix=matrix_p(i)%matrix, row=iat, col=iat, &
510 11526 : block=pblock, found=found)
511 22794 : IF (found) THEN
512 20982 : DO j = 1, natorb
513 20982 : charges(iat, i) = charges(iat, i) + pblock(j, j)
514 : END DO
515 : END IF
516 : END DO
517 28738 : mcharge(iat) = zeff/npe - SUM(charges(iat, 1:nspin))
518 : END DO
519 : END DO
520 : !
521 2866 : CALL para_env%sum(charges)
522 2866 : CALL para_env%sum(mcharge)
523 : !
524 2866 : IF (unit_nr > 0) THEN
525 1444 : WRITE (UNIT=unit_nr, FMT="(/,/,T2,A)") "POPULATION ANALYSIS"
526 1444 : IF (nspin == 1) THEN
527 : WRITE (UNIT=unit_nr, FMT="(/,T2,A,T70,A)") &
528 1402 : " # Atom Element Kind Atomic population", " Net charge"
529 4312 : DO ikind = 1, nkind
530 2910 : CALL get_atomic_kind(atomic_kind_set(ikind), natom=nat)
531 2910 : CALL get_qs_kind(qs_kind_set(ikind), se_parameter=se_kind, element_symbol=aname)
532 12760 : DO iatom = 1, nat
533 5538 : iat = atomic_kind_set(ikind)%atom_list(iatom)
534 : WRITE (UNIT=unit_nr, &
535 : FMT="(T2,I7,6X,A2,3X,I6,T39,F12.6,T69,F12.6)") &
536 8448 : iat, aname, ikind, charges(iat, 1), mcharge(iat)
537 : END DO
538 : END DO
539 : WRITE (UNIT=unit_nr, &
540 : FMT="(T2,A,T39,F12.6,T69,F12.6,/)") &
541 12478 : "# Total charge", SUM(charges(:, 1)), SUM(mcharge(:))
542 : ELSE
543 : WRITE (UNIT=unit_nr, FMT="(/,T2,A)") &
544 42 : "# Atom Element Kind Atomic population (alpha,beta) Net charge Spin moment"
545 126 : DO ikind = 1, nkind
546 84 : CALL get_atomic_kind(atomic_kind_set(ikind), natom=nat)
547 84 : CALL get_qs_kind(qs_kind_set(ikind), se_parameter=se_kind, element_symbol=aname)
548 339 : DO iatom = 1, nat
549 129 : iat = atomic_kind_set(ikind)%atom_list(iatom)
550 : WRITE (UNIT=unit_nr, &
551 : FMT="(T2,I6,5X,A2,2X,I6,T29,4(1X,F12.6))") &
552 213 : iat, aname, ikind, charges(iat, 1:2), mcharge(iat), charges(iat, 1) - charges(iat, 2)
553 : END DO
554 : END DO
555 : WRITE (UNIT=unit_nr, &
556 : FMT="(T2,A,T29,4(1X,F12.6),/)") &
557 429 : "# Total charge and spin", SUM(charges(:, 1)), SUM(charges(:, 2)), SUM(mcharge(:))
558 : END IF
559 : END IF
560 :
561 2866 : CALL cp_print_key_finished_output(unit_nr, logger, input, "DFT%PRINT%MULLIKEN")
562 :
563 2866 : DEALLOCATE (charges, mcharge)
564 : END IF
565 :
566 : ! EEQ Charges
567 3680 : print_key => section_vals_get_subs_vals(input, "DFT%PRINT%EEQ_CHARGES")
568 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
569 : unit_nr = cp_print_key_unit_nr(logger, input, "DFT%PRINT%EEQ_CHARGES", &
570 4 : extension=".eeq", log_filename=.FALSE.)
571 4 : CALL eeq_print(qs_env, unit_nr, print_level=1, ext=.FALSE.)
572 4 : CALL cp_print_key_finished_output(unit_nr, logger, print_key)
573 : END IF
574 :
575 : ! Compute the Lowdin charges
576 3680 : print_key => section_vals_get_subs_vals(input, "DFT%PRINT%LOWDIN")
577 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
578 4 : CPWARN("Lowdin charges not available for semi-empirical calculations!")
579 : END IF
580 :
581 : ! Hirshfeld charges
582 3680 : print_key => section_vals_get_subs_vals(input, "DFT%PRINT%HIRSHFELD")
583 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
584 2866 : CPWARN("Hirshfeld charges not available for semi-empirical calculations!")
585 : END IF
586 :
587 : ! MAO
588 3680 : print_key => section_vals_get_subs_vals(input, "DFT%PRINT%MAO_ANALYSIS")
589 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
590 4 : CPWARN("MAO analysis not available for semi-empirical calculations!")
591 : END IF
592 :
593 : ! ED
594 3680 : print_key => section_vals_get_subs_vals(input, "DFT%PRINT%ENERGY_DECOMPOSITION_ANALYSIS")
595 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
596 4 : CPWARN("ED analysis not available for semi-empirical calculations!")
597 : END IF
598 :
599 7360 : END SUBROUTINE qs_scf_post_charges
600 :
601 : ! **************************************************************************************************
602 : !> \brief Write QS results always available (if switched on through the print_keys)
603 : !> \param qs_env the qs_env in which the qs_env lives
604 : ! **************************************************************************************************
605 7360 : SUBROUTINE write_available_results(qs_env)
606 : TYPE(qs_environment_type), POINTER :: qs_env
607 :
608 : CHARACTER(len=*), PARAMETER :: routineN = 'write_available_results'
609 :
610 : INTEGER :: after, handle, ispin, iw, output_unit
611 : LOGICAL :: omit_headers
612 : TYPE(cp_logger_type), POINTER :: logger
613 3680 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: ks_rmpv, rho_ao
614 : TYPE(dft_control_type), POINTER :: dft_control
615 : TYPE(mp_para_env_type), POINTER :: para_env
616 : TYPE(particle_list_type), POINTER :: particles
617 3680 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
618 : TYPE(qs_rho_type), POINTER :: rho
619 : TYPE(qs_scf_env_type), POINTER :: scf_env
620 : TYPE(qs_subsys_type), POINTER :: subsys
621 : TYPE(section_vals_type), POINTER :: dft_section, input
622 :
623 3680 : CALL timeset(routineN, handle)
624 3680 : NULLIFY (dft_control, particle_set, rho, ks_rmpv, dft_section, input, &
625 3680 : particles, subsys, para_env, rho_ao)
626 3680 : logger => cp_get_default_logger()
627 3680 : output_unit = cp_logger_get_default_io_unit(logger)
628 :
629 3680 : CPASSERT(ASSOCIATED(qs_env))
630 : CALL get_qs_env(qs_env, &
631 : dft_control=dft_control, &
632 : particle_set=particle_set, &
633 : rho=rho, &
634 : matrix_ks=ks_rmpv, &
635 : input=input, &
636 : subsys=subsys, &
637 : scf_env=scf_env, &
638 3680 : para_env=para_env)
639 3680 : CALL qs_subsys_get(subsys, particles=particles)
640 3680 : CALL qs_rho_get(rho, rho_ao=rho_ao)
641 :
642 : ! Print MO information if requested
643 3680 : CALL qs_scf_write_mos(qs_env, scf_env, final_mos=.TRUE.)
644 :
645 : ! Aat the end of SCF printout the projected DOS for each atomic kind
646 3680 : dft_section => section_vals_get_subs_vals(input, "DFT")
647 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, dft_section, "PRINT%PDOS") &
648 : , cp_p_file)) THEN
649 4 : CPWARN("PDOS not implemented for Semi-Empirical calculations!")
650 : END IF
651 :
652 : ! Print the total density (electronic + core charge)
653 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
654 : "DFT%PRINT%TOT_DENSITY_CUBE"), cp_p_file)) THEN
655 4 : CPWARN("TOT_DENSITY_CUBE not implemented for Semi-Empirical calculations!")
656 : END IF
657 :
658 : ! Write cube file with electron density
659 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
660 : "DFT%PRINT%E_DENSITY_CUBE"), cp_p_file)) THEN
661 4 : CPWARN("E_DENSITY_CUBE not implemented for Semi-Empirical calculations!")
662 : END IF ! print key
663 :
664 : ! Write cube file with EFIELD
665 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
666 : "DFT%PRINT%EFIELD_CUBE"), cp_p_file)) THEN
667 4 : CPWARN("EFIELD_CUBE not implemented for Semi-Empirical calculations!")
668 : END IF ! print key
669 :
670 : ! Write cube file with ELF
671 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
672 : "DFT%PRINT%ELF_CUBE"), cp_p_file)) THEN
673 4 : CPWARN("ELF function not implemented for Semi-Empirical calculations!")
674 : END IF ! print key
675 :
676 : ! Print the hartree potential
677 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
678 : "DFT%PRINT%V_HARTREE_CUBE"), cp_p_file)) THEN
679 4 : CPWARN("V_HARTREE_CUBE not implemented for Semi-Empirical calculations!")
680 : END IF
681 :
682 : ! Print the XC potential
683 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
684 : "DFT%PRINT%V_XC_CUBE"), cp_p_file)) THEN
685 4 : CPWARN("V_XC_CUBE not available for Semi-Empirical calculations!")
686 : END IF
687 :
688 : ! Write the density matrix
689 3680 : CALL section_vals_val_get(input, "DFT%PRINT%AO_MATRICES%OMIT_HEADERS", l_val=omit_headers)
690 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
691 : "DFT%PRINT%AO_MATRICES/DENSITY"), cp_p_file)) THEN
692 : iw = cp_print_key_unit_nr(logger, input, "DFT%PRINT%AO_MATRICES/DENSITY", &
693 780 : extension=".Log")
694 780 : CALL section_vals_val_get(input, "DFT%PRINT%AO_MATRICES%NDIGITS", i_val=after)
695 780 : after = MIN(MAX(after, 1), 16)
696 1566 : DO ispin = 1, dft_control%nspins
697 : CALL cp_dbcsr_write_sparse_matrix(rho_ao(ispin)%matrix, 4, after, qs_env, &
698 1566 : para_env, output_unit=iw, omit_headers=omit_headers)
699 : END DO
700 : CALL cp_print_key_finished_output(iw, logger, input, &
701 780 : "DFT%PRINT%AO_MATRICES/DENSITY")
702 : END IF
703 :
704 : ! The Kohn-Sham matrix itself
705 3680 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
706 : "DFT%PRINT%AO_MATRICES/KOHN_SHAM_MATRIX"), cp_p_file)) THEN
707 632 : CALL qs_ks_update_qs_env(qs_env, calculate_forces=.FALSE., just_energy=.FALSE.)
708 632 : CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
709 : iw = cp_print_key_unit_nr(logger, input, "DFT%PRINT%AO_MATRICES/KOHN_SHAM_MATRIX", &
710 632 : extension=".Log")
711 632 : CALL section_vals_val_get(input, "DFT%PRINT%AO_MATRICES%NDIGITS", i_val=after)
712 632 : after = MIN(MAX(after, 1), 16)
713 : CALL cp_dbcsr_write_sparse_matrix(ks_rmpv(1)%matrix, 4, after, qs_env, &
714 632 : para_env, output_unit=iw, omit_headers=omit_headers)
715 : CALL cp_print_key_finished_output(iw, logger, input, &
716 632 : "DFT%PRINT%AO_MATRICES/KOHN_SHAM_MATRIX")
717 : END IF
718 :
719 3680 : CALL timestop(handle)
720 :
721 3680 : END SUBROUTINE write_available_results
722 :
723 : END MODULE qs_scf_post_se
|