Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2025 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Define methods related to particle_type
10 : !> \par History
11 : !> 10.2014 Move routines out of particle_types.F [Ole Schuett]
12 : !> \author Ole Schuett
13 : ! **************************************************************************************************
14 : MODULE particle_methods
15 : USE atomic_kind_types, ONLY: get_atomic_kind
16 : USE basis_set_types, ONLY: get_gto_basis_set,&
17 : gto_basis_set_p_type
18 : USE cell_methods, ONLY: cell_create,&
19 : set_cell_param
20 : USE cell_types, ONLY: cell_clone,&
21 : cell_release,&
22 : cell_type,&
23 : get_cell,&
24 : pbc,&
25 : real_to_scaled
26 : USE cp_log_handling, ONLY: cp_get_default_logger,&
27 : cp_logger_type,&
28 : cp_to_string
29 : USE cp_output_handling, ONLY: cp_print_key_finished_output,&
30 : cp_print_key_unit_nr
31 : USE cp_units, ONLY: cp_unit_from_cp2k
32 : USE external_potential_types, ONLY: fist_potential_type,&
33 : get_potential
34 : USE input_constants, ONLY: dump_atomic,&
35 : dump_dcd,&
36 : dump_dcd_aligned_cell,&
37 : dump_extxyz,&
38 : dump_pdb,&
39 : dump_xmol
40 : USE input_section_types, ONLY: section_vals_get_subs_vals,&
41 : section_vals_type,&
42 : section_vals_val_get
43 : USE kinds, ONLY: default_string_length,&
44 : dp,&
45 : sp
46 : USE mathconstants, ONLY: degree
47 : USE mathlib, ONLY: angle,&
48 : dihedral_angle
49 : USE memory_utilities, ONLY: reallocate
50 : USE particle_types, ONLY: get_particle_pos_or_vel,&
51 : particle_type
52 : USE physcon, ONLY: massunit
53 : USE qmmm_ff_fist, ONLY: qmmm_ff_precond_only_qm
54 : USE qs_kind_types, ONLY: get_qs_kind,&
55 : qs_kind_type
56 : USE shell_potential_types, ONLY: get_shell,&
57 : shell_kind_type
58 : USE string_utilities, ONLY: uppercase
59 : USE util, ONLY: sort,&
60 : sort_unique
61 : #include "./base/base_uses.f90"
62 :
63 : IMPLICIT NONE
64 :
65 : PRIVATE
66 :
67 : ! Public subroutines
68 :
69 : PUBLIC :: write_fist_particle_coordinates, &
70 : write_qs_particle_coordinates, &
71 : write_particle_distances, &
72 : write_particle_coordinates, &
73 : write_structure_data, &
74 : get_particle_set, &
75 : write_particle_matrix
76 :
77 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'particle_methods'
78 :
79 : CONTAINS
80 :
81 : ! **************************************************************************************************
82 : !> \brief Get the components of a particle set.
83 : !> \param particle_set ...
84 : !> \param qs_kind_set ...
85 : !> \param first_sgf ...
86 : !> \param last_sgf ...
87 : !> \param nsgf ...
88 : !> \param nmao ...
89 : !> \param basis ...
90 : !> \date 14.01.2002
91 : !> \par History
92 : !> - particle type cleaned (13.10.2003,MK)
93 : !> - refactoring and add basis set option (17.08.2010,jhu)
94 : !> \author MK
95 : !> \version 1.0
96 : ! **************************************************************************************************
97 171268 : SUBROUTINE get_particle_set(particle_set, qs_kind_set, first_sgf, last_sgf, nsgf, &
98 171268 : nmao, basis)
99 :
100 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
101 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
102 : INTEGER, DIMENSION(:), INTENT(INOUT), OPTIONAL :: first_sgf, last_sgf, nsgf, nmao
103 : TYPE(gto_basis_set_p_type), DIMENSION(:), OPTIONAL :: basis
104 :
105 : INTEGER :: ikind, iparticle, isgf, nparticle, ns
106 :
107 171268 : CPASSERT(ASSOCIATED(particle_set))
108 :
109 171268 : nparticle = SIZE(particle_set)
110 171268 : IF (PRESENT(first_sgf)) THEN
111 36882 : CPASSERT(SIZE(first_sgf) >= nparticle)
112 : END IF
113 171268 : IF (PRESENT(last_sgf)) THEN
114 30568 : CPASSERT(SIZE(last_sgf) >= nparticle)
115 : END IF
116 171268 : IF (PRESENT(nsgf)) THEN
117 133948 : CPASSERT(SIZE(nsgf) >= nparticle)
118 : END IF
119 171268 : IF (PRESENT(nmao)) THEN
120 14 : CPASSERT(SIZE(nmao) >= nparticle)
121 : END IF
122 :
123 171268 : IF (PRESENT(first_sgf) .OR. PRESENT(last_sgf) .OR. PRESENT(nsgf)) THEN
124 : isgf = 0
125 982791 : DO iparticle = 1, nparticle
126 812001 : CALL get_atomic_kind(particle_set(iparticle)%atomic_kind, kind_number=ikind)
127 812001 : IF (PRESENT(basis)) THEN
128 603137 : IF (ASSOCIATED(basis(ikind)%gto_basis_set)) THEN
129 603133 : CALL get_gto_basis_set(gto_basis_set=basis(ikind)%gto_basis_set, nsgf=ns)
130 : ELSE
131 4 : ns = 0
132 : END IF
133 : ELSE
134 208864 : CALL get_qs_kind(qs_kind_set(ikind), nsgf=ns)
135 : END IF
136 812001 : IF (PRESENT(nsgf)) nsgf(iparticle) = ns
137 812001 : IF (PRESENT(first_sgf)) first_sgf(iparticle) = isgf + 1
138 812001 : isgf = isgf + ns
139 1795270 : IF (PRESENT(last_sgf)) last_sgf(iparticle) = isgf
140 : END DO
141 : END IF
142 :
143 171268 : IF (PRESENT(first_sgf)) THEN
144 36882 : IF (SIZE(first_sgf) > nparticle) first_sgf(nparticle + 1) = isgf + 1
145 : END IF
146 :
147 171268 : IF (PRESENT(nmao)) THEN
148 86 : DO iparticle = 1, nparticle
149 72 : CALL get_atomic_kind(particle_set(iparticle)%atomic_kind, kind_number=ikind)
150 72 : CALL get_qs_kind(qs_kind_set(ikind), mao=ns)
151 86 : nmao(iparticle) = ns
152 : END DO
153 : END IF
154 :
155 171268 : END SUBROUTINE get_particle_set
156 :
157 : ! **************************************************************************************************
158 : !> \brief Should be able to write a few formats e.g. xmol, and some binary
159 : !> format (dcd) some format can be used for x,v,f
160 : !>
161 : !> FORMAT CONTENT UNITS x, v, f
162 : !> XMOL POS, VEL, FORCE, POS_VEL, POS_VEL_FORCE Angstrom, a.u., a.u.
163 : !>
164 : !> \param particle_set ...
165 : !> \param iunit ...
166 : !> \param output_format ...
167 : !> \param content ...
168 : !> \param title ...
169 : !> \param cell ...
170 : !> \param array ...
171 : !> \param unit_conv ...
172 : !> \param charge_occup ...
173 : !> \param charge_beta ...
174 : !> \param charge_extended ...
175 : !> \param print_kind ...
176 : !> \date 14.01.2002
177 : !> \author MK
178 : !> \version 1.0
179 : ! **************************************************************************************************
180 26646 : SUBROUTINE write_particle_coordinates(particle_set, iunit, output_format, &
181 26646 : content, title, cell, array, unit_conv, &
182 : charge_occup, charge_beta, &
183 : charge_extended, print_kind)
184 :
185 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
186 : INTEGER :: iunit, output_format
187 : CHARACTER(LEN=*) :: content, title
188 : TYPE(cell_type), OPTIONAL, POINTER :: cell
189 : REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL :: array
190 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: unit_conv
191 : LOGICAL, INTENT(IN), OPTIONAL :: charge_occup, charge_beta, &
192 : charge_extended, print_kind
193 :
194 : CHARACTER(len=*), PARAMETER :: routineN = 'write_particle_coordinates'
195 :
196 : CHARACTER(LEN=120) :: line
197 : CHARACTER(LEN=2) :: element_symbol
198 : CHARACTER(LEN=4) :: name
199 : CHARACTER(LEN=default_string_length) :: atm_name, my_format
200 : INTEGER :: handle, iatom, natom
201 : LOGICAL :: dummy, my_charge_beta, &
202 : my_charge_extended, my_charge_occup, &
203 : my_print_kind
204 : REAL(KIND=dp) :: angle_alpha, angle_beta, angle_gamma, &
205 : factor, qeff
206 26646 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: arr
207 : REAL(KIND=dp), DIMENSION(3) :: abc, angles, f, r, v
208 : REAL(KIND=dp), DIMENSION(3, 3) :: h
209 26646 : REAL(KIND=sp), ALLOCATABLE, DIMENSION(:) :: x4, y4, z4
210 : TYPE(cell_type), POINTER :: cell_dcd
211 : TYPE(fist_potential_type), POINTER :: fist_potential
212 : TYPE(shell_kind_type), POINTER :: shell
213 :
214 26646 : CALL timeset(routineN, handle)
215 :
216 26646 : natom = SIZE(particle_set)
217 26646 : IF (PRESENT(array)) THEN
218 1741 : SELECT CASE (TRIM(content))
219 : CASE ("POS_VEL", "POS_VEL_FORCE")
220 1741 : CPABORT("Illegal usage")
221 : END SELECT
222 : END IF
223 26646 : factor = 1.0_dp
224 26646 : IF (PRESENT(unit_conv)) THEN
225 26495 : factor = unit_conv
226 : END IF
227 53219 : SELECT CASE (output_format)
228 : CASE (dump_xmol, dump_extxyz)
229 26573 : my_print_kind = .FALSE.
230 26573 : IF (PRESENT(print_kind)) my_print_kind = print_kind
231 26573 : WRITE (iunit, "(I8)") natom
232 26573 : WRITE (iunit, "(A)") TRIM(title)
233 1334559 : DO iatom = 1, natom
234 : CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
235 1307986 : element_symbol=element_symbol)
236 1307986 : IF (LEN_TRIM(element_symbol) == 0 .OR. my_print_kind) THEN
237 : CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
238 24 : name=atm_name)
239 24 : dummy = qmmm_ff_precond_only_qm(id1=atm_name)
240 24 : my_format = "(A,"
241 24 : atm_name = TRIM(atm_name)
242 : ELSE
243 1307962 : my_format = "(T2,A2,"
244 1307962 : atm_name = TRIM(element_symbol)
245 : END IF
246 26573 : SELECT CASE (TRIM(content))
247 : CASE ("POS")
248 1192889 : IF (PRESENT(array)) THEN
249 47741 : r(1:3) = get_particle_pos_or_vel(iatom, particle_set, array)
250 : ELSE
251 4580592 : r(:) = particle_set(iatom)%r(:)
252 : END IF
253 4771556 : WRITE (iunit, TRIM(my_format)//"1X,3F20.10)") TRIM(atm_name), r(1:3)*factor
254 : CASE ("VEL")
255 85469 : IF (PRESENT(array)) THEN
256 0 : v(1:3) = get_particle_pos_or_vel(iatom, particle_set, array)
257 : ELSE
258 341876 : v(:) = particle_set(iatom)%v(:)
259 : END IF
260 341876 : WRITE (iunit, TRIM(my_format)//"1X,3F20.10)") TRIM(atm_name), v(1:3)*factor
261 : CASE ("FORCE")
262 21019 : IF (PRESENT(array)) THEN
263 0 : f(:) = array((iatom - 1)*3 + 1:(iatom - 1)*3 + 3)
264 : ELSE
265 84076 : f(:) = particle_set(iatom)%f(:)
266 : END IF
267 84076 : WRITE (iunit, TRIM(my_format)//"1X,3F20.10)") TRIM(atm_name), f(1:3)*factor
268 : CASE ("FORCE_MIXING_LABELS")
269 8609 : IF (PRESENT(array)) THEN
270 34436 : f(:) = array((iatom - 1)*3 + 1:(iatom - 1)*3 + 3)
271 : ELSE
272 0 : f(:) = particle_set(iatom)%f(:)
273 : END IF
274 1342422 : WRITE (iunit, TRIM(my_format)//"1X,3F20.10)") TRIM(atm_name), f(1:3)*factor
275 : END SELECT
276 : END DO
277 : CASE (dump_atomic)
278 170 : DO iatom = 1, natom
279 10 : SELECT CASE (TRIM(content))
280 : CASE ("POS")
281 160 : IF (PRESENT(array)) THEN
282 0 : r(1:3) = get_particle_pos_or_vel(iatom, particle_set, array)
283 : ELSE
284 640 : r(:) = particle_set(iatom)%r(:)
285 : END IF
286 640 : WRITE (iunit, "(3F20.10)") r(1:3)*factor
287 : CASE ("VEL")
288 0 : IF (PRESENT(array)) THEN
289 0 : v(1:3) = get_particle_pos_or_vel(iatom, particle_set, array)
290 : ELSE
291 0 : v(:) = particle_set(iatom)%v(:)
292 : END IF
293 0 : WRITE (iunit, "(3F20.10)") v(1:3)*factor
294 : CASE ("FORCE")
295 0 : IF (PRESENT(array)) THEN
296 0 : f(:) = array((iatom - 1)*3 + 1:(iatom - 1)*3 + 3)
297 : ELSE
298 0 : f(:) = particle_set(iatom)%f(:)
299 : END IF
300 0 : WRITE (iunit, "(3F20.10)") f(1:3)*factor
301 : CASE ("FORCE_MIXING_LABELS")
302 0 : IF (PRESENT(array)) THEN
303 0 : f(:) = array((iatom - 1)*3 + 1:(iatom - 1)*3 + 3)
304 : ELSE
305 0 : f(:) = particle_set(iatom)%f(:)
306 : END IF
307 160 : WRITE (iunit, "(3F20.10)") f(1:3)*factor
308 : END SELECT
309 : END DO
310 : CASE (dump_dcd, dump_dcd_aligned_cell)
311 4 : IF (.NOT. (PRESENT(cell))) THEN
312 0 : CPABORT("Cell is not present! Report this bug!")
313 : END IF
314 : CALL get_cell(cell, alpha=angle_alpha, beta=angle_beta, gamma=angle_gamma, &
315 4 : abc=abc)
316 4 : IF (.NOT. cell%orthorhombic .AND. (output_format == dump_dcd_aligned_cell)) THEN
317 : ! In the case of a non-orthorhombic cell adopt a common convention
318 : ! for the orientation of the cell with respect to the Cartesian axes:
319 : ! Cell vector a is aligned with the x axis and the cell vector b lies
320 : ! in the xy plane.
321 0 : NULLIFY (cell_dcd)
322 0 : CALL cell_create(cell_dcd)
323 0 : CALL cell_clone(cell, cell_dcd, tag="CELL_DCD")
324 0 : angles(1) = angle_alpha/degree
325 0 : angles(2) = angle_beta/degree
326 0 : angles(3) = angle_gamma/degree
327 : CALL set_cell_param(cell_dcd, abc, angles, &
328 0 : do_init_cell=.TRUE.)
329 0 : h(1:3, 1:3) = MATMUL(cell_dcd%hmat(1:3, 1:3), cell%h_inv(1:3, 1:3))
330 0 : CALL cell_release(cell_dcd)
331 : END IF
332 12 : ALLOCATE (arr(3, natom))
333 4 : IF (PRESENT(array)) THEN
334 0 : arr(1:3, 1:natom) = RESHAPE(array, [3, natom])
335 : ELSE
336 8 : SELECT CASE (TRIM(content))
337 : CASE ("POS")
338 1156 : DO iatom = 1, natom
339 4612 : arr(1:3, iatom) = particle_set(iatom)%r(1:3)
340 : END DO
341 : CASE ("VEL")
342 0 : DO iatom = 1, natom
343 0 : arr(1:3, iatom) = particle_set(iatom)%v(1:3)
344 : END DO
345 : CASE ("FORCE")
346 0 : DO iatom = 1, natom
347 0 : arr(1:3, iatom) = particle_set(iatom)%f(1:3)
348 : END DO
349 : CASE DEFAULT
350 4 : CPABORT("Illegal DCD dump type")
351 : END SELECT
352 : END IF
353 12 : ALLOCATE (x4(natom))
354 8 : ALLOCATE (y4(natom))
355 8 : ALLOCATE (z4(natom))
356 4 : IF (.NOT. cell%orthorhombic .AND. (output_format == dump_dcd_aligned_cell)) THEN
357 0 : x4(1:natom) = REAL(MATMUL(h(1, 1:3), arr(1:3, 1:natom)), KIND=sp)
358 0 : y4(1:natom) = REAL(MATMUL(h(2, 1:3), arr(1:3, 1:natom)), KIND=sp)
359 0 : z4(1:natom) = REAL(MATMUL(h(3, 1:3), arr(1:3, 1:natom)), KIND=sp)
360 : ELSE
361 1156 : x4(1:natom) = REAL(arr(1, 1:natom), KIND=sp)
362 1156 : y4(1:natom) = REAL(arr(2, 1:natom), KIND=sp)
363 1156 : z4(1:natom) = REAL(arr(3, 1:natom), KIND=sp)
364 : END IF
365 4 : WRITE (iunit) abc(1)*factor, angle_gamma, abc(2)*factor, &
366 8 : angle_beta, angle_alpha, abc(3)*factor
367 1156 : WRITE (iunit) x4*REAL(factor, KIND=sp)
368 1156 : WRITE (iunit) y4*REAL(factor, KIND=sp)
369 1156 : WRITE (iunit) z4*REAL(factor, KIND=sp)
370 : ! Release work storage
371 4 : DEALLOCATE (arr)
372 4 : DEALLOCATE (x4)
373 4 : DEALLOCATE (y4)
374 8 : DEALLOCATE (z4)
375 : CASE (dump_pdb)
376 59 : my_charge_occup = .FALSE.
377 59 : IF (PRESENT(charge_occup)) my_charge_occup = charge_occup
378 59 : my_charge_beta = .FALSE.
379 59 : IF (PRESENT(charge_beta)) my_charge_beta = charge_beta
380 59 : my_charge_extended = .FALSE.
381 59 : IF (PRESENT(charge_extended)) my_charge_extended = charge_extended
382 59 : IF (LEN_TRIM(title) > 0) THEN
383 : WRITE (UNIT=iunit, FMT="(A6,T11,A)") &
384 59 : "REMARK", TRIM(title)
385 : END IF
386 59 : CALL get_cell(cell, alpha=angle_alpha, beta=angle_beta, gamma=angle_gamma, abc=abc)
387 : ! COLUMNS DATA TYPE CONTENTS
388 : ! --------------------------------------------------
389 : ! 1 - 6 Record name "CRYST1"
390 : ! 7 - 15 Real(9.3) a (Angstroms)
391 : ! 16 - 24 Real(9.3) b (Angstroms)
392 : ! 25 - 33 Real(9.3) c (Angstroms)
393 : ! 34 - 40 Real(7.2) alpha (degrees)
394 : ! 41 - 47 Real(7.2) beta (degrees)
395 : ! 48 - 54 Real(7.2) gamma (degrees)
396 : ! 56 - 66 LString Space group
397 : ! 67 - 70 Integer Z value
398 : WRITE (UNIT=iunit, FMT="(A6,3F9.3,3F7.2)") &
399 236 : "CRYST1", abc(1:3)*factor, angle_alpha, angle_beta, angle_gamma
400 59 : WRITE (UNIT=line(1:6), FMT="(A6)") "ATOM "
401 2999 : DO iatom = 1, natom
402 2940 : line = ""
403 : ! COLUMNS DATA TYPE CONTENTS
404 : ! 1 - 6 Record name "ATOM "
405 : ! 7 - 11 Integer Atom serial number
406 : ! 13 - 16 Atom Atom name
407 : ! 17 Character Alternate location indicator
408 : ! 18 - 20 Residue name Residue name
409 : ! 22 Character Chain identifier
410 : ! 23 - 26 Integer Residue sequence number
411 : ! 27 AChar Code for insertion of residues
412 : ! 31 - 38 Real(8.3) Orthogonal coordinates for X in Angstrom
413 : ! 39 - 46 Real(8.3) Orthogonal coordinates for Y in Angstrom
414 : ! 47 - 54 Real(8.3) Orthogonal coordinates for Z in Angstrom
415 : ! 55 - 60 Real(6.2) Occupancy
416 : ! 61 - 66 Real(6.2) Temperature factor (Default = 0.0)
417 : ! 73 - 76 LString(4) Segment identifier, left-justified
418 : ! 77 - 78 LString(2) Element symbol, right-justified
419 : ! 79 - 80 LString(2) Charge on the atom
420 : CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
421 : element_symbol=element_symbol, name=atm_name, &
422 2940 : fist_potential=fist_potential, shell=shell)
423 2940 : IF (LEN_TRIM(element_symbol) == 0) THEN
424 0 : dummy = qmmm_ff_precond_only_qm(id1=atm_name)
425 : END IF
426 2940 : name = TRIM(atm_name)
427 2940 : IF (ASSOCIATED(fist_potential)) THEN
428 2940 : CALL get_potential(potential=fist_potential, qeff=qeff)
429 : ELSE
430 0 : qeff = 0.0_dp
431 : END IF
432 2940 : IF (ASSOCIATED(shell)) CALL get_shell(shell=shell, charge=qeff)
433 2940 : WRITE (UNIT=line(1:6), FMT="(A6)") "ATOM "
434 2940 : WRITE (UNIT=line(7:11), FMT="(I5)") MODULO(iatom, 100000)
435 2940 : WRITE (UNIT=line(13:16), FMT="(A4)") ADJUSTL(name)
436 : ! WRITE (UNIT=line(18:20),FMT="(A3)") TRIM(resname)
437 : ! WRITE (UNIT=line(23:26),FMT="(I4)") MODULO(idres,10000)
438 5880 : SELECT CASE (TRIM(content))
439 : CASE ("POS")
440 2940 : IF (PRESENT(array)) THEN
441 0 : r(1:3) = get_particle_pos_or_vel(iatom, particle_set, array)
442 : ELSE
443 11760 : r(:) = particle_set(iatom)%r(:)
444 : END IF
445 11760 : WRITE (UNIT=line(31:54), FMT="(3F8.3)") r(1:3)*factor
446 : CASE DEFAULT
447 2940 : CPABORT("PDB dump only for trajectory available")
448 : END SELECT
449 2940 : IF (my_charge_occup) THEN
450 2130 : WRITE (UNIT=line(55:60), FMT="(F6.2)") qeff
451 : ELSE
452 810 : WRITE (UNIT=line(55:60), FMT="(F6.2)") 0.0_dp
453 : END IF
454 2940 : IF (my_charge_beta) THEN
455 480 : WRITE (UNIT=line(61:66), FMT="(F6.2)") qeff
456 : ELSE
457 2460 : WRITE (UNIT=line(61:66), FMT="(F6.2)") 0.0_dp
458 : END IF
459 : ! WRITE (UNIT=line(73:76),FMT="(A4)") ADJUSTL(TRIM(molname))
460 2940 : WRITE (UNIT=line(77:78), FMT="(A2)") ADJUSTR(TRIM(element_symbol))
461 2940 : IF (my_charge_extended) THEN
462 330 : WRITE (UNIT=line(81:), FMT="(SP,F0.8)") qeff
463 : END IF
464 2999 : WRITE (UNIT=iunit, FMT="(A)") TRIM(line)
465 : END DO
466 59 : WRITE (UNIT=iunit, FMT="(A)") "END"
467 : CASE DEFAULT
468 26705 : CPABORT("Illegal dump type")
469 : END SELECT
470 :
471 26646 : CALL timestop(handle)
472 :
473 26646 : END SUBROUTINE write_particle_coordinates
474 :
475 : ! **************************************************************************************************
476 : !> \brief Write the atomic coordinates to the output unit.
477 : !> \param particle_set ...
478 : !> \param subsys_section ...
479 : !> \param charges ...
480 : !> \date 05.06.2000
481 : !> \author MK
482 : !> \version 1.0
483 : ! **************************************************************************************************
484 9693 : SUBROUTINE write_fist_particle_coordinates(particle_set, subsys_section, charges)
485 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
486 : TYPE(section_vals_type), POINTER :: subsys_section
487 : REAL(KIND=dp), DIMENSION(:), OPTIONAL :: charges
488 :
489 : CHARACTER(LEN=default_string_length) :: name, unit_str
490 : INTEGER :: iatom, ikind, iw, natom
491 : REAL(KIND=dp) :: conv, mass, qcore, qeff, qshell
492 : TYPE(cp_logger_type), POINTER :: logger
493 : TYPE(shell_kind_type), POINTER :: shell_kind
494 :
495 9693 : NULLIFY (logger)
496 9693 : NULLIFY (shell_kind)
497 :
498 9693 : logger => cp_get_default_logger()
499 : iw = cp_print_key_unit_nr(logger, subsys_section, &
500 9693 : "PRINT%ATOMIC_COORDINATES", extension=".coordLog")
501 :
502 9693 : CALL section_vals_val_get(subsys_section, "PRINT%ATOMIC_COORDINATES%UNIT", c_val=unit_str)
503 9693 : conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
504 9693 : CALL uppercase(unit_str)
505 9693 : IF (iw > 0) THEN
506 : WRITE (UNIT=iw, FMT="(/,/,T2,A)") &
507 2507 : "MODULE FIST: ATOMIC COORDINATES IN "//TRIM(unit_str)
508 : WRITE (UNIT=iw, FMT="(/,T4,A,T30,A,T44,A,T58,A,T66,A,T77,A)") &
509 2507 : "Atom Kind Name", "X", "Y", "Z", "q(eff)", "Mass"
510 2507 : natom = SIZE(particle_set)
511 363176 : DO iatom = 1, natom
512 : CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
513 : kind_number=ikind, &
514 : name=name, &
515 : mass=mass, &
516 : qeff=qeff, &
517 360669 : shell=shell_kind)
518 360669 : IF (PRESENT(charges)) qeff = charges(iatom)
519 360669 : IF (ASSOCIATED(shell_kind)) THEN
520 : CALL get_shell(shell=shell_kind, &
521 : charge_core=qcore, &
522 3426 : charge_shell=qshell)
523 3426 : qeff = qcore + qshell
524 : END IF
525 : WRITE (UNIT=iw, FMT="(T2,I6,1X,I4,1X,A7,3(1X,F13.6),2(1X,F8.4))") &
526 1805852 : iatom, ikind, name, particle_set(iatom)%r(1:3)*conv, qeff, mass/massunit
527 : END DO
528 2507 : WRITE (iw, "(A)") ""
529 : END IF
530 :
531 : CALL cp_print_key_finished_output(iw, logger, subsys_section, &
532 9693 : "PRINT%ATOMIC_COORDINATES")
533 :
534 9693 : END SUBROUTINE write_fist_particle_coordinates
535 :
536 : ! **************************************************************************************************
537 : !> \brief Write the atomic coordinates to the output unit.
538 : !> \param particle_set ...
539 : !> \param qs_kind_set ...
540 : !> \param subsys_section ...
541 : !> \param label ...
542 : !> \date 05.06.2000
543 : !> \author MK
544 : !> \version 1.0
545 : ! **************************************************************************************************
546 15228 : SUBROUTINE write_qs_particle_coordinates(particle_set, qs_kind_set, subsys_section, label)
547 :
548 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
549 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
550 : TYPE(section_vals_type), POINTER :: subsys_section
551 : CHARACTER(LEN=*), INTENT(IN) :: label
552 :
553 : CHARACTER(len=*), PARAMETER :: routineN = 'write_qs_particle_coordinates'
554 :
555 : CHARACTER(LEN=2) :: element_symbol
556 : CHARACTER(LEN=default_string_length) :: unit_str
557 : INTEGER :: handle, iatom, ikind, iw, natom, z
558 : REAL(KIND=dp) :: conv, mass, zeff
559 : TYPE(cp_logger_type), POINTER :: logger
560 :
561 15228 : CALL timeset(routineN, handle)
562 :
563 15228 : NULLIFY (logger)
564 15228 : logger => cp_get_default_logger()
565 : iw = cp_print_key_unit_nr(logger, subsys_section, &
566 15228 : "PRINT%ATOMIC_COORDINATES", extension=".coordLog")
567 :
568 15228 : CALL section_vals_val_get(subsys_section, "PRINT%ATOMIC_COORDINATES%UNIT", c_val=unit_str)
569 15228 : conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
570 15228 : CALL uppercase(unit_str)
571 15228 : IF (iw > 0) THEN
572 : WRITE (UNIT=iw, FMT="(/,/,T2,A)") &
573 3225 : "MODULE "//TRIM(label)//": ATOMIC COORDINATES IN "//TRIM(unit_str)
574 : WRITE (UNIT=iw, FMT="(/,T4,A,T30,A,T44,A,T58,A,T66,A,T77,A)") &
575 3225 : "Atom Kind Element", "X", "Y", "Z", "Z(eff)", "Mass"
576 3225 : natom = SIZE(particle_set)
577 20073 : DO iatom = 1, natom
578 : CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
579 : kind_number=ikind, &
580 : element_symbol=element_symbol, &
581 : mass=mass, &
582 16848 : z=z)
583 16848 : CALL get_qs_kind(qs_kind_set(ikind), zeff=zeff)
584 : WRITE (UNIT=iw, FMT="(T2,I6,1X,I4,1X,A2,1X,I4,3(1X,F13.6),2(1X,F8.4))") &
585 70617 : iatom, ikind, element_symbol, z, particle_set(iatom)%r(1:3)*conv, zeff, mass/massunit
586 : END DO
587 3225 : WRITE (iw, "(A)") ""
588 : END IF
589 :
590 : CALL cp_print_key_finished_output(iw, logger, subsys_section, &
591 15228 : "PRINT%ATOMIC_COORDINATES")
592 :
593 15228 : CALL timestop(handle)
594 :
595 15228 : END SUBROUTINE write_qs_particle_coordinates
596 :
597 : ! **************************************************************************************************
598 : !> \brief Write the matrix of the particle distances to the output unit.
599 : !> \param particle_set ...
600 : !> \param cell ...
601 : !> \param subsys_section ...
602 : !> \date 06.10.2000
603 : !> \author Matthias Krack
604 : !> \version 1.0
605 : ! **************************************************************************************************
606 10121 : SUBROUTINE write_particle_distances(particle_set, cell, subsys_section)
607 :
608 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
609 : TYPE(cell_type), POINTER :: cell
610 : TYPE(section_vals_type), POINTER :: subsys_section
611 :
612 : CHARACTER(len=*), PARAMETER :: routineN = 'write_particle_distances'
613 :
614 : CHARACTER(LEN=default_string_length) :: unit_str
615 : INTEGER :: handle, iatom, iw, jatom, natom
616 : INTEGER, DIMENSION(3) :: periodic
617 : LOGICAL :: explicit
618 : REAL(KIND=dp) :: conv, dab, dab_abort, dab_min, dab_warn
619 10121 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: distance_matrix
620 : REAL(KIND=dp), DIMENSION(3) :: rab
621 : TYPE(cp_logger_type), POINTER :: logger
622 :
623 10121 : CALL timeset(routineN, handle)
624 :
625 10121 : CPASSERT(ASSOCIATED(particle_set))
626 10121 : CPASSERT(ASSOCIATED(cell))
627 10121 : CPASSERT(ASSOCIATED(subsys_section))
628 :
629 10121 : NULLIFY (logger)
630 10121 : logger => cp_get_default_logger()
631 : iw = cp_print_key_unit_nr(logger, subsys_section, &
632 10121 : "PRINT%INTERATOMIC_DISTANCES", extension=".distLog")
633 :
634 10121 : CALL section_vals_val_get(subsys_section, "PRINT%INTERATOMIC_DISTANCES%UNIT", c_val=unit_str)
635 10121 : conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
636 : CALL section_vals_val_get(subsys_section, "PRINT%INTERATOMIC_DISTANCES%CHECK_INTERATOMIC_DISTANCES", &
637 10121 : r_val=dab_min, explicit=explicit)
638 :
639 10121 : dab_abort = 0.0_dp
640 10121 : dab_warn = 0.0_dp
641 10121 : natom = SIZE(particle_set)
642 :
643 : ! Compute interatomic distances only if their printout or check is explicitly requested
644 : ! Disable the default check for systems with more than 3000 atoms
645 10121 : IF (explicit .OR. (iw > 0) .OR. (natom <= 2000)) THEN
646 10079 : IF (dab_min > 0.0_dp) THEN
647 10075 : dab_warn = dab_min*conv
648 4 : ELSE IF (dab_min < 0.0_dp) THEN
649 0 : dab_abort = ABS(dab_min)*conv
650 : END IF
651 : END IF
652 :
653 10121 : IF ((iw > 0) .OR. (dab_abort > 0.0_dp) .OR. (dab_warn > 0.0_dp)) THEN
654 10075 : CALL get_cell(cell=cell, periodic=periodic)
655 10075 : IF (iw > 0) THEN
656 128 : ALLOCATE (distance_matrix(natom, natom))
657 72180 : distance_matrix(:, :) = 0.0_dp
658 : END IF
659 321444 : DO iatom = 1, natom
660 116881130 : DO jatom = iatom + 1, natom
661 : rab(:) = pbc(particle_set(iatom)%r(:), &
662 116559686 : particle_set(jatom)%r(:), cell)
663 116559686 : dab = SQRT(rab(1)*rab(1) + rab(2)*rab(2) + rab(3)*rab(3))*conv
664 116559686 : IF (dab_abort > 0.0_dp) THEN
665 : ! Stop the run for interatomic distances smaller than the requested threshold
666 0 : IF (dab < dab_abort) THEN
667 : CALL cp_abort(__LOCATION__, "The distance between the atoms "// &
668 : TRIM(ADJUSTL(cp_to_string(iatom, fmt="(I8)")))//" and "// &
669 : TRIM(ADJUSTL(cp_to_string(jatom, fmt="(I8)")))//" is only "// &
670 : TRIM(ADJUSTL(cp_to_string(dab, fmt="(F6.3)")))//" "// &
671 : TRIM(ADJUSTL(unit_str))//" and thus smaller than the requested threshold of "// &
672 : TRIM(ADJUSTL(cp_to_string(dab_abort, fmt="(F6.3)")))//" "// &
673 0 : TRIM(ADJUSTL(unit_str)))
674 : END IF
675 : END IF
676 116559686 : IF (dab < dab_warn) THEN
677 : ! Print warning for interatomic distances smaller than the requested threshold
678 : CALL cp_warn(__LOCATION__, "The distance between the atoms "// &
679 : TRIM(ADJUSTL(cp_to_string(iatom, fmt="(I8)")))//" and "// &
680 : TRIM(ADJUSTL(cp_to_string(jatom, fmt="(I8)")))//" is only "// &
681 : TRIM(ADJUSTL(cp_to_string(dab, fmt="(F6.3)")))//" "// &
682 : TRIM(ADJUSTL(unit_str))//" and thus smaller than the threshold of "// &
683 : TRIM(ADJUSTL(cp_to_string(dab_warn, fmt="(F6.3)")))//" "// &
684 908 : TRIM(ADJUSTL(unit_str)))
685 : END IF
686 116871055 : IF (iw > 0) THEN
687 35183 : distance_matrix(iatom, jatom) = dab
688 35183 : distance_matrix(jatom, iatom) = distance_matrix(iatom, jatom)
689 : END IF
690 : END DO
691 : END DO
692 10075 : IF (iw > 0) THEN
693 : ! Print the distance matrix
694 : WRITE (UNIT=iw, FMT="(/,/,T2,A)") &
695 32 : "INTERATOMIC DISTANCES IN "//TRIM(unit_str)
696 32 : CALL write_particle_matrix(distance_matrix, particle_set, iw)
697 32 : IF (ALLOCATED(distance_matrix)) DEALLOCATE (distance_matrix)
698 : END IF
699 : CALL cp_print_key_finished_output(iw, logger, subsys_section, &
700 10075 : "PRINT%INTERATOMIC_DISTANCES")
701 : END IF
702 :
703 10121 : CALL timestop(handle)
704 :
705 10121 : END SUBROUTINE write_particle_distances
706 :
707 : ! **************************************************************************************************
708 : !> \brief ...
709 : !> \param matrix ...
710 : !> \param particle_set ...
711 : !> \param iw ...
712 : !> \param el_per_part ...
713 : !> \param Ilist ...
714 : !> \param parts_per_line : number of particle columns to be printed in one line
715 : ! **************************************************************************************************
716 52 : SUBROUTINE write_particle_matrix(matrix, particle_set, iw, el_per_part, Ilist, parts_per_line)
717 : REAL(KIND=dp), DIMENSION(:, :) :: matrix
718 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
719 : INTEGER, INTENT(IN) :: iw
720 : INTEGER, INTENT(IN), OPTIONAL :: el_per_part
721 : INTEGER, DIMENSION(:), OPTIONAL, POINTER :: Ilist
722 : INTEGER, INTENT(IN), OPTIONAL :: parts_per_line
723 :
724 : CHARACTER(LEN=2) :: element_symbol
725 : CHARACTER(LEN=default_string_length) :: fmt_string1, fmt_string2
726 : INTEGER :: from, i, iatom, icol, jatom, katom, &
727 : my_el_per_part, my_parts_per_line, &
728 : natom, to
729 52 : INTEGER, DIMENSION(:), POINTER :: my_list
730 :
731 52 : my_el_per_part = 1
732 20 : IF (PRESENT(el_per_part)) my_el_per_part = el_per_part
733 52 : my_parts_per_line = 5
734 52 : IF (PRESENT(parts_per_line)) my_parts_per_line = MAX(parts_per_line, 1)
735 : WRITE (fmt_string1, FMT='(A,I0,A)') &
736 52 : "(/,T2,11X,", my_parts_per_line, "(4X,I5,4X))"
737 : WRITE (fmt_string2, FMT='(A,I0,A)') &
738 52 : "(T2,I5,2X,A2,2X,", my_parts_per_line, "(1X,F12.6))"
739 52 : IF (PRESENT(Ilist)) THEN
740 20 : natom = SIZE(Ilist)
741 : ELSE
742 32 : natom = SIZE(particle_set)
743 : END IF
744 156 : ALLOCATE (my_list(natom))
745 52 : IF (PRESENT(Ilist)) THEN
746 120 : my_list = Ilist
747 : ELSE
748 923 : DO i = 1, natom
749 923 : my_list(i) = i
750 : END DO
751 : END IF
752 52 : natom = natom*my_el_per_part
753 286 : DO jatom = 1, natom, my_parts_per_line
754 234 : from = jatom
755 234 : to = MIN(from + my_parts_per_line - 1, natom)
756 1275 : WRITE (UNIT=iw, FMT=TRIM(fmt_string1)) (icol, icol=from, to)
757 15441 : DO iatom = 1, natom
758 15155 : katom = iatom/my_el_per_part
759 15155 : IF (MOD(iatom, my_el_per_part) /= 0) katom = katom + 1
760 : CALL get_atomic_kind(atomic_kind=particle_set(my_list(katom))%atomic_kind, &
761 15155 : element_symbol=element_symbol)
762 : WRITE (UNIT=iw, FMT=TRIM(fmt_string2)) &
763 15155 : iatom, element_symbol, &
764 30544 : (matrix(iatom, icol), icol=from, to)
765 : END DO
766 : END DO
767 :
768 52 : DEALLOCATE (my_list)
769 :
770 52 : END SUBROUTINE write_particle_matrix
771 :
772 : ! **************************************************************************************************
773 : !> \brief Write structure data requested by a separate structure data input
774 : !> section to the output unit.
775 : !> input_section can be either motion_section or subsys_section.
776 : !>
777 : !> \param particle_set ...
778 : !> \param cell ...
779 : !> \param input_section ...
780 : !> \date 11.03.04
781 : !> \par History
782 : !> Recovered (23.03.06,MK)
783 : !> \author MK
784 : !> \version 1.0
785 : ! **************************************************************************************************
786 66920 : SUBROUTINE write_structure_data(particle_set, cell, input_section)
787 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
788 : TYPE(cell_type), POINTER :: cell
789 : TYPE(section_vals_type), POINTER :: input_section
790 :
791 : CHARACTER(LEN=*), PARAMETER :: routineN = 'write_structure_data'
792 :
793 : CHARACTER(LEN=default_string_length) :: string, unit_str
794 : INTEGER :: handle, i, i_rep, iw, n, n_rep, n_vals, &
795 : natom, new_size, old_size, wrk2(2), &
796 : wrk3(3), wrk4(4)
797 66920 : INTEGER, ALLOCATABLE, DIMENSION(:) :: work
798 66920 : INTEGER, DIMENSION(:), POINTER :: atomic_indices, index_list
799 : LOGICAL :: unique
800 : REAL(KIND=dp) :: conv, dab
801 : REAL(KIND=dp), DIMENSION(3) :: r, rab, rbc, rcd, s
802 : TYPE(cp_logger_type), POINTER :: logger
803 : TYPE(section_vals_type), POINTER :: section
804 :
805 66920 : CALL timeset(routineN, handle)
806 66920 : NULLIFY (atomic_indices)
807 66920 : NULLIFY (index_list)
808 66920 : NULLIFY (logger)
809 66920 : NULLIFY (section)
810 66920 : string = ""
811 :
812 66920 : logger => cp_get_default_logger()
813 : iw = cp_print_key_unit_nr(logger=logger, &
814 : basis_section=input_section, &
815 : print_key_path="PRINT%STRUCTURE_DATA", &
816 66920 : extension=".coordLog")
817 :
818 66920 : CALL section_vals_val_get(input_section, "PRINT%STRUCTURE_DATA%UNIT", c_val=unit_str)
819 66920 : conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
820 66920 : CALL uppercase(unit_str)
821 66920 : IF (iw > 0) THEN
822 553 : natom = SIZE(particle_set)
823 : section => section_vals_get_subs_vals(section_vals=input_section, &
824 553 : subsection_name="PRINT%STRUCTURE_DATA")
825 :
826 553 : WRITE (UNIT=iw, FMT="(/,T2,A)") "REQUESTED STRUCTURE DATA"
827 : ! Print the requested atomic position vectors
828 : CALL section_vals_val_get(section_vals=section, &
829 : keyword_name="POSITION", &
830 553 : n_rep_val=n_rep)
831 553 : IF (n_rep > 0) THEN
832 : WRITE (UNIT=iw, FMT="(/,T3,A,/)") &
833 145 : "Position vectors r(i) of the atoms i in "//TRIM(unit_str)
834 145 : old_size = 0
835 848 : DO i_rep = 1, n_rep
836 : CALL section_vals_val_get(section_vals=section, &
837 : keyword_name="POSITION", &
838 : i_rep_val=i_rep, &
839 703 : i_vals=atomic_indices)
840 703 : n_vals = SIZE(atomic_indices)
841 703 : new_size = old_size + n_vals
842 703 : CALL reallocate(index_list, 1, new_size)
843 2903 : index_list(old_size + 1:new_size) = atomic_indices(1:n_vals)
844 848 : old_size = new_size
845 : END DO
846 435 : ALLOCATE (work(new_size))
847 145 : CALL sort(index_list, new_size, work)
848 145 : DEALLOCATE (work)
849 1245 : DO i = 1, new_size
850 1100 : WRITE (UNIT=string, FMT="(A,I0,A)") "(", index_list(i), ")"
851 1100 : IF ((index_list(i) < 1) .OR. (index_list(i) > natom)) THEN
852 : WRITE (UNIT=iw, FMT="(T3,A)") &
853 30 : "Invalid atomic index "//TRIM(string)//" specified. Print request is ignored."
854 30 : CYCLE
855 : END IF
856 1070 : IF (i > 1) THEN
857 : ! Skip redundant indices
858 935 : IF (index_list(i) == index_list(i - 1)) CYCLE
859 : END IF
860 : WRITE (UNIT=iw, FMT="(T3,A,T20,A,3F13.6)") &
861 4425 : "r"//TRIM(string), "=", pbc(particle_set(index_list(i))%r(1:3), cell)*conv
862 : END DO
863 145 : DEALLOCATE (index_list)
864 : END IF
865 :
866 : ! Print the requested atomic position vectors in scaled coordinates
867 : CALL section_vals_val_get(section_vals=section, &
868 : keyword_name="POSITION_SCALED", &
869 553 : n_rep_val=n_rep)
870 553 : IF (n_rep > 0) THEN
871 : WRITE (UNIT=iw, FMT="(/,T3,A,/)") &
872 27 : "Position vectors s(i) of the atoms i in scaled coordinates"
873 27 : old_size = 0
874 84 : DO i_rep = 1, n_rep
875 : CALL section_vals_val_get(section_vals=section, &
876 : keyword_name="POSITION_SCALED", &
877 : i_rep_val=i_rep, &
878 57 : i_vals=atomic_indices)
879 57 : n_vals = SIZE(atomic_indices)
880 57 : new_size = old_size + n_vals
881 57 : CALL reallocate(index_list, 1, new_size)
882 965 : index_list(old_size + 1:new_size) = atomic_indices(1:n_vals)
883 84 : old_size = new_size
884 : END DO
885 81 : ALLOCATE (work(new_size))
886 27 : CALL sort(index_list, new_size, work)
887 27 : DEALLOCATE (work)
888 481 : DO i = 1, new_size
889 454 : WRITE (UNIT=string, FMT="(A,I0,A)") "(", index_list(i), ")"
890 454 : IF ((index_list(i) < 1) .OR. (index_list(i) > natom)) THEN
891 : WRITE (UNIT=iw, FMT="(T3,A)") &
892 30 : "Invalid atomic index "//TRIM(string)//" specified. Print request is ignored."
893 30 : CYCLE
894 : END IF
895 424 : IF (i > 1) THEN
896 : ! Skip redundant indices
897 407 : IF (index_list(i) == index_list(i - 1)) CYCLE
898 : END IF
899 424 : r(1:3) = pbc(particle_set(index_list(i))%r(1:3), cell)
900 424 : CALL real_to_scaled(s, r, cell)
901 : WRITE (UNIT=iw, FMT="(T3,A,T20,A,3F13.6)") &
902 451 : "s"//TRIM(string), "=", s(1:3)
903 : END DO
904 27 : DEALLOCATE (index_list)
905 : END IF
906 :
907 : ! Print the requested distances
908 : CALL section_vals_val_get(section_vals=section, &
909 : keyword_name="DISTANCE", &
910 553 : n_rep_val=n)
911 553 : IF (n > 0) THEN
912 : WRITE (UNIT=iw, FMT="(/,T3,A,/)") &
913 : "Distance vector r(i,j) between the atom i and j in "// &
914 128 : TRIM(unit_str)
915 353 : DO i = 1, n
916 : CALL section_vals_val_get(section_vals=section, &
917 : keyword_name="DISTANCE", &
918 : i_rep_val=i, &
919 225 : i_vals=atomic_indices)
920 225 : string = ""
921 : WRITE (UNIT=string, FMT="(A,2(I0,A))") &
922 225 : "(", atomic_indices(1), ",", atomic_indices(2), ")"
923 675 : wrk2 = atomic_indices
924 225 : CALL sort_unique(wrk2, unique)
925 353 : IF (((wrk2(1) >= 1) .AND. (wrk2(SIZE(wrk2)) <= natom)) .AND. unique) THEN
926 : rab(:) = pbc(particle_set(atomic_indices(1))%r(:), &
927 225 : particle_set(atomic_indices(2))%r(:), cell)
928 225 : dab = SQRT(rab(1)*rab(1) + rab(2)*rab(2) + rab(3)*rab(3))
929 : WRITE (UNIT=iw, FMT="(T3,A,T20,A,3F13.6,3X,A,F13.6)") &
930 900 : "r"//TRIM(string), "=", rab(:)*conv, &
931 450 : "|r| =", dab*conv
932 : ELSE
933 : WRITE (UNIT=iw, FMT="(T3,A)") &
934 0 : "Invalid atomic indices "//TRIM(string)//" specified. Print request is ignored."
935 : END IF
936 : END DO
937 : END IF
938 :
939 : ! Print the requested angles
940 : CALL section_vals_val_get(section_vals=section, &
941 : keyword_name="ANGLE", &
942 553 : n_rep_val=n)
943 553 : IF (n > 0) THEN
944 : WRITE (UNIT=iw, FMT="(/,T3,A,/)") &
945 : "Angle a(i,j,k) between the atomic distance vectors r(j,i) and "// &
946 67 : "r(j,k) in DEGREE"
947 139 : DO i = 1, n
948 : CALL section_vals_val_get(section_vals=section, &
949 : keyword_name="ANGLE", &
950 : i_rep_val=i, &
951 72 : i_vals=atomic_indices)
952 72 : string = ""
953 : WRITE (UNIT=string, FMT="(A,3(I0,A))") &
954 72 : "(", atomic_indices(1), ",", atomic_indices(2), ",", atomic_indices(3), ")"
955 288 : wrk3 = atomic_indices
956 72 : CALL sort_unique(wrk3, unique)
957 139 : IF (((wrk3(1) >= 1) .AND. (wrk3(SIZE(wrk3)) <= natom)) .AND. unique) THEN
958 : rab(:) = pbc(particle_set(atomic_indices(1))%r(:), &
959 67 : particle_set(atomic_indices(2))%r(:), cell)
960 : rbc(:) = pbc(particle_set(atomic_indices(2))%r(:), &
961 67 : particle_set(atomic_indices(3))%r(:), cell)
962 : WRITE (UNIT=iw, FMT="(T3,A,T26,A,F9.3)") &
963 268 : "a"//TRIM(string), "=", angle(-rab, rbc)*degree
964 : ELSE
965 : WRITE (UNIT=iw, FMT="(T3,A)") &
966 5 : "Invalid atomic indices "//TRIM(string)//" specified. Print request is ignored."
967 : END IF
968 : END DO
969 : END IF
970 :
971 : ! Print the requested dihedral angles
972 : CALL section_vals_val_get(section_vals=section, &
973 : keyword_name="DIHEDRAL_ANGLE", &
974 553 : n_rep_val=n)
975 553 : IF (n > 0) THEN
976 : WRITE (UNIT=iw, FMT="(/,T3,A,/)") &
977 : "Dihedral angle d(i,j,k,l) between the planes (i,j,k) and (j,k,l) "// &
978 5 : "in DEGREE"
979 15 : DO i = 1, n
980 : CALL section_vals_val_get(section_vals=section, &
981 : keyword_name="DIHEDRAL_ANGLE", &
982 : i_rep_val=i, &
983 10 : i_vals=atomic_indices)
984 10 : string = ""
985 : WRITE (UNIT=string, FMT="(A,4(I0,A))") &
986 10 : "(", atomic_indices(1), ",", atomic_indices(2), ",", &
987 20 : atomic_indices(3), ",", atomic_indices(4), ")"
988 50 : wrk4 = atomic_indices
989 10 : CALL sort_unique(wrk4, unique)
990 15 : IF (((wrk4(1) >= 1) .AND. (wrk4(SIZE(wrk4)) <= natom)) .AND. unique) THEN
991 : rab(:) = pbc(particle_set(atomic_indices(1))%r(:), &
992 0 : particle_set(atomic_indices(2))%r(:), cell)
993 : rbc(:) = pbc(particle_set(atomic_indices(2))%r(:), &
994 0 : particle_set(atomic_indices(3))%r(:), cell)
995 : rcd(:) = pbc(particle_set(atomic_indices(3))%r(:), &
996 0 : particle_set(atomic_indices(4))%r(:), cell)
997 : WRITE (UNIT=iw, FMT="(T3,A,T26,A,F9.3)") &
998 0 : "d"//TRIM(string), "=", dihedral_angle(rab, rbc, rcd)*degree
999 : ELSE
1000 : WRITE (UNIT=iw, FMT="(T3,A)") &
1001 10 : "Invalid atomic indices "//TRIM(string)//" specified. Print request is ignored."
1002 : END IF
1003 : END DO
1004 : END IF
1005 : END IF
1006 : CALL cp_print_key_finished_output(iw, logger, input_section, &
1007 66920 : "PRINT%STRUCTURE_DATA")
1008 :
1009 66920 : CALL timestop(handle)
1010 :
1011 66920 : END SUBROUTINE write_structure_data
1012 :
1013 0 : END MODULE particle_methods
|