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