LCOV - code coverage report
Current view: top level - src - particle_methods.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:34ef472) Lines: 365 410 89.0 %
Date: 2024-04-26 08:30:29 Functions: 7 7 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 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      164828 :    SUBROUTINE get_particle_set(particle_set, qs_kind_set, first_sgf, last_sgf, nsgf, &
      97      164828 :                                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      164828 :       CPASSERT(ASSOCIATED(particle_set))
     107             : 
     108      164828 :       nparticle = SIZE(particle_set)
     109      164828 :       IF (PRESENT(first_sgf)) THEN
     110       39468 :          CPASSERT(SIZE(first_sgf) >= nparticle)
     111             :       END IF
     112      164828 :       IF (PRESENT(last_sgf)) THEN
     113       33508 :          CPASSERT(SIZE(last_sgf) >= nparticle)
     114             :       END IF
     115      164828 :       IF (PRESENT(nsgf)) THEN
     116      124930 :          CPASSERT(SIZE(nsgf) >= nparticle)
     117             :       END IF
     118      164828 :       IF (PRESENT(nmao)) THEN
     119          14 :          CPASSERT(SIZE(nmao) >= nparticle)
     120             :       END IF
     121             : 
     122      164828 :       IF (PRESENT(first_sgf) .OR. PRESENT(last_sgf) .OR. PRESENT(nsgf)) THEN
     123             :          isgf = 0
     124      963787 :          DO iparticle = 1, nparticle
     125      799429 :             CALL get_atomic_kind(particle_set(iparticle)%atomic_kind, kind_number=ikind)
     126      799429 :             IF (PRESENT(basis)) THEN
     127      592069 :                IF (ASSOCIATED(basis(ikind)%gto_basis_set)) THEN
     128      592065 :                   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      207360 :                CALL get_qs_kind(qs_kind_set(ikind), nsgf=ns)
     134             :             END IF
     135      799429 :             IF (PRESENT(nsgf)) nsgf(iparticle) = ns
     136      799429 :             IF (PRESENT(first_sgf)) first_sgf(iparticle) = isgf + 1
     137      799429 :             isgf = isgf + ns
     138     1763686 :             IF (PRESENT(last_sgf)) last_sgf(iparticle) = isgf
     139             :          END DO
     140             :       END IF
     141             : 
     142      164828 :       IF (PRESENT(first_sgf)) THEN
     143       39468 :          IF (SIZE(first_sgf) > nparticle) first_sgf(nparticle + 1) = isgf + 1
     144             :       END IF
     145             : 
     146      164828 :       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      164828 :    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       26987 :    SUBROUTINE write_particle_coordinates(particle_set, iunit, output_format, &
     180       26987 :                                          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       26987 :       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       26987 :       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       26987 :       CALL timeset(routineN, handle)
     214             : 
     215       26987 :       natom = SIZE(particle_set)
     216       26987 :       IF (PRESENT(array)) THEN
     217        1773 :          SELECT CASE (TRIM(content))
     218             :          CASE ("POS_VEL", "POS_VEL_FORCE")
     219        1773 :             CPABORT("Illegal usage")
     220             :          END SELECT
     221             :       END IF
     222       26987 :       factor = 1.0_dp
     223       26987 :       IF (PRESENT(unit_conv)) THEN
     224       26836 :          factor = unit_conv
     225             :       END IF
     226       53901 :       SELECT CASE (output_format)
     227             :       CASE (dump_xmol)
     228       26914 :          my_print_kind = .FALSE.
     229       26914 :          IF (PRESENT(print_kind)) my_print_kind = print_kind
     230       26914 :          WRITE (iunit, "(I8)") natom
     231       26914 :          WRITE (iunit, "(A)") TRIM(title)
     232     1323030 :          DO iatom = 1, natom
     233             :             CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
     234     1296116 :                                  element_symbol=element_symbol)
     235     1296116 :             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     1296092 :                my_format = "(T2,A2,"
     243     1296092 :                atm_name = TRIM(element_symbol)
     244             :             END IF
     245       26914 :             SELECT CASE (TRIM(content))
     246             :             CASE ("POS")
     247     1181019 :                IF (PRESENT(array)) THEN
     248       48271 :                   r(1:3) = get_particle_pos_or_vel(iatom, particle_set, array)
     249             :                ELSE
     250     4530992 :                   r(:) = particle_set(iatom)%r(:)
     251             :                END IF
     252     4724076 :                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     1330552 :                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          12 :          ALLOCATE (y4(natom))
     354          12 :          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       27046 :          CPABORT("Illegal dump type")
     468             :       END SELECT
     469             : 
     470       26987 :       CALL timestop(handle)
     471             : 
     472       26987 :    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        9761 :    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        9761 :       NULLIFY (logger)
     495        9761 :       NULLIFY (shell_kind)
     496             : 
     497        9761 :       logger => cp_get_default_logger()
     498             :       iw = cp_print_key_unit_nr(logger, subsys_section, &
     499        9761 :                                 "PRINT%ATOMIC_COORDINATES", extension=".coordLog")
     500             : 
     501        9761 :       CALL section_vals_val_get(subsys_section, "PRINT%ATOMIC_COORDINATES%UNIT", c_val=unit_str)
     502        9761 :       conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
     503        9761 :       CALL uppercase(unit_str)
     504        9761 :       IF (iw > 0) THEN
     505             :          WRITE (UNIT=iw, FMT="(/,/,T2,A)") &
     506        2505 :             "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        2505 :             "Atom Kind Name", "X", "Y", "Z", "q(eff)", "Mass"
     509        2505 :          natom = SIZE(particle_set)
     510      362590 :          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      360085 :                                  shell=shell_kind)
     517      360085 :             IF (PRESENT(charges)) qeff = charges(iatom)
     518      360085 :             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     1802930 :                iatom, ikind, name, particle_set(iatom)%r(1:3)*conv, qeff, mass/massunit
     526             :          END DO
     527        2505 :          WRITE (iw, "(A)") ""
     528             :       END IF
     529             : 
     530             :       CALL cp_print_key_finished_output(iw, logger, subsys_section, &
     531        9761 :                                         "PRINT%ATOMIC_COORDINATES")
     532             : 
     533        9761 :    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       13326 :    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       13326 :       CALL timeset(routineN, handle)
     561             : 
     562       13326 :       NULLIFY (logger)
     563       13326 :       logger => cp_get_default_logger()
     564             :       iw = cp_print_key_unit_nr(logger, subsys_section, &
     565       13326 :                                 "PRINT%ATOMIC_COORDINATES", extension=".coordLog")
     566             : 
     567       13326 :       CALL section_vals_val_get(subsys_section, "PRINT%ATOMIC_COORDINATES%UNIT", c_val=unit_str)
     568       13326 :       conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
     569       13326 :       CALL uppercase(unit_str)
     570       13326 :       IF (iw > 0) THEN
     571             :          WRITE (UNIT=iw, FMT="(/,/,T2,A)") &
     572        3150 :             "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        3150 :             "Atom Kind Element", "X", "Y", "Z", "Z(eff)", "Mass"
     575        3150 :          natom = SIZE(particle_set)
     576       19762 :          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       16612 :                                  z=z)
     582       16612 :             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       69598 :                iatom, ikind, element_symbol, z, particle_set(iatom)%r(1:3)*conv, zeff, mass/massunit
     585             :          END DO
     586        3150 :          WRITE (iw, "(A)") ""
     587             :       END IF
     588             : 
     589             :       CALL cp_print_key_finished_output(iw, logger, subsys_section, &
     590       13326 :                                         "PRINT%ATOMIC_COORDINATES")
     591             : 
     592       13326 :       CALL timestop(handle)
     593             : 
     594       13326 :    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        9217 :    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        9217 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: distance_matrix
     619             :       REAL(KIND=dp), DIMENSION(3)                        :: rab
     620             :       TYPE(cp_logger_type), POINTER                      :: logger
     621             : 
     622        9217 :       CALL timeset(routineN, handle)
     623             : 
     624        9217 :       CPASSERT(ASSOCIATED(particle_set))
     625        9217 :       CPASSERT(ASSOCIATED(cell))
     626        9217 :       CPASSERT(ASSOCIATED(subsys_section))
     627             : 
     628        9217 :       NULLIFY (logger)
     629        9217 :       logger => cp_get_default_logger()
     630             :       iw = cp_print_key_unit_nr(logger, subsys_section, &
     631        9217 :                                 "PRINT%INTERATOMIC_DISTANCES", extension=".distLog")
     632             : 
     633        9217 :       CALL section_vals_val_get(subsys_section, "PRINT%INTERATOMIC_DISTANCES%UNIT", c_val=unit_str)
     634        9217 :       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        9217 :                                 r_val=dab_min, explicit=explicit)
     637             : 
     638        9217 :       dab_abort = 0.0_dp
     639        9217 :       dab_warn = 0.0_dp
     640        9217 :       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        9217 :       IF (explicit .OR. (iw > 0) .OR. (natom <= 2000)) THEN
     645        9175 :          IF (dab_min > 0.0_dp) THEN
     646        9171 :             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        9217 :       IF ((iw > 0) .OR. (dab_abort > 0.0_dp) .OR. (dab_warn > 0.0_dp)) THEN
     653        9171 :          CALL get_cell(cell=cell, periodic=periodic)
     654        9171 :          IF (iw > 0) THEN
     655         128 :             ALLOCATE (distance_matrix(natom, natom))
     656       72180 :             distance_matrix(:, :) = 0.0_dp
     657             :          END IF
     658      315890 :          DO iatom = 1, natom
     659   116776912 :             DO jatom = iatom + 1, natom
     660             :                rab(:) = pbc(particle_set(iatom)%r(:), &
     661   116461022 :                             particle_set(jatom)%r(:), cell)
     662   116461022 :                dab = SQRT(rab(1)*rab(1) + rab(2)*rab(2) + rab(3)*rab(3))*conv
     663   116461022 :                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   116461022 :                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         912 :                                TRIM(ADJUSTL(unit_str)))
     684             :                END IF
     685   116767741 :                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        9171 :          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        9171 :                                            "PRINT%INTERATOMIC_DISTANCES")
     700             :       END IF
     701             : 
     702        9217 :       CALL timestop(handle)
     703             : 
     704        9217 :    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       69297 :    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       69297 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: work
     797       69297 :       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       69297 :       CALL timeset(routineN, handle)
     805       69297 :       NULLIFY (atomic_indices)
     806       69297 :       NULLIFY (index_list)
     807       69297 :       NULLIFY (logger)
     808       69297 :       NULLIFY (section)
     809       69297 :       string = ""
     810             : 
     811       69297 :       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       69297 :                                 extension=".coordLog")
     816             : 
     817       69297 :       CALL section_vals_val_get(input_section, "PRINT%STRUCTURE_DATA%UNIT", c_val=unit_str)
     818       69297 :       conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
     819       69297 :       CALL uppercase(unit_str)
     820       69297 :       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       69297 :                                         "PRINT%STRUCTURE_DATA")
    1007             : 
    1008       69297 :       CALL timestop(handle)
    1009             : 
    1010       69297 :    END SUBROUTINE write_structure_data
    1011             : 
    1012           0 : END MODULE particle_methods

Generated by: LCOV version 1.15