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 Writer for CASINO gwfn.data files.
10 : !> \par History
11 : !> 05.2026 created [Codex]
12 : ! **************************************************************************************************
13 : MODULE casino_utils
14 :
15 : USE atomic_kind_types, ONLY: get_atomic_kind
16 : USE basis_set_types, ONLY: get_gto_basis_set,&
17 : gto_basis_set_type
18 : USE cell_types, ONLY: cell_type,&
19 : pbc,&
20 : pbc_stable,&
21 : real_to_scaled
22 : USE cp2k_info, ONLY: cp2k_version
23 : USE cp_blacs_env, ONLY: cp_blacs_env_type
24 : USE cp_control_types, ONLY: dft_control_type
25 : USE cp_dbcsr_api, ONLY: dbcsr_p_type
26 : USE cp_dbcsr_operations, ONLY: copy_dbcsr_to_fm
27 : USE cp_files, ONLY: close_file,&
28 : open_file
29 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
30 : cp_fm_struct_release,&
31 : cp_fm_struct_type
32 : USE cp_fm_types, ONLY: cp_fm_create,&
33 : cp_fm_get_submatrix,&
34 : cp_fm_release,&
35 : cp_fm_set_all,&
36 : cp_fm_to_fm_submat_general,&
37 : cp_fm_type
38 : USE cp_log_handling, ONLY: cp_get_default_logger,&
39 : cp_logger_get_default_io_unit,&
40 : cp_logger_type
41 : USE external_potential_types, ONLY: get_potential,&
42 : gth_potential_type,&
43 : sgp_potential_type
44 : USE input_section_types, ONLY: section_vals_type,&
45 : section_vals_val_get
46 : USE kinds, ONLY: default_path_length,&
47 : default_string_length,&
48 : dp
49 : USE kpoint_methods, ONLY: kpoint_env_initialize,&
50 : kpoint_init_cell_index,&
51 : kpoint_initialize,&
52 : kpoint_initialize_mo_set,&
53 : kpoint_initialize_mos
54 : USE kpoint_types, ONLY: get_kpoint_env,&
55 : get_kpoint_info,&
56 : kpoint_create,&
57 : kpoint_env_p_type,&
58 : kpoint_release,&
59 : kpoint_type
60 : USE mathconstants, ONLY: pi,&
61 : rootpi
62 : USE message_passing, ONLY: mp_para_env_type
63 : USE orbital_pointers, ONLY: nso
64 : USE particle_types, ONLY: particle_type
65 : USE qs_environment_types, ONLY: get_qs_env,&
66 : qs_environment_type
67 : USE qs_kind_types, ONLY: get_qs_kind,&
68 : get_qs_kind_set,&
69 : qs_kind_type
70 : USE qs_mo_types, ONLY: get_mo_set,&
71 : mo_set_type
72 : USE qs_neighbor_list_types, ONLY: neighbor_list_set_p_type
73 : USE qs_scf_diagonalization, ONLY: do_general_diag_kp
74 : USE qs_scf_types, ONLY: qs_scf_env_type
75 : USE qs_wannier90, ONLY: prepare_wannier90_scf_mos
76 : USE scf_control_types, ONLY: scf_control_type
77 : USE string_utilities, ONLY: lowercase
78 : #include "./base/base_uses.f90"
79 :
80 : IMPLICIT NONE
81 :
82 : PRIVATE
83 :
84 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'casino_utils'
85 : INTEGER, PARAMETER, PRIVATE :: max_casino_l = 4
86 :
87 : PUBLIC :: write_casino
88 :
89 : CONTAINS
90 :
91 : ! **************************************************************************************************
92 : !> \brief Write a CASINO gwfn.data file from the converged GPW/GAPW wavefunction.
93 : !> \param qs_env the QS environment
94 : !> \param casino_section the DFT%PRINT%CASINO input section
95 : ! **************************************************************************************************
96 10 : SUBROUTINE write_casino(qs_env, casino_section)
97 : TYPE(qs_environment_type), INTENT(IN), POINTER :: qs_env
98 : TYPE(section_vals_type), INTENT(IN), POINTER :: casino_section
99 :
100 : CHARACTER(LEN=*), PARAMETER :: routineN = 'write_casino'
101 :
102 : CHARACTER(len=default_path_length) :: filename
103 : INTEGER :: ao_num, col_offset, handle, iao, iatom, ikind, ikp, ikp_loc, ikp_out, imo, ipgf, &
104 : iset, ishell, ishell_loc, ispin, iw, k, l, mo_num, nao_shell, natoms, nel_tot, &
105 : ngth_pseudo, nkp, nkp_mo, nkp_out, nmo, npseudo_atoms, nreal_k, nset, nsgf, nsgp_pseudo, &
106 : nspins, output_unit, periodicity, prim_num, shell_num, zatom
107 10 : INTEGER, ALLOCATABLE, DIMENSION(:) :: agauge, ao_to_atom, atomic_number, cp2k_to_casino_ao, &
108 10 : first_shell, kp_order, prim_per_shell, shell_ang_mom, shell_type
109 : INTEGER, DIMENSION(2) :: kp_range, nmo_spin
110 10 : INTEGER, DIMENSION(:), POINTER :: npgf, nshell
111 10 : INTEGER, DIMENSION(:, :), POINTER :: l_shell_set
112 : LOGICAL :: casino_kpoints_created, do_kpoints, &
113 : ionode, periodic, use_real_wfn, &
114 : write_pseudos
115 10 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: kp_real
116 : REAL(KIND=dp) :: cval, e_nn, eps_kpoint_real, kdotg, &
117 : pseudo_tol, sval, zeff
118 10 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: coefficients, exponents, mo_scale, &
119 10 : valence_charge
120 10 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: coord, kvec, mo_energy, mos_sgf, &
121 10 : mos_sgf_im, shell_position
122 : REAL(KIND=dp), DIMENSION(3) :: r_pbc, scoord, scoord_pbc
123 10 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: xkp, zetas
124 10 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: gcc
125 : TYPE(cell_type), POINTER :: cell
126 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
127 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
128 : TYPE(cp_fm_type) :: fm_dummy, fm_mo_coeff, fm_mo_coeff_im
129 : TYPE(cp_logger_type), POINTER :: logger
130 : TYPE(dft_control_type), POINTER :: dft_control
131 : TYPE(gth_potential_type), POINTER :: gth_potential
132 : TYPE(gto_basis_set_type), POINTER :: basis_set
133 10 : TYPE(kpoint_env_p_type), DIMENSION(:), POINTER :: kp_env
134 : TYPE(kpoint_type), POINTER :: casino_kpoints, kpoints
135 10 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
136 10 : TYPE(mo_set_type), DIMENSION(:, :), POINTER :: mos_kp
137 : TYPE(mp_para_env_type), POINTER :: para_env, para_env_inter_kp
138 10 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
139 10 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: kind_set
140 : TYPE(sgp_potential_type), POINTER :: sgp_potential
141 :
142 10 : CALL timeset(routineN, handle)
143 :
144 10 : NULLIFY (basis_set, blacs_env, casino_kpoints, cell, dft_control, fm_struct, gcc, &
145 10 : gth_potential, kind_set, kp_env, kpoints, l_shell_set, logger, mos, mos_kp, npgf, &
146 10 : nshell, para_env, para_env_inter_kp, particle_set, sgp_potential, xkp, zetas)
147 :
148 10 : logger => cp_get_default_logger()
149 10 : output_unit = cp_logger_get_default_io_unit(logger)
150 :
151 10 : CPASSERT(ASSOCIATED(qs_env))
152 :
153 10 : CALL section_vals_val_get(casino_section, "FILENAME", c_val=filename)
154 10 : IF (LEN_TRIM(filename) == 0) filename = "gwfn.data"
155 10 : CALL section_vals_val_get(casino_section, "EPS_KPOINT_REAL", r_val=eps_kpoint_real)
156 10 : CALL section_vals_val_get(casino_section, "WRITE_PSEUDOPOTENTIALS", l_val=write_pseudos)
157 :
158 10 : CALL get_qs_env(qs_env, para_env=para_env)
159 10 : ionode = para_env%is_source()
160 :
161 : CALL get_qs_env(qs_env, cell=cell, particle_set=particle_set, qs_kind_set=kind_set, &
162 : natom=natoms, dft_control=dft_control, nelectron_total=nel_tot, &
163 10 : do_kpoints=do_kpoints, kpoints=kpoints, blacs_env=blacs_env)
164 10 : casino_kpoints => kpoints
165 : casino_kpoints_created = .FALSE.
166 : CALL prepare_casino_kpoint_grid(qs_env, casino_section, do_kpoints, kpoints, &
167 10 : casino_kpoints, casino_kpoints_created)
168 10 : nspins = dft_control%nspins
169 10 : IF (nspins > 2) CPABORT("CASINO gwfn.data supports at most two spin channels.")
170 :
171 40 : periodicity = COUNT(cell%perd /= 0)
172 10 : periodic = periodicity > 0
173 10 : pseudo_tol = 1.0E-8_dp
174 :
175 70 : ALLOCATE (coord(3, natoms), atomic_number(natoms), valence_charge(natoms))
176 10 : npseudo_atoms = 0
177 10 : ngth_pseudo = 0
178 10 : nsgp_pseudo = 0
179 28 : DO iatom = 1, natoms
180 72 : coord(:, iatom) = particle_set(iatom)%r(1:3)
181 18 : CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
182 : CALL get_qs_kind(kind_set(ikind), zatom=zatom, zeff=zeff, &
183 18 : gth_potential=gth_potential, sgp_potential=sgp_potential)
184 18 : IF (ABS(zeff) < pseudo_tol) zeff = REAL(zatom, KIND=dp)
185 18 : atomic_number(iatom) = zatom
186 18 : IF (ASSOCIATED(gth_potential) .OR. ASSOCIATED(sgp_potential)) THEN
187 8 : atomic_number(iatom) = zatom + 200
188 8 : npseudo_atoms = npseudo_atoms + 1
189 8 : IF (ASSOCIATED(gth_potential)) ngth_pseudo = ngth_pseudo + 1
190 8 : IF (ASSOCIATED(sgp_potential)) nsgp_pseudo = nsgp_pseudo + 1
191 10 : ELSE IF (ABS(zeff - REAL(zatom, KIND=dp)) > pseudo_tol) THEN
192 0 : atomic_number(iatom) = zatom + 200
193 0 : npseudo_atoms = npseudo_atoms + 1
194 : END IF
195 46 : valence_charge(iatom) = zeff
196 : END DO
197 :
198 10 : IF (ionode .AND. write_pseudos .AND. nsgp_pseudo > 0) THEN
199 1 : CALL write_casino_sgp_pseudopotentials(kind_set, particle_set, natoms, filename, output_unit)
200 : END IF
201 :
202 10 : IF (periodic) THEN
203 2 : CALL periodic_nuclear_repulsion_energy(cell, periodicity, coord, valence_charge, e_nn)
204 : ELSE
205 8 : CALL nuclear_repulsion_energy(particle_set, kind_set, e_nn)
206 : END IF
207 10 : e_nn = e_nn/REAL(natoms, KIND=dp)
208 :
209 10 : IF (do_kpoints) THEN
210 2 : CALL get_kpoint_info(casino_kpoints, nkp=nkp, xkp=xkp, use_real_wfn=use_real_wfn)
211 : ELSE
212 8 : nkp = 1
213 8 : use_real_wfn = .TRUE.
214 : END IF
215 10 : nkp_mo = MERGE(nkp, 1, do_kpoints)
216 :
217 60 : ALLOCATE (kp_order(nkp_mo), kp_real(nkp_mo), kvec(3, nkp_mo))
218 : CALL build_kpoint_order(cell, periodic, do_kpoints, nkp, xkp, eps_kpoint_real, &
219 10 : kp_order, kp_real, nkp_out, nreal_k, kvec)
220 18 : IF (do_kpoints .AND. use_real_wfn .AND. ANY(.NOT. kp_real(1:nkp_out))) THEN
221 0 : CPABORT("CASINO complex k-points require CP2K complex k-point wavefunctions.")
222 : END IF
223 :
224 10 : CALL get_qs_kind_set(kind_set, nshell=shell_num, npgf_seg=prim_num, nsgf=nsgf)
225 10 : ao_num = nsgf
226 :
227 0 : ALLOCATE (shell_type(shell_num), prim_per_shell(shell_num), first_shell(natoms + 1), &
228 0 : shell_ang_mom(shell_num), shell_position(3, shell_num), &
229 0 : exponents(prim_num), coefficients(prim_num), ao_to_atom(ao_num), &
230 170 : cp2k_to_casino_ao(ao_num), mo_scale(ao_num))
231 :
232 10 : ishell = 0
233 10 : ipgf = 0
234 10 : iao = 0
235 28 : DO iatom = 1, natoms
236 18 : first_shell(iatom) = ishell + 1
237 18 : CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
238 18 : CALL get_qs_kind(kind_set(ikind), basis_set=basis_set, basis_type="ORB")
239 : CALL get_gto_basis_set(basis_set, nset=nset, nshell=nshell, npgf=npgf, &
240 18 : zet=zetas, gcc=gcc, l=l_shell_set)
241 74 : DO iset = 1, nset
242 86 : DO ishell_loc = 1, nshell(iset)
243 40 : ishell = ishell + 1
244 40 : l = l_shell_set(ishell_loc, iset)
245 40 : IF (l > max_casino_l) THEN
246 0 : CPABORT("CASINO writer currently supports harmonic Gaussian shells up to g.")
247 : END IF
248 40 : shell_ang_mom(ishell) = l
249 40 : shell_type(ishell) = casino_shell_type(l)
250 40 : prim_per_shell(ishell) = npgf(iset)
251 160 : shell_position(:, ishell) = particle_set(iatom)%r(1:3)
252 : CALL casino_shell_coefficients(l, npgf(iset), zetas(1:npgf(iset), iset), &
253 : gcc(1:npgf(iset), ishell_loc, iset), &
254 : exponents(ipgf + 1:ipgf + npgf(iset)), &
255 40 : coefficients(ipgf + 1:ipgf + npgf(iset)))
256 40 : nao_shell = nso(l)
257 88 : DO k = 1, nao_shell
258 48 : cp2k_to_casino_ao(iao + k) = iao + casino_cp2k_index(l, k)
259 48 : mo_scale(iao + k) = casino_mo_scale(l, k)
260 88 : ao_to_atom(iao + k) = iatom
261 : END DO
262 40 : ipgf = ipgf + npgf(iset)
263 68 : iao = iao + nao_shell
264 : END DO
265 : END DO
266 : END DO
267 10 : first_shell(natoms + 1) = shell_num + 1
268 10 : CPASSERT(ishell == shell_num)
269 10 : CPASSERT(ipgf == prim_num)
270 10 : CPASSERT(iao == ao_num)
271 :
272 40 : ALLOCATE (mo_energy(ao_num, nkp_mo*nspins))
273 10 : mo_energy(:, :) = 0.0_dp
274 10 : nmo_spin(:) = 0
275 :
276 10 : IF (do_kpoints) THEN
277 2 : CALL get_kpoint_info(casino_kpoints, kp_env=kp_env, kp_range=kp_range, nkp=nkp)
278 2 : CALL get_kpoint_env(kp_env(1)%kpoint_env, mos=mos_kp)
279 4 : DO ispin = 1, nspins
280 2 : CALL get_mo_set(mos_kp(1, ispin), nmo=nmo)
281 2 : IF (nmo < ao_num) THEN
282 0 : CPABORT("CASINO gwfn.data requires a complete MO set. Increase ADDED_MOS.")
283 : END IF
284 6 : nmo_spin(ispin) = nmo
285 : END DO
286 6 : mo_num = nkp*SUM(nmo_spin)
287 : CALL cp_fm_struct_create(fm_struct, para_env=para_env, context=blacs_env, &
288 2 : nrow_global=nsgf, ncol_global=mo_num)
289 2 : CALL cp_fm_create(fm_mo_coeff, fm_struct)
290 2 : CALL cp_fm_set_all(fm_mo_coeff, 0.0_dp)
291 2 : IF (.NOT. use_real_wfn) THEN
292 2 : CALL cp_fm_create(fm_mo_coeff_im, fm_struct)
293 2 : CALL cp_fm_set_all(fm_mo_coeff_im, 0.0_dp)
294 : END IF
295 2 : CALL cp_fm_struct_release(fm_struct)
296 :
297 4 : DO ispin = 1, nspins
298 8 : DO ikp = 1, nkp
299 4 : nmo = nmo_spin(ispin)
300 4 : col_offset = (ikp - 1)*nmo + (ispin - 1)*nmo_spin(1)*nkp
301 6 : IF (ikp >= kp_range(1) .AND. ikp <= kp_range(2)) THEN
302 4 : ikp_loc = ikp - kp_range(1) + 1
303 4 : CALL get_kpoint_env(kp_env(ikp_loc)%kpoint_env, mos=mos_kp)
304 4 : IF (mos_kp(1, ispin)%use_mo_coeff_b) THEN
305 0 : CALL copy_dbcsr_to_fm(mos_kp(1, ispin)%mo_coeff_b, mos_kp(1, ispin)%mo_coeff)
306 : END IF
307 : CALL cp_fm_to_fm_submat_general(mos_kp(1, ispin)%mo_coeff, fm_mo_coeff, &
308 4 : nsgf, nmo, 1, 1, 1, col_offset + 1, blacs_env)
309 : mo_energy(1:ao_num, ikp + (ispin - 1)*nkp_mo) = &
310 20 : mos_kp(1, ispin)%eigenvalues(1:ao_num)
311 4 : IF (.NOT. use_real_wfn) THEN
312 4 : IF (mos_kp(2, ispin)%use_mo_coeff_b) THEN
313 0 : CALL copy_dbcsr_to_fm(mos_kp(2, ispin)%mo_coeff_b, mos_kp(2, ispin)%mo_coeff)
314 : END IF
315 : CALL cp_fm_to_fm_submat_general(mos_kp(2, ispin)%mo_coeff, fm_mo_coeff_im, &
316 4 : nsgf, nmo, 1, 1, 1, col_offset + 1, blacs_env)
317 : END IF
318 : ELSE
319 : CALL cp_fm_to_fm_submat_general(fm_dummy, fm_mo_coeff, &
320 0 : nsgf, nmo, 1, 1, 1, col_offset + 1, blacs_env)
321 0 : IF (.NOT. use_real_wfn) THEN
322 : CALL cp_fm_to_fm_submat_general(fm_dummy, fm_mo_coeff_im, &
323 0 : nsgf, nmo, 1, 1, 1, col_offset + 1, blacs_env)
324 : END IF
325 : END IF
326 : END DO
327 : END DO
328 2 : CALL get_kpoint_info(casino_kpoints, para_env_inter_kp=para_env_inter_kp)
329 2 : CALL para_env_inter_kp%sum(mo_energy)
330 : ELSE
331 8 : CALL get_qs_env(qs_env, mos=mos)
332 18 : DO ispin = 1, nspins
333 10 : CALL get_mo_set(mos(ispin), nmo=nmo)
334 10 : IF (nmo < ao_num) THEN
335 0 : CPABORT("CASINO gwfn.data requires a complete MO set. Increase ADDED_MOS.")
336 : END IF
337 10 : nmo_spin(ispin) = nmo
338 72 : mo_energy(1:ao_num, 1 + (ispin - 1)*nkp_mo) = mos(ispin)%eigenvalues(1:ao_num)
339 : END DO
340 : END IF
341 :
342 10 : IF (do_kpoints .AND. .NOT. use_real_wfn) THEN
343 6 : ALLOCATE (agauge(3*natoms))
344 6 : DO iatom = 1, natoms
345 4 : CALL real_to_scaled(scoord, particle_set(iatom)%r(1:3), cell)
346 4 : IF (kpoints%symmetry) THEN
347 4 : r_pbc = pbc_stable(particle_set(iatom)%r(1:3), cell)
348 : ELSE
349 0 : r_pbc = pbc(particle_set(iatom)%r(1:3), cell)
350 : END IF
351 4 : CALL real_to_scaled(scoord_pbc, r_pbc, cell)
352 18 : agauge(3*(iatom - 1) + 1:3*iatom) = NINT(scoord_pbc - scoord)
353 : END DO
354 : END IF
355 :
356 10 : IF (ionode) THEN
357 5 : IF (npseudo_atoms > 0) THEN
358 2 : WRITE (output_unit, "((T2,A,I0,A))") "CASINO| Marked ", npseudo_atoms, &
359 4 : " pseudopotential atoms in gwfn.data."
360 2 : IF (ngth_pseudo > 0) THEN
361 : WRITE (output_unit, "((T2,A))") &
362 1 : "CASINO| GTH pseudopotentials require matching external CASINO *_pp.data files."
363 : END IF
364 2 : IF (.NOT. write_pseudos) THEN
365 : WRITE (output_unit, "((T2,A))") &
366 1 : "CASINO| WRITE_PSEUDOPOTENTIALS is disabled; provide CASINO *_pp.data files manually."
367 : END IF
368 : END IF
369 5 : WRITE (output_unit, "((T2,A,A))") 'CASINO| Writing gwfn.data file ', TRIM(filename)
370 : CALL open_file(file_name=filename, file_status="REPLACE", file_action="WRITE", &
371 5 : file_form="FORMATTED", unit_number=iw)
372 : CALL write_casino_header(iw, periodicity, nspins, e_nn, nel_tot, natoms, coord, &
373 : atomic_number, valence_charge, cell, periodic, nkp_out, nreal_k, &
374 : kvec, shell_num, ao_num, prim_num, shell_ang_mom, shell_type, &
375 5 : prim_per_shell, first_shell, exponents, coefficients, shell_position)
376 : END IF
377 :
378 60 : ALLOCATE (mos_sgf(nsgf, ao_num), mos_sgf_im(nsgf, ao_num))
379 10 : mos_sgf(:, :) = 0.0_dp
380 10 : mos_sgf_im(:, :) = 0.0_dp
381 :
382 10 : IF (do_kpoints) THEN
383 4 : DO ispin = 1, nspins
384 6 : DO ikp_out = 1, nkp_out
385 2 : ikp = kp_order(ikp_out)
386 2 : col_offset = (ikp - 1)*nmo_spin(ispin) + (ispin - 1)*nmo_spin(1)*nkp
387 2 : CALL cp_fm_get_submatrix(fm_mo_coeff, mos_sgf, 1, col_offset + 1, nsgf, ao_num)
388 2 : IF (.NOT. use_real_wfn) THEN
389 2 : CALL cp_fm_get_submatrix(fm_mo_coeff_im, mos_sgf_im, 1, col_offset + 1, nsgf, ao_num)
390 10 : DO iao = 1, ao_num
391 8 : iatom = ao_to_atom(iao)
392 : kdotg = 2.0_dp*pi*DOT_PRODUCT(xkp(:, ikp), &
393 32 : REAL(agauge(3*(iatom - 1) + 1:3*iatom), KIND=dp))
394 8 : cval = COS(kdotg)
395 8 : sval = SIN(kdotg)
396 42 : DO imo = 1, ao_num
397 : CALL rotate_complex_pair(mos_sgf(cp2k_to_casino_ao(iao), imo), &
398 40 : mos_sgf_im(cp2k_to_casino_ao(iao), imo), cval, sval)
399 : END DO
400 : END DO
401 : ELSE
402 0 : mos_sgf_im(:, :) = 0.0_dp
403 : END IF
404 4 : IF (ionode) THEN
405 : CALL write_casino_orbitals(iw, mos_sgf, mos_sgf_im, cp2k_to_casino_ao, mo_scale, &
406 1 : ao_num,.NOT. kp_real(ikp_out))
407 : END IF
408 : END DO
409 : END DO
410 : ELSE
411 18 : DO ispin = 1, nspins
412 10 : IF (mos(ispin)%use_mo_coeff_b) THEN
413 0 : CALL copy_dbcsr_to_fm(mos(ispin)%mo_coeff_b, mos(ispin)%mo_coeff)
414 : END IF
415 10 : CALL cp_fm_get_submatrix(mos(ispin)%mo_coeff, mos_sgf, 1, 1, nsgf, ao_num)
416 10 : mos_sgf_im(:, :) = 0.0_dp
417 18 : IF (ionode) THEN
418 : CALL write_casino_orbitals(iw, mos_sgf, mos_sgf_im, cp2k_to_casino_ao, mo_scale, &
419 5 : ao_num, .FALSE.)
420 : END IF
421 : END DO
422 : END IF
423 :
424 10 : IF (ionode) THEN
425 5 : WRITE (iw, *)
426 5 : IF (periodic) THEN
427 1 : WRITE (iw, '(A)') "EIGENVALUES"
428 1 : WRITE (iw, '(A)') "-----------"
429 2 : DO ikp_out = 1, nkp_out
430 1 : ikp = kp_order(ikp_out)
431 3 : DO ispin = 1, nspins
432 1 : IF (nspins == 1) THEN
433 1 : WRITE (iw, '(A,I6,3F14.8)') "k", ikp_out, kvec(:, ikp_out)
434 : ELSE
435 0 : WRITE (iw, '(A,I3,A,I6,3F14.8)') "spin", ispin, " k", ikp_out, kvec(:, ikp_out)
436 : END IF
437 2 : CALL write_real_vector(iw, mo_energy(1:ao_num, ikp + (ispin - 1)*nkp_mo))
438 : END DO
439 : END DO
440 : END IF
441 5 : CALL close_file(unit_number=iw)
442 : END IF
443 :
444 10 : DEALLOCATE (mos_sgf, mos_sgf_im)
445 10 : IF (do_kpoints) THEN
446 2 : CALL cp_fm_release(fm_mo_coeff)
447 2 : IF (.NOT. use_real_wfn) CALL cp_fm_release(fm_mo_coeff_im)
448 : END IF
449 10 : IF (casino_kpoints_created) CALL kpoint_release(casino_kpoints)
450 10 : IF (ALLOCATED(agauge)) DEALLOCATE (agauge)
451 0 : DEALLOCATE (ao_to_atom, atomic_number, coefficients, coord, cp2k_to_casino_ao, exponents, &
452 0 : first_shell, kp_order, kp_real, kvec, mo_energy, mo_scale, prim_per_shell, &
453 10 : shell_ang_mom, shell_position, shell_type, valence_charge)
454 :
455 10 : CALL timestop(handle)
456 60 : END SUBROUTINE write_casino
457 :
458 : ! **************************************************************************************************
459 : !> \brief Write CASINO pseudopotential files for the semilocal ECP kinds.
460 : !> \param kind_set the QS kinds
461 : !> \param particle_set the particle set
462 : !> \param natoms the number of atoms
463 : !> \param gwfn_filename the gwfn.data filename
464 : !> \param output_unit output unit for log messages
465 : ! **************************************************************************************************
466 1 : SUBROUTINE write_casino_sgp_pseudopotentials(kind_set, particle_set, natoms, gwfn_filename, output_unit)
467 : TYPE(qs_kind_type), DIMENSION(:), INTENT(IN), &
468 : POINTER :: kind_set
469 : TYPE(particle_type), DIMENSION(:), INTENT(IN), &
470 : POINTER :: particle_set
471 : INTEGER, INTENT(IN) :: natoms
472 : CHARACTER(LEN=*), INTENT(IN) :: gwfn_filename
473 : INTEGER, INTENT(IN) :: output_unit
474 :
475 : CHARACTER(LEN=2) :: element_symbol
476 : INTEGER :: iatom, ikind, zatom
477 1 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: written
478 : REAL(KIND=dp) :: zeff
479 : TYPE(sgp_potential_type), POINTER :: sgp_potential
480 :
481 1 : NULLIFY (sgp_potential)
482 3 : ALLOCATE (written(SIZE(kind_set)))
483 1 : written(:) = .FALSE.
484 :
485 3 : DO iatom = 1, natoms
486 : CALL get_atomic_kind(particle_set(iatom)%atomic_kind, element_symbol=element_symbol, &
487 2 : kind_number=ikind, z=zatom)
488 2 : IF (written(ikind)) CYCLE
489 :
490 1 : CALL get_qs_kind(kind_set(ikind), sgp_potential=sgp_potential, zeff=zeff)
491 4 : IF (ASSOCIATED(sgp_potential)) THEN
492 1 : IF (ABS(zeff) < 1.0E-8_dp) zeff = REAL(zatom, KIND=dp)
493 : CALL write_casino_sgp_pseudopotential(sgp_potential, element_symbol, zatom, zeff, &
494 1 : gwfn_filename, output_unit)
495 1 : written(ikind) = .TRUE.
496 : END IF
497 : END DO
498 :
499 1 : DEALLOCATE (written)
500 1 : END SUBROUTINE write_casino_sgp_pseudopotentials
501 :
502 : ! **************************************************************************************************
503 : !> \brief Write a CASINO tabulated pseudopotential for a CP2K semilocal ECP.
504 : !> \param sgp_potential the CP2K semilocal Gaussian potential
505 : !> \param element_symbol the chemical symbol
506 : !> \param zatom the nuclear charge
507 : !> \param zeff the ECP valence charge
508 : !> \param gwfn_filename the gwfn.data filename
509 : !> \param output_unit output unit for log messages
510 : ! **************************************************************************************************
511 1 : SUBROUTINE write_casino_sgp_pseudopotential(sgp_potential, element_symbol, zatom, zeff, &
512 : gwfn_filename, output_unit)
513 : TYPE(sgp_potential_type), INTENT(IN), POINTER :: sgp_potential
514 : CHARACTER(LEN=*), INTENT(IN) :: element_symbol
515 : INTEGER, INTENT(IN) :: zatom
516 : REAL(KIND=dp), INTENT(IN) :: zeff
517 : CHARACTER(LEN=*), INTENT(IN) :: gwfn_filename
518 : INTEGER, INTENT(IN) :: output_unit
519 :
520 : CHARACTER(LEN=default_path_length) :: pp_filename
521 : INTEGER :: igrid, iw, l, local_l, ngrid, nloc, &
522 : nsemiloc, sl_lmax
523 : INTEGER, DIMENSION(0:10) :: npot
524 : LOGICAL :: ecp_local, ecp_semi_local, has_nlcc
525 : REAL(KIND=dp) :: agrid, bgrid, r, rmax, rv_local
526 1 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: rgrid
527 1 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: rpot
528 :
529 : CALL get_potential(potential=sgp_potential, ecp_local=ecp_local, &
530 : ecp_semi_local=ecp_semi_local, nloc=nloc, sl_lmax=sl_lmax, &
531 1 : npot=npot, has_nlcc=has_nlcc)
532 1 : IF (.NOT. ecp_local .OR. nloc == 0) THEN
533 0 : WRITE (output_unit, "((T2,A,A,A))") "CASINO| Cannot write ", TRIM(element_symbol), &
534 0 : "_pp.data: only CP2K semilocal ECP potentials are supported."
535 : RETURN
536 : END IF
537 :
538 1 : local_l = MERGE(sl_lmax + 1, 0, ecp_semi_local)
539 1 : rmax = 100.0_dp
540 1 : agrid = 70.0_dp*EXP(-5.0_dp*LOG(10.0_dp))/REAL(zatom, KIND=dp)
541 1 : bgrid = 1.0_dp/70.0_dp
542 :
543 1 : ngrid = 0
544 831 : DO
545 832 : r = agrid*(EXP(bgrid*REAL(ngrid, KIND=dp)) - 1.0_dp)
546 832 : IF (r > rmax) EXIT
547 831 : ngrid = ngrid + 1
548 : END DO
549 :
550 6 : ALLOCATE (rgrid(ngrid), rpot(0:local_l, ngrid))
551 832 : DO igrid = 1, ngrid
552 831 : r = agrid*(EXP(bgrid*REAL(igrid - 1, KIND=dp)) - 1.0_dp)
553 831 : rgrid(igrid) = r
554 : rv_local = casino_sgp_r_times_v(nloc, sgp_potential%nrloc(1:nloc), &
555 : sgp_potential%bloc(1:nloc), &
556 831 : sgp_potential%aloc(1:nloc), r, zeff, .TRUE.)
557 2494 : DO l = 0, local_l
558 1662 : rpot(l, igrid) = rv_local
559 2493 : IF (l < local_l .AND. ecp_semi_local) THEN
560 831 : nsemiloc = npot(l)
561 831 : IF (nsemiloc > 0) THEN
562 : rpot(l, igrid) = rpot(l, igrid) + &
563 : casino_sgp_r_times_v(nsemiloc, sgp_potential%nrpot(1:nsemiloc, l), &
564 : sgp_potential%bpot(1:nsemiloc, l), &
565 831 : sgp_potential%apot(1:nsemiloc, l), r, zeff, .FALSE.)
566 : END IF
567 : END IF
568 : END DO
569 : END DO
570 2494 : rpot(:, :) = 2.0_dp*rpot(:, :)
571 :
572 1 : CALL casino_pp_filename(gwfn_filename, element_symbol, pp_filename)
573 : CALL open_file(file_name=pp_filename, file_status="REPLACE", file_action="WRITE", &
574 1 : file_form="FORMATTED", unit_number=iw)
575 1 : WRITE (iw, '(A)') "CP2K ECP pseudopotential in real space"
576 1 : WRITE (iw, '(A)') "Atomic number and pseudo-charge"
577 1 : WRITE (iw, '(I6,1X,F18.10)') zatom, zeff
578 1 : WRITE (iw, '(A)') "Energy units (rydberg/hartree/ev):"
579 1 : WRITE (iw, '(A)') "rydberg"
580 1 : WRITE (iw, '(A)') "Angular momentum of local component (0=s,1=p,2=d..)"
581 1 : WRITE (iw, '(I6)') local_l
582 1 : WRITE (iw, '(A)') "NLRULE override (1) VMC/DMC (2) config gen (0 ==> input/default value)"
583 1 : WRITE (iw, '(2I6)') 0, 0
584 1 : WRITE (iw, '(A)') "Number of grid points"
585 1 : WRITE (iw, '(I8)') ngrid
586 1 : WRITE (iw, '(A)') "R(i) in atomic units"
587 832 : DO igrid = 1, ngrid
588 832 : WRITE (iw, '(ES20.12)') rgrid(igrid)
589 : END DO
590 3 : DO l = 0, local_l
591 2 : WRITE (iw, '(A,I0,A)') "r*potential (L=", l, ") in Ry"
592 1665 : DO igrid = 1, ngrid
593 1664 : WRITE (iw, '(ES20.12)') rpot(l, igrid)
594 : END DO
595 : END DO
596 1 : CALL close_file(unit_number=iw)
597 :
598 1 : WRITE (output_unit, "((T2,A,A))") "CASINO| Wrote pseudopotential file ", TRIM(pp_filename)
599 1 : IF (has_nlcc) THEN
600 0 : WRITE (output_unit, "((T2,A,A,A))") "CASINO| NLCC terms for ", TRIM(element_symbol), &
601 0 : " are not represented in CASINO *_pp.data."
602 : END IF
603 :
604 1 : DEALLOCATE (rgrid, rpot)
605 1 : END SUBROUTINE write_casino_sgp_pseudopotential
606 :
607 : ! **************************************************************************************************
608 : !> \brief Return r times a CP2K semilocal Gaussian ECP channel in Hartree.
609 : !> \param nterm the number of Gaussian terms
610 : !> \param nr the CP2K r**(n-2) exponents
611 : !> \param gaussian_exponent the Gaussian exponents
612 : !> \param coefficient the Gaussian coefficients
613 : !> \param r the radial grid point
614 : !> \param zeff the ECP valence charge
615 : !> \param local_channel true for the local Coulomb-tailed channel
616 : !> \return r times the potential value
617 : ! **************************************************************************************************
618 1662 : FUNCTION casino_sgp_r_times_v(nterm, nr, gaussian_exponent, coefficient, r, zeff, local_channel) RESULT(r_times_v)
619 : INTEGER, INTENT(IN) :: nterm
620 : INTEGER, DIMENSION(:), INTENT(IN) :: nr
621 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: gaussian_exponent, coefficient
622 : REAL(KIND=dp), INTENT(IN) :: r, zeff
623 : LOGICAL, INTENT(IN) :: local_channel
624 : REAL(KIND=dp) :: r_times_v
625 :
626 : INTEGER :: iterm
627 :
628 1662 : IF (r == 0.0_dp) THEN
629 1662 : r_times_v = 0.0_dp
630 : RETURN
631 : END IF
632 :
633 1660 : r_times_v = 0.0_dp
634 1660 : IF (local_channel) r_times_v = -zeff
635 4980 : DO iterm = 1, nterm
636 3320 : CPASSERT(nr(iterm) >= 1)
637 : r_times_v = r_times_v + coefficient(iterm)*r**(nr(iterm) - 1)* &
638 4980 : EXP(-gaussian_exponent(iterm)*r*r)
639 : END DO
640 : END FUNCTION casino_sgp_r_times_v
641 :
642 : ! **************************************************************************************************
643 : !> \brief Build the CASINO pseudopotential filename next to gwfn.data.
644 : !> \param gwfn_filename the gwfn.data filename
645 : !> \param element_symbol the chemical symbol
646 : !> \param pp_filename the CASINO pseudopotential filename
647 : ! **************************************************************************************************
648 1 : SUBROUTINE casino_pp_filename(gwfn_filename, element_symbol, pp_filename)
649 : CHARACTER(LEN=*), INTENT(IN) :: gwfn_filename, element_symbol
650 : CHARACTER(LEN=*), INTENT(OUT) :: pp_filename
651 :
652 : CHARACTER(LEN=2) :: symbol
653 : INTEGER :: slash
654 :
655 1 : symbol = ADJUSTL(element_symbol)
656 1 : CALL lowercase(symbol)
657 1 : slash = INDEX(TRIM(gwfn_filename), "/", BACK=.TRUE.)
658 1 : IF (slash > 0) THEN
659 0 : pp_filename = gwfn_filename(1:slash)//TRIM(symbol)//"_pp.data"
660 : ELSE
661 1 : pp_filename = TRIM(symbol)//"_pp.data"
662 : END IF
663 1 : END SUBROUTINE casino_pp_filename
664 :
665 : ! **************************************************************************************************
666 : !> \brief Prepare the k-point object used for CASINO export.
667 : !> \param qs_env the QS environment
668 : !> \param casino_section the CASINO print section
669 : !> \param do_kpoints true when the SCF used k-points
670 : !> \param kpoints_scf the converged SCF k-point object
671 : !> \param kpoints_out the k-point object to write
672 : !> \param created true if kpoints_out must be released by the caller
673 : ! **************************************************************************************************
674 14 : SUBROUTINE prepare_casino_kpoint_grid(qs_env, casino_section, do_kpoints, kpoints_scf, &
675 : kpoints_out, created)
676 : TYPE(qs_environment_type), INTENT(IN), POINTER :: qs_env
677 : TYPE(section_vals_type), INTENT(IN), POINTER :: casino_section
678 : LOGICAL, INTENT(IN) :: do_kpoints
679 : TYPE(kpoint_type), POINTER :: kpoints_scf, kpoints_out
680 : LOGICAL, INTENT(OUT) :: created
681 :
682 : CHARACTER(LEN=*), PARAMETER :: routineN = 'prepare_casino_kpoint_grid'
683 :
684 : CHARACTER(LEN=default_string_length) :: kp_scheme, reuse_reason
685 : INTEGER :: aligned_blocks, aligned_max_size, &
686 : handle, nfull, output_unit
687 : INTEGER, DIMENSION(3) :: nkp_grid
688 10 : INTEGER, DIMENSION(:, :, :), POINTER :: cell_to_index
689 : LOGICAL :: diis_step, full_grid, full_kpoint_grid, &
690 : gamma_centered, reuse_scf_mos, &
691 : reused_scf_mos, symmetry
692 : REAL(KIND=dp) :: aligned_min_svalue, eps_geo, wsum
693 : REAL(KIND=dp), DIMENSION(3) :: kp_shift
694 10 : REAL(KIND=dp), DIMENSION(:), POINTER :: wkp_source
695 10 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: xkp_source
696 : TYPE(cell_type), POINTER :: cell
697 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
698 : TYPE(cp_logger_type), POINTER :: logger
699 10 : TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: matrix_ks, matrix_s
700 : TYPE(dft_control_type), POINTER :: dft_control
701 10 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
702 : TYPE(mp_para_env_type), POINTER :: para_env
703 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
704 10 : POINTER :: sab_nl
705 10 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
706 : TYPE(qs_scf_env_type), POINTER :: scf_env
707 : TYPE(scf_control_type), POINTER :: scf_control
708 :
709 10 : CALL timeset(routineN, handle)
710 :
711 10 : created = .FALSE.
712 10 : kpoints_out => kpoints_scf
713 10 : NULLIFY (blacs_env, cell, cell_to_index, dft_control, logger, matrix_ks, matrix_s, mos, &
714 10 : para_env, particle_set, sab_nl, scf_control, scf_env, wkp_source, xkp_source)
715 :
716 10 : IF (.NOT. do_kpoints) THEN
717 8 : CALL timestop(handle)
718 8 : RETURN
719 : END IF
720 2 : CPASSERT(ASSOCIATED(kpoints_scf))
721 :
722 : CALL get_kpoint_info(kpoints_scf, kp_scheme=kp_scheme, symmetry=symmetry, &
723 : full_grid=full_grid, nkp_grid=nkp_grid, kp_shift=kp_shift, &
724 2 : gamma_centered=gamma_centered, eps_geo=eps_geo)
725 2 : IF (.NOT. symmetry .OR. full_grid) THEN
726 0 : CALL timestop(handle)
727 0 : RETURN
728 : END IF
729 :
730 2 : CALL section_vals_val_get(casino_section, "FULL_KPOINT_GRID", l_val=full_kpoint_grid)
731 2 : IF (.NOT. full_kpoint_grid) THEN
732 0 : CPABORT("CASINO export requires a full k-point grid. Use PRINT%CASINO%FULL_KPOINT_GRID.")
733 : END IF
734 :
735 2 : SELECT CASE (TRIM(kp_scheme))
736 : CASE ("MONKHORST-PACK", "MACDONALD", "GENERAL")
737 : ! supported below
738 : CASE DEFAULT
739 2 : CPABORT("CASINO%FULL_KPOINT_GRID supports only MONKHORST-PACK, MACDONALD, and GENERAL k-points.")
740 : END SELECT
741 :
742 2 : logger => cp_get_default_logger()
743 2 : output_unit = cp_logger_get_default_io_unit(logger)
744 2 : CALL section_vals_val_get(casino_section, "REUSE_SCF_MOS", l_val=reuse_scf_mos)
745 : CALL get_qs_env(qs_env, para_env=para_env, blacs_env=blacs_env, cell=cell, &
746 : particle_set=particle_set, mos=mos, dft_control=dft_control, &
747 : sab_orb=sab_nl, matrix_ks_kp=matrix_ks, matrix_s_kp=matrix_s, &
748 2 : scf_env=scf_env, scf_control=scf_control)
749 2 : CPASSERT(ASSOCIATED(para_env))
750 2 : CPASSERT(ASSOCIATED(blacs_env))
751 2 : CPASSERT(ASSOCIATED(cell))
752 2 : CPASSERT(ASSOCIATED(particle_set))
753 2 : CPASSERT(ASSOCIATED(mos))
754 2 : CPASSERT(ASSOCIATED(dft_control))
755 2 : CPASSERT(ASSOCIATED(sab_nl))
756 2 : CPASSERT(ASSOCIATED(matrix_ks))
757 2 : CPASSERT(ASSOCIATED(matrix_s))
758 2 : CPASSERT(ASSOCIATED(scf_env))
759 2 : CPASSERT(ASSOCIATED(scf_control))
760 :
761 2 : NULLIFY (kpoints_out)
762 2 : CALL kpoint_create(kpoints_out)
763 2 : kpoints_out%kp_scheme = kp_scheme
764 2 : kpoints_out%symmetry = .FALSE.
765 2 : kpoints_out%full_grid = .TRUE.
766 2 : kpoints_out%verbose = .FALSE.
767 2 : kpoints_out%use_real_wfn = .FALSE.
768 2 : kpoints_out%eps_geo = eps_geo
769 2 : kpoints_out%parallel_group_size = para_env%num_pe
770 :
771 4 : SELECT CASE (TRIM(kp_scheme))
772 : CASE ("MONKHORST-PACK", "MACDONALD")
773 8 : kpoints_out%nkp_grid(1:3) = nkp_grid(1:3)
774 8 : kpoints_out%kp_shift(1:3) = kp_shift(1:3)
775 2 : kpoints_out%gamma_centered = gamma_centered
776 2 : CALL kpoint_initialize(kpoints_out, particle_set, cell)
777 : CASE ("GENERAL")
778 0 : IF (.NOT. ASSOCIATED(kpoints_scf%xkp_input) .OR. &
779 : .NOT. ASSOCIATED(kpoints_scf%wkp_input)) THEN
780 0 : CPABORT("CASINO%FULL_KPOINT_GRID cannot recover the unreduced GENERAL k-point set.")
781 : END IF
782 0 : xkp_source => kpoints_scf%xkp_input
783 0 : wkp_source => kpoints_scf%wkp_input
784 0 : nfull = SIZE(wkp_source)
785 0 : wsum = SUM(wkp_source)
786 0 : IF (wsum <= 0.0_dp) CPABORT("CASINO%FULL_KPOINT_GRID found invalid GENERAL k-point weights.")
787 0 : kpoints_out%nkp = nfull
788 0 : ALLOCATE (kpoints_out%xkp(3, nfull), kpoints_out%wkp(nfull))
789 0 : kpoints_out%xkp(1:3, 1:nfull) = xkp_source(1:3, 1:nfull)
790 2 : kpoints_out%wkp(1:nfull) = wkp_source(1:nfull)/wsum
791 : END SELECT
792 :
793 2 : CALL kpoint_env_initialize(kpoints_out, para_env, blacs_env)
794 2 : CALL kpoint_initialize_mos(kpoints_out, mos)
795 2 : CALL kpoint_initialize_mo_set(kpoints_out)
796 2 : CALL kpoint_init_cell_index(kpoints_out, sab_nl, para_env, dft_control%nimages)
797 :
798 2 : reused_scf_mos = .FALSE.
799 2 : reuse_reason = ""
800 2 : aligned_blocks = 0
801 2 : aligned_max_size = 0
802 2 : aligned_min_svalue = 0.0_dp
803 2 : diis_step = .FALSE.
804 2 : IF (reuse_scf_mos) THEN
805 : CALL do_general_diag_kp(matrix_ks, matrix_s, kpoints_scf, scf_env, scf_control, .FALSE., &
806 2 : diis_step)
807 2 : CALL get_kpoint_info(kpoints_out, cell_to_index=cell_to_index)
808 : CALL prepare_wannier90_scf_mos(kpoints_out, kpoints_scf, matrix_s, matrix_ks, &
809 : cell_to_index, sab_nl, para_env, reused_scf_mos, &
810 : reuse_reason, aligned_blocks, aligned_max_size, &
811 2 : aligned_min_svalue)
812 : END IF
813 2 : IF (reused_scf_mos) THEN
814 2 : IF (output_unit > 0) THEN
815 : WRITE (output_unit, '(T2,A)') &
816 1 : "CASINO| Reused SCF MO coefficients for the full k-point grid."
817 1 : IF (aligned_blocks > 0) THEN
818 : WRITE (output_unit, '(T2,A,I0,A,I0,A,ES10.3)') &
819 0 : "CASINO| Ritz-stabilized ", aligned_blocks, &
820 0 : " degenerate SCF MO subspace(s); largest block has ", aligned_max_size, &
821 0 : " band(s), min metric eigenvalue ", aligned_min_svalue
822 : END IF
823 : END IF
824 : ELSE
825 0 : IF (output_unit > 0) THEN
826 0 : IF (reuse_scf_mos) THEN
827 : WRITE (output_unit, '(T2,A,A)') &
828 0 : "CASINO| Could not reuse SCF MOs: ", TRIM(reuse_reason)
829 : END IF
830 : WRITE (output_unit, '(T2,A)') &
831 0 : "CASINO| Diagonalizing the full k-point grid for export."
832 : END IF
833 0 : diis_step = .FALSE.
834 : CALL do_general_diag_kp(matrix_ks, matrix_s, kpoints_out, scf_env, scf_control, .FALSE., &
835 0 : diis_step)
836 : END IF
837 2 : created = .TRUE.
838 :
839 2 : CALL timestop(handle)
840 10 : END SUBROUTINE prepare_casino_kpoint_grid
841 :
842 : ! **************************************************************************************************
843 : !> \brief Build the CASINO k-point order with all real k-points first.
844 : !> \param cell ...
845 : !> \param periodic ...
846 : !> \param do_kpoints ...
847 : !> \param nkp_total ...
848 : !> \param xkp ...
849 : !> \param eps_kpoint_real ...
850 : !> \param kp_order ...
851 : !> \param kp_real ...
852 : !> \param nkp_out ...
853 : !> \param nreal_k ...
854 : !> \param kvec ...
855 : ! **************************************************************************************************
856 10 : SUBROUTINE build_kpoint_order(cell, periodic, do_kpoints, nkp_total, xkp, eps_kpoint_real, &
857 10 : kp_order, kp_real, nkp_out, nreal_k, kvec)
858 : TYPE(cell_type), INTENT(IN), POINTER :: cell
859 : LOGICAL, INTENT(IN) :: periodic, do_kpoints
860 : INTEGER, INTENT(IN) :: nkp_total
861 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
862 : OPTIONAL, POINTER :: xkp
863 : REAL(KIND=dp), INTENT(IN) :: eps_kpoint_real
864 : INTEGER, DIMENSION(:), INTENT(OUT) :: kp_order
865 : LOGICAL, DIMENSION(:), INTENT(OUT) :: kp_real
866 : INTEGER, INTENT(OUT) :: nkp_out, nreal_k
867 : REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT) :: kvec
868 :
869 : INTEGER :: ikp, jkp, ncomplex_k
870 20 : INTEGER, DIMENSION(nkp_total) :: complex_order, real_order
871 8 : LOGICAL, DIMENSION(nkp_total) :: used
872 :
873 10 : IF (.NOT. periodic) THEN
874 8 : kp_order(1) = 1
875 8 : kp_real(1) = .TRUE.
876 8 : nkp_out = 1
877 8 : nreal_k = 1
878 32 : kvec(:, 1) = 0.0_dp
879 : RETURN
880 : END IF
881 :
882 2 : IF (.NOT. do_kpoints) THEN
883 0 : kp_order(1) = 1
884 0 : kp_real(1) = .TRUE.
885 0 : nkp_out = 1
886 0 : nreal_k = 1
887 0 : kvec(:, 1) = 0.0_dp
888 : RETURN
889 : END IF
890 :
891 6 : used(:) = .FALSE.
892 2 : nreal_k = 0
893 2 : ncomplex_k = 0
894 :
895 6 : DO ikp = 1, nkp_total
896 6 : IF (is_real_kpoint(cell, xkp(:, ikp), eps_kpoint_real)) THEN
897 0 : used(ikp) = .TRUE.
898 0 : nreal_k = nreal_k + 1
899 0 : real_order(nreal_k) = ikp
900 : END IF
901 : END DO
902 :
903 6 : DO ikp = 1, nkp_total
904 6 : IF (.NOT. used(ikp)) THEN
905 2 : used(ikp) = .TRUE.
906 2 : ncomplex_k = ncomplex_k + 1
907 2 : complex_order(ncomplex_k) = ikp
908 2 : DO jkp = ikp + 1, nkp_total
909 2 : IF (.NOT. used(jkp)) THEN
910 2 : IF (is_conjugate_kpoint(cell, xkp(:, ikp), xkp(:, jkp), eps_kpoint_real)) THEN
911 2 : used(jkp) = .TRUE.
912 2 : EXIT
913 : END IF
914 : END IF
915 : END DO
916 : END IF
917 : END DO
918 :
919 2 : nkp_out = nreal_k + ncomplex_k
920 2 : DO ikp = 1, nreal_k
921 0 : kp_order(ikp) = real_order(ikp)
922 0 : kp_real(ikp) = .TRUE.
923 2 : kvec(:, ikp) = 2.0_dp*pi*MATMUL(TRANSPOSE(cell%h_inv), xkp(:, real_order(ikp)))
924 : END DO
925 4 : DO ikp = 1, ncomplex_k
926 2 : jkp = nreal_k + ikp
927 2 : kp_order(jkp) = complex_order(ikp)
928 2 : kp_real(jkp) = .FALSE.
929 10 : kvec(:, jkp) = 2.0_dp*pi*MATMUL(TRANSPOSE(cell%h_inv), xkp(:, complex_order(ikp)))
930 : END DO
931 2 : END SUBROUTINE build_kpoint_order
932 :
933 : ! **************************************************************************************************
934 : !> \brief Returns true for conjugate k-points modulo reciprocal lattice vectors.
935 : !> \param cell ...
936 : !> \param xk1 ...
937 : !> \param xk2 ...
938 : !> \param eps_kpoint_real ...
939 : !> \return ...
940 : ! **************************************************************************************************
941 2 : FUNCTION is_conjugate_kpoint(cell, xk1, xk2, eps_kpoint_real) RESULT(is_conjugate)
942 : TYPE(cell_type), INTENT(IN), POINTER :: cell
943 : REAL(KIND=dp), DIMENSION(3), INTENT(IN) :: xk1, xk2
944 : REAL(KIND=dp), INTENT(IN) :: eps_kpoint_real
945 : LOGICAL :: is_conjugate
946 :
947 : INTEGER :: idir
948 : REAL(KIND=dp) :: reduced
949 :
950 2 : is_conjugate = .TRUE.
951 8 : DO idir = 1, 3
952 8 : IF (cell%perd(idir) /= 0) THEN
953 6 : reduced = xk1(idir) + xk2(idir)
954 6 : reduced = reduced - REAL(NINT(reduced), KIND=dp)
955 6 : IF (ABS(reduced) > eps_kpoint_real) THEN
956 : is_conjugate = .FALSE.
957 : EXIT
958 : END IF
959 : END IF
960 : END DO
961 2 : END FUNCTION is_conjugate_kpoint
962 :
963 : ! **************************************************************************************************
964 : !> \brief Returns true for Gamma/BZ-edge k-points where real Bloch orbitals can be used.
965 : !> \param cell ...
966 : !> \param xk ...
967 : !> \param eps_kpoint_real ...
968 : !> \return ...
969 : ! **************************************************************************************************
970 4 : FUNCTION is_real_kpoint(cell, xk, eps_kpoint_real) RESULT(is_real)
971 : TYPE(cell_type), INTENT(IN), POINTER :: cell
972 : REAL(KIND=dp), DIMENSION(3), INTENT(IN) :: xk
973 : REAL(KIND=dp), INTENT(IN) :: eps_kpoint_real
974 : LOGICAL :: is_real
975 :
976 : INTEGER :: idir
977 : REAL(KIND=dp) :: reduced
978 :
979 4 : is_real = .TRUE.
980 16 : DO idir = 1, 3
981 16 : IF (cell%perd(idir) /= 0) THEN
982 12 : reduced = xk(idir) - REAL(NINT(xk(idir)), KIND=dp)
983 4 : IF (ABS(reduced) > eps_kpoint_real .AND. &
984 16 : ABS(ABS(reduced) - 0.5_dp) > eps_kpoint_real) is_real = .FALSE.
985 : END IF
986 : END DO
987 4 : END FUNCTION is_real_kpoint
988 :
989 : ! **************************************************************************************************
990 : !> \brief Write all non-orbital CASINO gwfn.data sections.
991 : !> \param iw ...
992 : !> \param periodicity ...
993 : !> \param nspins ...
994 : !> \param e_nn ...
995 : !> \param nel_tot ...
996 : !> \param natoms ...
997 : !> \param coord ...
998 : !> \param atomic_number ...
999 : !> \param valence_charge ...
1000 : !> \param cell ...
1001 : !> \param periodic ...
1002 : !> \param nkp ...
1003 : !> \param nreal_k ...
1004 : !> \param kvec ...
1005 : !> \param shell_num ...
1006 : !> \param ao_num ...
1007 : !> \param prim_num ...
1008 : !> \param shell_ang_mom ...
1009 : !> \param shell_type ...
1010 : !> \param prim_per_shell ...
1011 : !> \param first_shell ...
1012 : !> \param exponents ...
1013 : !> \param coefficients ...
1014 : !> \param shell_position ...
1015 : ! **************************************************************************************************
1016 15 : SUBROUTINE write_casino_header(iw, periodicity, nspins, e_nn, nel_tot, natoms, coord, &
1017 5 : atomic_number, valence_charge, cell, periodic, nkp, nreal_k, kvec, &
1018 10 : shell_num, ao_num, prim_num, shell_ang_mom, shell_type, prim_per_shell, &
1019 5 : first_shell, exponents, coefficients, shell_position)
1020 : INTEGER, INTENT(IN) :: iw, periodicity, nspins
1021 : REAL(KIND=dp), INTENT(IN) :: e_nn
1022 : INTEGER, INTENT(IN) :: nel_tot, natoms
1023 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: coord
1024 : INTEGER, DIMENSION(:), INTENT(IN) :: atomic_number
1025 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: valence_charge
1026 : TYPE(cell_type), INTENT(IN), POINTER :: cell
1027 : LOGICAL, INTENT(IN) :: periodic
1028 : INTEGER, INTENT(IN) :: nkp, nreal_k
1029 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: kvec
1030 : INTEGER, INTENT(IN) :: shell_num, ao_num, prim_num
1031 : INTEGER, DIMENSION(:), INTENT(IN) :: shell_ang_mom, shell_type, &
1032 : prim_per_shell, first_shell
1033 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: exponents, coefficients
1034 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: shell_position
1035 :
1036 : INTEGER :: highest_ang_mom, i
1037 :
1038 25 : highest_ang_mom = MAXVAL(shell_ang_mom) + 1
1039 :
1040 5 : WRITE (iw, '(A)') "CP2K CASINO gwfn.data"
1041 5 : WRITE (iw, *)
1042 5 : WRITE (iw, '(A)') "BASIC INFO"
1043 5 : WRITE (iw, '(A)') "----------"
1044 5 : WRITE (iw, '(A)') "Generated by:"
1045 5 : WRITE (iw, '(1X,A)') TRIM(cp2k_version)
1046 5 : WRITE (iw, '(A)') "Method:"
1047 5 : WRITE (iw, '(A)') " DFT"
1048 5 : WRITE (iw, '(A)') "DFT functional:"
1049 5 : WRITE (iw, '(A)') " CP2K"
1050 5 : WRITE (iw, '(A)') "Periodicity:"
1051 5 : WRITE (iw, '(1X,I0)') periodicity
1052 5 : WRITE (iw, '(A)') "Spin unrestricted:"
1053 9 : WRITE (iw, '(1X,A)') MERGE(".true. ", ".false.", nspins > 1)
1054 5 : WRITE (iw, '(A)') "Nuclear repulsion energy (au/atom):"
1055 5 : WRITE (iw, '(1PE20.13)') e_nn
1056 5 : WRITE (iw, '(A)') "Number of electrons per primitive cell"
1057 5 : WRITE (iw, '(1X,I0)') nel_tot
1058 5 : WRITE (iw, *)
1059 :
1060 5 : WRITE (iw, '(A)') "GEOMETRY"
1061 5 : WRITE (iw, '(A)') "--------"
1062 5 : WRITE (iw, '(A)') "Number of atoms"
1063 5 : WRITE (iw, '(1X,I0)') natoms
1064 5 : WRITE (iw, '(A)') "Atomic positions (au)"
1065 14 : DO i = 1, natoms
1066 14 : WRITE (iw, '(3(1PE20.13))') coord(:, i)
1067 : END DO
1068 5 : WRITE (iw, '(A)') "Atomic numbers for each atom"
1069 5 : CALL write_integer_vector(iw, atomic_number)
1070 5 : WRITE (iw, '(A)') "Valence charges for each atom"
1071 5 : CALL write_real_vector(iw, valence_charge)
1072 5 : IF (.NOT. periodic) WRITE (iw, *)
1073 5 : IF (periodic) THEN
1074 1 : WRITE (iw, '(A)') "Primitive lattice vectors (au)"
1075 4 : DO i = 1, 3
1076 13 : WRITE (iw, '(3(1PE20.13))') cell%hmat(:, i)
1077 : END DO
1078 1 : WRITE (iw, *)
1079 :
1080 1 : WRITE (iw, '(A)') "K SPACE NET"
1081 1 : WRITE (iw, '(A)') "-----------"
1082 1 : WRITE (iw, '(A)') "Number of k points"
1083 1 : WRITE (iw, '(1X,I0)') nkp
1084 1 : WRITE (iw, '(A)') "Number of 'real' k points on BZ edge"
1085 1 : WRITE (iw, '(1X,I0)') nreal_k
1086 1 : WRITE (iw, '(A)') "k point coordinates (au)"
1087 2 : DO i = 1, nkp
1088 2 : WRITE (iw, '(3(1PE20.13))') kvec(:, i)
1089 : END DO
1090 1 : WRITE (iw, *)
1091 : END IF
1092 :
1093 5 : WRITE (iw, '(A)') "BASIS SET"
1094 5 : WRITE (iw, '(A)') "---------"
1095 5 : WRITE (iw, '(A)') "Number of Gaussian centres"
1096 5 : WRITE (iw, '(1X,I0)') natoms
1097 5 : WRITE (iw, '(A)') "Number of shells per primitive cell"
1098 5 : WRITE (iw, '(1X,I0)') shell_num
1099 5 : WRITE (iw, '(A)') "Number of basis functions ('AO') per primitive cell"
1100 5 : WRITE (iw, '(1X,I0)') ao_num
1101 5 : WRITE (iw, '(A)') "Number of Gaussian primitives per primitive cell"
1102 5 : WRITE (iw, '(1X,I0)') prim_num
1103 5 : WRITE (iw, '(A)') "Highest shell angular momentum (s/p/d/f/g... 1/2/3/4/5...)"
1104 5 : WRITE (iw, '(1X,I0)') highest_ang_mom
1105 5 : WRITE (iw, '(A)') "Code for shell types (s/sp/p/d/f... 1/2/3/4/5...)"
1106 5 : CALL write_integer_vector(iw, shell_type)
1107 5 : WRITE (iw, '(A)') "Number of primitive Gaussians in each shell"
1108 5 : CALL write_integer_vector(iw, prim_per_shell)
1109 5 : WRITE (iw, '(A)') "Sequence number of first shell on each centre"
1110 5 : CALL write_integer_vector(iw, first_shell)
1111 5 : WRITE (iw, '(A)') "Exponents of Gaussian primitives"
1112 5 : CALL write_real_vector(iw, exponents)
1113 5 : WRITE (iw, '(A)') "Correctly normalised contraction coefficients"
1114 5 : CALL write_real_vector(iw, coefficients)
1115 5 : WRITE (iw, '(A)') "Position of each shell (au)"
1116 25 : DO i = 1, shell_num
1117 25 : WRITE (iw, '(3(1PE20.13))') shell_position(:, i)
1118 : END DO
1119 5 : WRITE (iw, *)
1120 :
1121 5 : WRITE (iw, '(A)') "MULTIDETERMINANT INFORMATION"
1122 5 : WRITE (iw, '(A)') "----------------------------"
1123 5 : WRITE (iw, '(A)') "GS"
1124 5 : WRITE (iw, *)
1125 5 : WRITE (iw, '(A)') "ORBITAL COEFFICIENTS"
1126 5 : WRITE (iw, '(A)') "---------------------------"
1127 5 : END SUBROUTINE write_casino_header
1128 :
1129 : ! **************************************************************************************************
1130 : !> \brief Write one CASINO MO block for a spin/k-point.
1131 : !> \param iw ...
1132 : !> \param mos_sgf ...
1133 : !> \param mos_sgf_im ...
1134 : !> \param cp2k_to_casino_ao ...
1135 : !> \param mo_scale ...
1136 : !> \param ao_num ...
1137 : !> \param complex_orbitals ...
1138 : ! **************************************************************************************************
1139 6 : SUBROUTINE write_casino_orbitals(iw, mos_sgf, mos_sgf_im, cp2k_to_casino_ao, mo_scale, ao_num, &
1140 : complex_orbitals)
1141 : INTEGER, INTENT(IN) :: iw
1142 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: mos_sgf, mos_sgf_im
1143 : INTEGER, DIMENSION(:), INTENT(IN) :: cp2k_to_casino_ao
1144 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: mo_scale
1145 : INTEGER, INTENT(IN) :: ao_num
1146 : LOGICAL, INTENT(IN) :: complex_orbitals
1147 :
1148 : INTEGER :: iao, imo, nbuffer
1149 : REAL(KIND=dp), DIMENSION(4) :: buffer
1150 :
1151 6 : nbuffer = 0
1152 6 : buffer(:) = 0.0_dp
1153 32 : DO imo = 1, ao_num
1154 188 : DO iao = 1, ao_num
1155 156 : CALL push_real(iw, buffer, nbuffer, mo_scale(iao)*mos_sgf(cp2k_to_casino_ao(iao), imo))
1156 182 : IF (complex_orbitals) THEN
1157 16 : CALL push_real(iw, buffer, nbuffer, mo_scale(iao)*mos_sgf_im(cp2k_to_casino_ao(iao), imo))
1158 : END IF
1159 : END DO
1160 : END DO
1161 6 : IF (nbuffer > 0) WRITE (iw, '(4(1PE20.13))') buffer(1:nbuffer)
1162 6 : END SUBROUTINE write_casino_orbitals
1163 :
1164 : ! **************************************************************************************************
1165 : !> \brief Append one real number to a four-column output buffer.
1166 : !> \param iw ...
1167 : !> \param buffer ...
1168 : !> \param nbuffer ...
1169 : !> \param value ...
1170 : ! **************************************************************************************************
1171 172 : SUBROUTINE push_real(iw, buffer, nbuffer, value)
1172 : INTEGER, INTENT(IN) :: iw
1173 : REAL(KIND=dp), DIMENSION(4), INTENT(INOUT) :: buffer
1174 : INTEGER, INTENT(INOUT) :: nbuffer
1175 : REAL(KIND=dp), INTENT(IN) :: value
1176 :
1177 172 : nbuffer = nbuffer + 1
1178 172 : buffer(nbuffer) = value
1179 172 : IF (nbuffer == SIZE(buffer)) THEN
1180 43 : WRITE (iw, '(4(1PE20.13))') buffer
1181 43 : nbuffer = 0
1182 : END IF
1183 172 : END SUBROUTINE push_real
1184 :
1185 : ! **************************************************************************************************
1186 : !> \brief Write an integer vector in CASINO-friendly fixed-width columns.
1187 : !> \param iw ...
1188 : !> \param values ...
1189 : ! **************************************************************************************************
1190 20 : SUBROUTINE write_integer_vector(iw, values)
1191 : INTEGER, INTENT(IN) :: iw
1192 : INTEGER, DIMENSION(:), INTENT(IN) :: values
1193 :
1194 : INTEGER :: i, ilast
1195 :
1196 40 : DO i = 1, SIZE(values), 8
1197 20 : ilast = MIN(i + 7, SIZE(values))
1198 40 : WRITE (iw, '(8I10)') values(i:ilast)
1199 : END DO
1200 20 : END SUBROUTINE write_integer_vector
1201 :
1202 : ! **************************************************************************************************
1203 : !> \brief Write a real vector in CASINO-friendly fixed-width columns.
1204 : !> \param iw ...
1205 : !> \param values ...
1206 : ! **************************************************************************************************
1207 16 : SUBROUTINE write_real_vector(iw, values)
1208 : INTEGER, INTENT(IN) :: iw
1209 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: values
1210 :
1211 : INTEGER :: i, ilast
1212 :
1213 62 : DO i = 1, SIZE(values), 4
1214 46 : ilast = MIN(i + 3, SIZE(values))
1215 62 : WRITE (iw, '(4(1PE20.13))') values(i:ilast)
1216 : END DO
1217 16 : END SUBROUTINE write_real_vector
1218 :
1219 : ! **************************************************************************************************
1220 : !> \brief Rotate a complex value by exp(-i*k.g) using the TREXIO gauge convention.
1221 : !> \param re ...
1222 : !> \param im ...
1223 : !> \param cval ...
1224 : !> \param sval ...
1225 : ! **************************************************************************************************
1226 32 : SUBROUTINE rotate_complex_pair(re, im, cval, sval)
1227 : REAL(KIND=dp), INTENT(INOUT) :: re, im
1228 : REAL(KIND=dp), INTENT(IN) :: cval, sval
1229 :
1230 : REAL(KIND=dp) :: im_old, re_old
1231 :
1232 32 : re_old = re
1233 32 : im_old = im
1234 32 : re = cval*re_old + sval*im_old
1235 32 : im = -sval*re_old + cval*im_old
1236 32 : END SUBROUTINE rotate_complex_pair
1237 :
1238 : ! **************************************************************************************************
1239 : !> \brief Convert CP2K normalized primitive data to CASINO contraction coefficients.
1240 : !> \param l ...
1241 : !> \param nprim ...
1242 : !> \param zetas ...
1243 : !> \param gcc ...
1244 : !> \param exponents ...
1245 : !> \param coefficients ...
1246 : ! **************************************************************************************************
1247 40 : SUBROUTINE casino_shell_coefficients(l, nprim, zetas, gcc, exponents, coefficients)
1248 : INTEGER, INTENT(IN) :: l, nprim
1249 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: zetas, gcc
1250 : REAL(KIND=dp), DIMENSION(:), INTENT(OUT) :: exponents, coefficients
1251 :
1252 : INTEGER :: i
1253 : REAL(KIND=dp) :: contraction_norm, expzet, prefac, &
1254 : prim_cart_fac
1255 80 : REAL(KIND=dp), DIMENSION(nprim) :: raw_coeff
1256 :
1257 40 : expzet = 0.25_dp*REAL(2*l + 3, KIND=dp)
1258 40 : prefac = 2.0_dp**l*(2.0_dp/pi)**0.75_dp
1259 186 : DO i = 1, nprim
1260 146 : prim_cart_fac = prefac*zetas(i)**expzet
1261 186 : raw_coeff(i) = gcc(i)/prim_cart_fac
1262 : END DO
1263 40 : contraction_norm = casino_contraction_norm(l, nprim, zetas, raw_coeff)
1264 186 : DO i = 1, nprim
1265 146 : exponents(i) = zetas(i)
1266 186 : coefficients(i) = raw_coeff(i)*contraction_norm*casino_primitive_norm(l, zetas(i))
1267 : END DO
1268 40 : END SUBROUTINE casino_shell_coefficients
1269 :
1270 : ! **************************************************************************************************
1271 : !> \brief Whole-contraction normalization used by CASINO's molden2qmc converter.
1272 : !> \param l ...
1273 : !> \param nprim ...
1274 : !> \param zetas ...
1275 : !> \param raw_coeff ...
1276 : !> \return ...
1277 : ! **************************************************************************************************
1278 40 : FUNCTION casino_contraction_norm(l, nprim, zetas, raw_coeff) RESULT(norm)
1279 : INTEGER, INTENT(IN) :: l, nprim
1280 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: zetas, raw_coeff
1281 : REAL(KIND=dp) :: norm
1282 :
1283 : INTEGER :: i, j
1284 : REAL(KIND=dp) :: overlap
1285 :
1286 40 : overlap = 0.0_dp
1287 186 : DO i = 1, nprim
1288 952 : DO j = 1, nprim
1289 : overlap = overlap + raw_coeff(i)*raw_coeff(j)* &
1290 912 : (2.0_dp*SQRT(zetas(i)*zetas(j))/(zetas(i) + zetas(j)))**(l + 1.5_dp)
1291 : END DO
1292 : END DO
1293 40 : norm = 1.0_dp/SQRT(overlap)
1294 40 : END FUNCTION casino_contraction_norm
1295 :
1296 : ! **************************************************************************************************
1297 : !> \brief Primitive m-independent normalization used by CASINO's Gaussian evaluator.
1298 : !> \param l ...
1299 : !> \param alpha ...
1300 : !> \return ...
1301 : ! **************************************************************************************************
1302 146 : FUNCTION casino_primitive_norm(l, alpha) RESULT(norm)
1303 : INTEGER, INTENT(IN) :: l
1304 : REAL(KIND=dp), INTENT(IN) :: alpha
1305 : REAL(KIND=dp) :: norm
1306 :
1307 146 : norm = SQRT(2.0_dp**(l + 1.5_dp)*alpha**(l + 1.5_dp))/pi**0.75_dp
1308 146 : IF (l > 0) norm = norm*SQRT(2.0_dp**l/odd_double_factorial(2*l - 1))
1309 146 : END FUNCTION casino_primitive_norm
1310 :
1311 : ! **************************************************************************************************
1312 : !> \brief CASINO shell type code.
1313 : !> \param l ...
1314 : !> \return ...
1315 : ! **************************************************************************************************
1316 40 : FUNCTION casino_shell_type(l) RESULT(shell_type)
1317 : INTEGER, INTENT(IN) :: l
1318 : INTEGER :: shell_type
1319 :
1320 40 : IF (l == 0) THEN
1321 : shell_type = 1
1322 : ELSE
1323 4 : shell_type = l + 2
1324 : END IF
1325 40 : END FUNCTION casino_shell_type
1326 :
1327 : ! **************************************************************************************************
1328 : !> \brief CP2K AO index for a CASINO/MOLDEN ordered harmonic shell.
1329 : !> \param l ...
1330 : !> \param k ...
1331 : !> \return ...
1332 : ! **************************************************************************************************
1333 48 : FUNCTION casino_cp2k_index(l, k) RESULT(idx)
1334 : INTEGER, INTENT(IN) :: l, k
1335 : INTEGER :: idx
1336 :
1337 : INTEGER, DIMENSION(9, 0:max_casino_l), PARAMETER :: map = RESHAPE([1, 0, 0, 0, 0, 0, 0, 0, 0 &
1338 : , 3, 1, 2, 0, 0, 0, 0, 0, 0, 3, 4, 2, 5, 1, 0, 0, 0, 0, 4, 5, 3, 6, 2, 7, 1, 0, 0, 5, 6, 4&
1339 : , 7, 3, 8, 2, 9, 1], [9, max_casino_l + 1])
1340 :
1341 48 : idx = map(k, l)
1342 48 : END FUNCTION casino_cp2k_index
1343 :
1344 : ! **************************************************************************************************
1345 : !> \brief Scale factors converting MOLDEN harmonic MO coefficients to CASINO conventions.
1346 : !> \param l ...
1347 : !> \param k ...
1348 : !> \return ...
1349 : ! **************************************************************************************************
1350 48 : FUNCTION casino_mo_scale(l, k) RESULT(scale)
1351 : INTEGER, INTENT(IN) :: l, k
1352 : REAL(KIND=dp) :: scale
1353 :
1354 : REAL(KIND=dp), DIMENSION(5), PARAMETER :: d_factor = [0.5_dp, 3.0_dp, 3.0_dp, 3.0_dp, 6.0_dp]
1355 :
1356 : INTEGER :: m
1357 :
1358 48 : IF (l <= 1) THEN
1359 : scale = 1.0_dp
1360 : ELSE
1361 0 : m = casino_m_quantum_number(k)
1362 0 : scale = casino_m_dependent_factor(l, m)
1363 0 : IF (l == 2) scale = scale*d_factor(k)
1364 : END IF
1365 48 : END FUNCTION casino_mo_scale
1366 :
1367 : ! **************************************************************************************************
1368 : !> \brief m sequence in CASINO/MOLDEN harmonic order: 0,+1,-1,+2,-2,...
1369 : !> \param k ...
1370 : !> \return ...
1371 : ! **************************************************************************************************
1372 0 : FUNCTION casino_m_quantum_number(k) RESULT(m)
1373 : INTEGER, INTENT(IN) :: k
1374 : INTEGER :: m
1375 :
1376 0 : IF (k == 1) THEN
1377 : m = 0
1378 0 : ELSE IF (MOD(k, 2) == 0) THEN
1379 0 : m = k/2
1380 : ELSE
1381 0 : m = -(k/2)
1382 : END IF
1383 0 : END FUNCTION casino_m_quantum_number
1384 :
1385 : ! **************************************************************************************************
1386 : !> \brief CASINO m-dependent normalization factor.
1387 : !> \param l ...
1388 : !> \param m ...
1389 : !> \return ...
1390 : ! **************************************************************************************************
1391 0 : FUNCTION casino_m_dependent_factor(l, m) RESULT(factor)
1392 : INTEGER, INTENT(IN) :: l, m
1393 : REAL(KIND=dp) :: factor
1394 :
1395 : INTEGER :: am
1396 : REAL(KIND=dp) :: prefactor
1397 :
1398 0 : am = ABS(m)
1399 0 : prefactor = MERGE(1.0_dp, 2.0_dp, am == 0)
1400 0 : factor = SQRT(prefactor*factorial(l - am)/factorial(l + am))
1401 0 : END FUNCTION casino_m_dependent_factor
1402 :
1403 : ! **************************************************************************************************
1404 : !> \brief Real factorial for small non-negative integers.
1405 : !> \param n ...
1406 : !> \return ...
1407 : ! **************************************************************************************************
1408 0 : FUNCTION factorial(n) RESULT(value)
1409 : INTEGER, INTENT(IN) :: n
1410 : REAL(KIND=dp) :: value
1411 :
1412 : INTEGER :: i
1413 :
1414 0 : value = 1.0_dp
1415 0 : DO i = 2, n
1416 0 : value = value*REAL(i, KIND=dp)
1417 : END DO
1418 0 : END FUNCTION factorial
1419 :
1420 : ! **************************************************************************************************
1421 : !> \brief Odd double factorial.
1422 : !> \param n ...
1423 : !> \return ...
1424 : ! **************************************************************************************************
1425 28 : FUNCTION odd_double_factorial(n) RESULT(value)
1426 : INTEGER, INTENT(IN) :: n
1427 : REAL(KIND=dp) :: value
1428 :
1429 : INTEGER :: i
1430 :
1431 28 : value = 1.0_dp
1432 28 : DO i = MAX(1, n), 1, -2
1433 28 : value = value*REAL(i, KIND=dp)
1434 : END DO
1435 28 : END FUNCTION odd_double_factorial
1436 :
1437 : ! **************************************************************************************************
1438 : !> \brief Computes the nuclear repulsion energy of a molecular system.
1439 : !> \param particle_set ...
1440 : !> \param kind_set ...
1441 : !> \param e_nn ...
1442 : ! **************************************************************************************************
1443 8 : SUBROUTINE nuclear_repulsion_energy(particle_set, kind_set, e_nn)
1444 : TYPE(particle_type), DIMENSION(:), INTENT(IN), &
1445 : POINTER :: particle_set
1446 : TYPE(qs_kind_type), DIMENSION(:), INTENT(IN), &
1447 : POINTER :: kind_set
1448 : REAL(KIND=dp), INTENT(OUT) :: e_nn
1449 :
1450 : INTEGER :: i, ikind, j, jkind, natoms
1451 : REAL(KIND=dp) :: r_ij, zeff_i, zeff_j
1452 :
1453 8 : natoms = SIZE(particle_set)
1454 8 : e_nn = 0.0_dp
1455 22 : DO i = 1, natoms
1456 14 : CALL get_atomic_kind(particle_set(i)%atomic_kind, kind_number=ikind)
1457 14 : CALL get_qs_kind(kind_set(ikind), zeff=zeff_i)
1458 28 : DO j = i + 1, natoms
1459 24 : r_ij = NORM2(particle_set(i)%r - particle_set(j)%r)
1460 6 : CALL get_atomic_kind(particle_set(j)%atomic_kind, kind_number=jkind)
1461 6 : CALL get_qs_kind(kind_set(jkind), zeff=zeff_j)
1462 20 : e_nn = e_nn + zeff_i*zeff_j/r_ij
1463 : END DO
1464 : END DO
1465 8 : END SUBROUTINE nuclear_repulsion_energy
1466 :
1467 : ! **************************************************************************************************
1468 : !> \brief Computes the CASINO-compatible 3D periodic nuclear repulsion energy.
1469 : !> \param cell ...
1470 : !> \param periodicity ...
1471 : !> \param coord ...
1472 : !> \param charge ...
1473 : !> \param e_nn ...
1474 : ! **************************************************************************************************
1475 2 : SUBROUTINE periodic_nuclear_repulsion_energy(cell, periodicity, coord, charge, e_nn)
1476 : TYPE(cell_type), INTENT(IN), POINTER :: cell
1477 : INTEGER, INTENT(IN) :: periodicity
1478 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: coord
1479 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: charge
1480 : REAL(KIND=dp), INTENT(OUT) :: e_nn
1481 :
1482 : INTEGER :: gmax, i, ig1, ig2, ig3, j, n1, n2, n3, &
1483 : natoms, nmax
1484 : REAL(KIND=dp) :: alpha, alpha2, cutoff_arg, g_cut, g_sq, min_g, min_h, neut_energy, phase, &
1485 : r, real_cut, real_energy, recip_energy, self_energy, struc_im, struc_re, volume
1486 : REAL(KIND=dp), DIMENSION(3) :: delta, g_index, gvec, lattice_shift
1487 :
1488 2 : e_nn = 0.0_dp
1489 2 : IF (periodicity /= 3) RETURN
1490 :
1491 2 : volume = ABS(cell%deth)
1492 2 : IF (volume <= 0.0_dp) CPABORT("CASINO periodic nuclear repulsion requires a non-zero cell volume.")
1493 :
1494 2 : natoms = SIZE(charge)
1495 2 : IF (natoms == 0) RETURN
1496 :
1497 : min_h = HUGE(1.0_dp)
1498 : min_g = HUGE(1.0_dp)
1499 8 : DO i = 1, 3
1500 24 : min_h = MIN(min_h, NORM2(cell%hmat(:, i)))
1501 6 : g_index = 0.0_dp
1502 6 : g_index(i) = 1.0_dp
1503 30 : gvec = 2.0_dp*pi*MATMUL(TRANSPOSE(cell%h_inv), g_index)
1504 26 : min_g = MIN(min_g, NORM2(gvec))
1505 : END DO
1506 2 : IF (min_h <= 0.0_dp .OR. min_g <= 0.0_dp) THEN
1507 0 : CPABORT("CASINO periodic nuclear repulsion requires non-zero lattice vectors.")
1508 : END IF
1509 :
1510 2 : cutoff_arg = SQRT(-LOG(1.0E-12_dp))
1511 2 : alpha = rootpi*(REAL(natoms, KIND=dp)/volume)**(1.0_dp/3.0_dp)
1512 2 : alpha2 = alpha*alpha
1513 2 : real_cut = cutoff_arg/alpha
1514 2 : g_cut = 2.0_dp*alpha*cutoff_arg
1515 2 : nmax = MAX(1, CEILING(real_cut/min_h) + 1)
1516 2 : gmax = MAX(1, CEILING(g_cut/min_g) + 1)
1517 :
1518 2 : real_energy = 0.0_dp
1519 6 : DO i = 1, natoms
1520 14 : DO j = 1, natoms
1521 84 : DO n1 = -nmax, nmax
1522 728 : DO n2 = -nmax, nmax
1523 6552 : DO n3 = -nmax, nmax
1524 5832 : IF (i == j .AND. n1 == 0 .AND. n2 == 0 .AND. n3 == 0) CYCLE
1525 : lattice_shift = REAL(n1, KIND=dp)*cell%hmat(:, 1) + &
1526 : REAL(n2, KIND=dp)*cell%hmat(:, 2) + &
1527 23312 : REAL(n3, KIND=dp)*cell%hmat(:, 3)
1528 23312 : delta = coord(:, i) - coord(:, j) + lattice_shift
1529 23312 : r = NORM2(delta)
1530 6476 : IF (r <= real_cut) real_energy = real_energy + charge(i)*charge(j)*ERFC(alpha*r)/r
1531 : END DO
1532 : END DO
1533 : END DO
1534 : END DO
1535 : END DO
1536 2 : real_energy = 0.5_dp*real_energy
1537 :
1538 2 : recip_energy = 0.0_dp
1539 24 : DO ig1 = -gmax, gmax
1540 266 : DO ig2 = -gmax, gmax
1541 2926 : DO ig3 = -gmax, gmax
1542 2662 : IF (ig1 == 0 .AND. ig2 == 0 .AND. ig3 == 0) CYCLE
1543 10640 : g_index = [REAL(ig1, KIND=dp), REAL(ig2, KIND=dp), REAL(ig3, KIND=dp)]
1544 13300 : gvec = 2.0_dp*pi*MATMUL(TRANSPOSE(cell%h_inv), g_index)
1545 10640 : g_sq = DOT_PRODUCT(gvec, gvec)
1546 2660 : IF (SQRT(g_sq) > g_cut) CYCLE
1547 : struc_re = 0.0_dp
1548 : struc_im = 0.0_dp
1549 1212 : DO i = 1, natoms
1550 3232 : phase = DOT_PRODUCT(gvec, coord(:, i))
1551 808 : struc_re = struc_re + charge(i)*COS(phase)
1552 1212 : struc_im = struc_im + charge(i)*SIN(phase)
1553 : END DO
1554 : recip_energy = recip_energy + EXP(-g_sq/(4.0_dp*alpha2))/g_sq* &
1555 2904 : (struc_re*struc_re + struc_im*struc_im)
1556 : END DO
1557 : END DO
1558 : END DO
1559 2 : recip_energy = 2.0_dp*pi*recip_energy/volume
1560 :
1561 6 : self_energy = -alpha*SUM(charge*charge)/rootpi
1562 6 : neut_energy = -pi*SUM(charge)**2/(2.0_dp*alpha2*volume)
1563 2 : e_nn = real_energy + recip_energy + self_energy + neut_energy
1564 : END SUBROUTINE periodic_nuclear_repulsion_energy
1565 :
1566 : END MODULE casino_utils
|