LCOV - code coverage report
Current view: top level - src - particle_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 89.0 % 410 365
Test Date: 2025-12-04 06:27:48 Functions: 100.0 % 7 7

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

Generated by: LCOV version 2.0-1