LCOV - code coverage report
Current view: top level - src - force_env_utils.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:b279b6b) Lines: 166 194 85.6 %
Date: 2024-04-24 07:13:09 Functions: 5 5 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 Util force_env module
      10             : !> \author Teodoro Laino [tlaino] - 02.2011
      11             : ! **************************************************************************************************
      12             : MODULE force_env_utils
      13             : 
      14             :    USE atomic_kind_list_types,          ONLY: atomic_kind_list_type
      15             :    USE cell_types,                      ONLY: cell_type
      16             :    USE constraint,                      ONLY: rattle_control,&
      17             :                                               shake_control
      18             :    USE constraint_util,                 ONLY: getold
      19             :    USE cp_subsys_types,                 ONLY: cp_subsys_get,&
      20             :                                               cp_subsys_type
      21             :    USE distribution_1d_types,           ONLY: distribution_1d_type
      22             :    USE force_env_types,                 ONLY: force_env_get,&
      23             :                                               force_env_type
      24             :    USE input_section_types,             ONLY: section_vals_get,&
      25             :                                               section_vals_get_subs_vals,&
      26             :                                               section_vals_type,&
      27             :                                               section_vals_val_get
      28             :    USE kinds,                           ONLY: dp
      29             :    USE molecule_kind_list_types,        ONLY: molecule_kind_list_type
      30             :    USE molecule_list_types,             ONLY: molecule_list_type
      31             :    USE molecule_types,                  ONLY: global_constraint_type
      32             :    USE particle_list_types,             ONLY: particle_list_type
      33             :    USE particle_types,                  ONLY: update_particle_set
      34             :    USE physcon,                         ONLY: angstrom
      35             : #include "./base/base_uses.f90"
      36             : 
      37             :    IMPLICIT NONE
      38             : 
      39             :    PRIVATE
      40             : 
      41             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'force_env_utils'
      42             : 
      43             :    PUBLIC :: force_env_shake, &
      44             :              force_env_rattle, &
      45             :              rescale_forces, &
      46             :              write_atener, &
      47             :              write_forces
      48             : 
      49             : CONTAINS
      50             : 
      51             : ! **************************************************************************************************
      52             : !> \brief perform shake (enforcing of constraints)
      53             : !> \param force_env the force env to shake
      54             : !> \param dt the dt for shake (if you are not interested in the velocities
      55             : !>        it can be any positive number)
      56             : !> \param shake_tol the tolerance for shake
      57             : !> \param log_unit if >0 then some information on the shake is printed,
      58             : !>        defaults to -1
      59             : !> \param lagrange_mult ...
      60             : !> \param dump_lm ...
      61             : !> \param pos ...
      62             : !> \param vel ...
      63             : !> \param compold ...
      64             : !> \param reset ...
      65             : !> \author fawzi
      66             : ! **************************************************************************************************
      67          48 :    SUBROUTINE force_env_shake(force_env, dt, shake_tol, log_unit, lagrange_mult, dump_lm, &
      68          24 :                               pos, vel, compold, reset)
      69             : 
      70             :       TYPE(force_env_type), POINTER                      :: force_env
      71             :       REAL(kind=dp), INTENT(IN), OPTIONAL                :: dt
      72             :       REAL(kind=dp), INTENT(IN)                          :: shake_tol
      73             :       INTEGER, INTENT(in), OPTIONAL                      :: log_unit, lagrange_mult
      74             :       LOGICAL, INTENT(IN), OPTIONAL                      :: dump_lm
      75             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT), &
      76             :          OPTIONAL, TARGET                                :: pos, vel
      77             :       LOGICAL, INTENT(IN), OPTIONAL                      :: compold, reset
      78             : 
      79             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'force_env_shake'
      80             : 
      81             :       INTEGER :: handle, i, iparticle, iparticle_kind, iparticle_local, j, my_lagrange_mult, &
      82             :          my_log_unit, nparticle_kind, nparticle_local
      83             :       LOGICAL                                            :: has_pos, has_vel, my_dump_lm
      84             :       REAL(KIND=dp)                                      :: mydt
      85          24 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: my_pos, my_vel
      86             :       TYPE(atomic_kind_list_type), POINTER               :: atomic_kinds
      87             :       TYPE(cell_type), POINTER                           :: cell
      88             :       TYPE(cp_subsys_type), POINTER                      :: subsys
      89             :       TYPE(distribution_1d_type), POINTER                :: local_molecules, local_particles
      90             :       TYPE(global_constraint_type), POINTER              :: gci
      91             :       TYPE(molecule_kind_list_type), POINTER             :: molecule_kinds
      92             :       TYPE(molecule_list_type), POINTER                  :: molecules
      93             :       TYPE(particle_list_type), POINTER                  :: particles
      94             : 
      95          24 :       CALL timeset(routineN, handle)
      96          24 :       CPASSERT(ASSOCIATED(force_env))
      97          24 :       CPASSERT(force_env%ref_count > 0)
      98          24 :       my_log_unit = -1
      99          24 :       IF (PRESENT(log_unit)) my_log_unit = log_unit
     100          24 :       my_lagrange_mult = -1
     101          24 :       IF (PRESENT(lagrange_mult)) my_lagrange_mult = lagrange_mult
     102          24 :       my_dump_lm = .FALSE.
     103          24 :       IF (PRESENT(dump_lm)) my_dump_lm = dump_lm
     104          24 :       NULLIFY (subsys, cell, molecules, molecule_kinds, local_molecules, particles, &
     105          24 :                my_pos, my_vel, gci)
     106          24 :       IF (PRESENT(pos)) my_pos => pos
     107          24 :       IF (PRESENT(vel)) my_vel => vel
     108          24 :       mydt = 0.1_dp
     109          24 :       IF (PRESENT(dt)) mydt = dt
     110          24 :       CALL force_env_get(force_env, subsys=subsys, cell=cell)
     111             :       CALL cp_subsys_get(subsys, &
     112             :                          atomic_kinds=atomic_kinds, &
     113             :                          local_molecules=local_molecules, &
     114             :                          local_particles=local_particles, &
     115             :                          molecules=molecules, &
     116             :                          molecule_kinds=molecule_kinds, &
     117             :                          particles=particles, &
     118          24 :                          gci=gci)
     119          24 :       nparticle_kind = atomic_kinds%n_els
     120          24 :       IF (PRESENT(compold)) THEN
     121          24 :          IF (compold) THEN
     122             :             CALL getold(gci, local_molecules, molecules%els, molecule_kinds%els, &
     123          24 :                         particles%els, cell)
     124             :          END IF
     125             :       END IF
     126          24 :       has_pos = .FALSE.
     127          24 :       IF (.NOT. ASSOCIATED(my_pos)) THEN
     128          24 :          has_pos = .TRUE.
     129          72 :          ALLOCATE (my_pos(3, particles%n_els))
     130        7504 :          my_pos = 0.0_dp
     131         112 :          DO iparticle_kind = 1, nparticle_kind
     132          88 :             nparticle_local = local_particles%n_el(iparticle_kind)
     133        1047 :             DO iparticle_local = 1, nparticle_local
     134         935 :                iparticle = local_particles%list(iparticle_kind)%array(iparticle_local)
     135        3828 :                my_pos(:, iparticle) = particles%els(iparticle)%r(:)
     136             :             END DO
     137             :          END DO
     138             :       END IF
     139          24 :       has_vel = .FALSE.
     140          24 :       IF (.NOT. ASSOCIATED(my_vel)) THEN
     141          24 :          has_vel = .TRUE.
     142          72 :          ALLOCATE (my_vel(3, particles%n_els))
     143        7504 :          my_vel = 0.0_dp
     144         112 :          DO iparticle_kind = 1, nparticle_kind
     145          88 :             nparticle_local = local_particles%n_el(iparticle_kind)
     146        1047 :             DO iparticle_local = 1, nparticle_local
     147         935 :                iparticle = local_particles%list(iparticle_kind)%array(iparticle_local)
     148        3828 :                my_vel(:, iparticle) = particles%els(iparticle)%v(:)
     149             :             END DO
     150             :          END DO
     151             :       END IF
     152             : 
     153             :       CALL shake_control(gci=gci, local_molecules=local_molecules, &
     154             :                          molecule_set=molecules%els, molecule_kind_set=molecule_kinds%els, &
     155             :                          particle_set=particles%els, pos=my_pos, vel=my_vel, dt=mydt, &
     156             :                          shake_tol=shake_tol, log_unit=my_log_unit, lagrange_mult=my_lagrange_mult, &
     157             :                          dump_lm=my_dump_lm, cell=cell, group=force_env%para_env, &
     158          24 :                          local_particles=local_particles)
     159             : 
     160             :       ! Possibly reset the lagrange multipliers
     161          24 :       IF (PRESENT(reset)) THEN
     162           0 :          IF (reset) THEN
     163             :             ! Reset Intramolecular constraints
     164           0 :             DO i = 1, SIZE(molecules%els)
     165           0 :                IF (ASSOCIATED(molecules%els(i)%lci%lcolv)) THEN
     166           0 :                   DO j = 1, SIZE(molecules%els(i)%lci%lcolv)
     167             :                      ! Reset langrange multiplier
     168           0 :                      molecules%els(i)%lci%lcolv(j)%lambda = 0.0_dp
     169             :                   END DO
     170             :                END IF
     171           0 :                IF (ASSOCIATED(molecules%els(i)%lci%lg3x3)) THEN
     172           0 :                   DO j = 1, SIZE(molecules%els(i)%lci%lg3x3)
     173             :                      ! Reset langrange multiplier
     174           0 :                      molecules%els(i)%lci%lg3x3(j)%lambda = 0.0_dp
     175             :                   END DO
     176             :                END IF
     177           0 :                IF (ASSOCIATED(molecules%els(i)%lci%lg4x6)) THEN
     178           0 :                   DO j = 1, SIZE(molecules%els(i)%lci%lg4x6)
     179             :                      ! Reset langrange multiplier
     180           0 :                      molecules%els(i)%lci%lg4x6(j)%lambda = 0.0_dp
     181             :                   END DO
     182             :                END IF
     183             :             END DO
     184             :             ! Reset Intermolecular constraints
     185           0 :             IF (ASSOCIATED(gci)) THEN
     186           0 :                IF (ASSOCIATED(gci%lcolv)) THEN
     187           0 :                   DO j = 1, SIZE(gci%lcolv)
     188             :                      ! Reset langrange multiplier
     189           0 :                      gci%lcolv(j)%lambda = 0.0_dp
     190             :                   END DO
     191             :                END IF
     192           0 :                IF (ASSOCIATED(gci%lg3x3)) THEN
     193           0 :                   DO j = 1, SIZE(gci%lg3x3)
     194             :                      ! Reset langrange multiplier
     195           0 :                      gci%lg3x3(j)%lambda = 0.0_dp
     196             :                   END DO
     197             :                END IF
     198           0 :                IF (ASSOCIATED(gci%lg4x6)) THEN
     199           0 :                   DO j = 1, SIZE(gci%lg4x6)
     200             :                      ! Reset langrange multiplier
     201           0 :                      gci%lg4x6(j)%lambda = 0.0_dp
     202             :                   END DO
     203             :                END IF
     204             :             END IF
     205             :          END IF
     206             :       END IF
     207             : 
     208          24 :       IF (has_pos) THEN
     209          24 :          CALL update_particle_set(particles%els, force_env%para_env, pos=my_pos)
     210          24 :          DEALLOCATE (my_pos)
     211             :       END IF
     212          24 :       IF (has_vel) THEN
     213          24 :          CALL update_particle_set(particles%els, force_env%para_env, vel=my_vel)
     214          24 :          DEALLOCATE (my_vel)
     215             :       END IF
     216          24 :       CALL timestop(handle)
     217          24 :    END SUBROUTINE force_env_shake
     218             : 
     219             : ! **************************************************************************************************
     220             : !> \brief perform rattle (enforcing of constraints on velocities)
     221             : !>      This routine can be easily adapted to performe rattle on whatever
     222             : !>      other vector different from forces..
     223             : !> \param force_env the force env to shake
     224             : !> \param dt the dt for shake (if you are not interested in the velocities
     225             : !>        it can be any positive number)
     226             : !> \param shake_tol the tolerance for shake
     227             : !> \param log_unit if >0 then some information on the shake is printed,
     228             : !>        defaults to -1
     229             : !> \param lagrange_mult ...
     230             : !> \param dump_lm ...
     231             : !> \param vel ...
     232             : !> \param reset ...
     233             : !> \author tlaino
     234             : ! **************************************************************************************************
     235          48 :    SUBROUTINE force_env_rattle(force_env, dt, shake_tol, log_unit, lagrange_mult, dump_lm, &
     236          24 :                                vel, reset)
     237             : 
     238             :       TYPE(force_env_type), POINTER                      :: force_env
     239             :       REAL(kind=dp), INTENT(in), OPTIONAL                :: dt
     240             :       REAL(kind=dp), INTENT(in)                          :: shake_tol
     241             :       INTEGER, INTENT(in), OPTIONAL                      :: log_unit, lagrange_mult
     242             :       LOGICAL, INTENT(IN), OPTIONAL                      :: dump_lm
     243             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT), &
     244             :          OPTIONAL, TARGET                                :: vel
     245             :       LOGICAL, INTENT(IN), OPTIONAL                      :: reset
     246             : 
     247             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'force_env_rattle'
     248             : 
     249             :       INTEGER :: handle, i, iparticle, iparticle_kind, iparticle_local, j, my_lagrange_mult, &
     250             :          my_log_unit, nparticle_kind, nparticle_local
     251             :       LOGICAL                                            :: has_vel, my_dump_lm
     252             :       REAL(KIND=dp)                                      :: mydt
     253          24 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: my_vel
     254             :       TYPE(atomic_kind_list_type), POINTER               :: atomic_kinds
     255             :       TYPE(cell_type), POINTER                           :: cell
     256             :       TYPE(cp_subsys_type), POINTER                      :: subsys
     257             :       TYPE(distribution_1d_type), POINTER                :: local_molecules, local_particles
     258             :       TYPE(global_constraint_type), POINTER              :: gci
     259             :       TYPE(molecule_kind_list_type), POINTER             :: molecule_kinds
     260             :       TYPE(molecule_list_type), POINTER                  :: molecules
     261             :       TYPE(particle_list_type), POINTER                  :: particles
     262             : 
     263          24 :       CALL timeset(routineN, handle)
     264          24 :       CPASSERT(ASSOCIATED(force_env))
     265          24 :       CPASSERT(force_env%ref_count > 0)
     266          24 :       my_log_unit = -1
     267          24 :       IF (PRESENT(log_unit)) my_log_unit = log_unit
     268          24 :       my_lagrange_mult = -1
     269          24 :       IF (PRESENT(lagrange_mult)) my_lagrange_mult = lagrange_mult
     270          24 :       my_dump_lm = .FALSE.
     271          24 :       IF (PRESENT(dump_lm)) my_dump_lm = dump_lm
     272          24 :       NULLIFY (subsys, cell, molecules, molecule_kinds, local_molecules, particles, &
     273          24 :                my_vel)
     274          24 :       IF (PRESENT(vel)) my_vel => vel
     275          24 :       mydt = 0.1_dp
     276          24 :       IF (PRESENT(dt)) mydt = dt
     277          24 :       CALL force_env_get(force_env, subsys=subsys, cell=cell)
     278             :       CALL cp_subsys_get(subsys, &
     279             :                          atomic_kinds=atomic_kinds, &
     280             :                          local_molecules=local_molecules, &
     281             :                          local_particles=local_particles, &
     282             :                          molecules=molecules, &
     283             :                          molecule_kinds=molecule_kinds, &
     284             :                          particles=particles, &
     285          24 :                          gci=gci)
     286          24 :       nparticle_kind = atomic_kinds%n_els
     287          24 :       has_vel = .FALSE.
     288          24 :       IF (.NOT. ASSOCIATED(my_vel)) THEN
     289          24 :          has_vel = .TRUE.
     290          72 :          ALLOCATE (my_vel(3, particles%n_els))
     291        7504 :          my_vel = 0.0_dp
     292         112 :          DO iparticle_kind = 1, nparticle_kind
     293          88 :             nparticle_local = local_particles%n_el(iparticle_kind)
     294        1047 :             DO iparticle_local = 1, nparticle_local
     295         935 :                iparticle = local_particles%list(iparticle_kind)%array(iparticle_local)
     296        3828 :                my_vel(:, iparticle) = particles%els(iparticle)%v(:)
     297             :             END DO
     298             :          END DO
     299             :       END IF
     300             : 
     301             :       CALL rattle_control(gci=gci, local_molecules=local_molecules, &
     302             :                           molecule_set=molecules%els, molecule_kind_set=molecule_kinds%els, &
     303             :                           particle_set=particles%els, vel=my_vel, dt=mydt, &
     304             :                           rattle_tol=shake_tol, log_unit=my_log_unit, lagrange_mult=my_lagrange_mult, &
     305             :                           dump_lm=my_dump_lm, cell=cell, group=force_env%para_env, &
     306          24 :                           local_particles=local_particles)
     307             : 
     308             :       ! Possibly reset the lagrange multipliers
     309          24 :       IF (PRESENT(reset)) THEN
     310          24 :          IF (reset) THEN
     311             :             ! Reset Intramolecular constraints
     312         500 :             DO i = 1, SIZE(molecules%els)
     313         476 :                IF (ASSOCIATED(molecules%els(i)%lci%lcolv)) THEN
     314          28 :                   DO j = 1, SIZE(molecules%els(i)%lci%lcolv)
     315             :                      ! Reset langrange multiplier
     316          28 :                      molecules%els(i)%lci%lcolv(j)%lambda = 0.0_dp
     317             :                   END DO
     318             :                END IF
     319         476 :                IF (ASSOCIATED(molecules%els(i)%lci%lg3x3)) THEN
     320         890 :                   DO j = 1, SIZE(molecules%els(i)%lci%lg3x3)
     321             :                      ! Reset langrange multiplier
     322        2216 :                      molecules%els(i)%lci%lg3x3(j)%lambda = 0.0_dp
     323             :                   END DO
     324             :                END IF
     325         500 :                IF (ASSOCIATED(molecules%els(i)%lci%lg4x6)) THEN
     326          12 :                   DO j = 1, SIZE(molecules%els(i)%lci%lg4x6)
     327             :                      ! Reset langrange multiplier
     328          36 :                      molecules%els(i)%lci%lg4x6(j)%lambda = 0.0_dp
     329             :                   END DO
     330             :                END IF
     331             :             END DO
     332             :             ! Reset Intermolecular constraints
     333          24 :             IF (ASSOCIATED(gci)) THEN
     334          24 :                IF (ASSOCIATED(gci%lcolv)) THEN
     335           0 :                   DO j = 1, SIZE(gci%lcolv)
     336             :                      ! Reset langrange multiplier
     337           0 :                      gci%lcolv(j)%lambda = 0.0_dp
     338             :                   END DO
     339             :                END IF
     340          24 :                IF (ASSOCIATED(gci%lg3x3)) THEN
     341           0 :                   DO j = 1, SIZE(gci%lg3x3)
     342             :                      ! Reset langrange multiplier
     343           0 :                      gci%lg3x3(j)%lambda = 0.0_dp
     344             :                   END DO
     345             :                END IF
     346          24 :                IF (ASSOCIATED(gci%lg4x6)) THEN
     347           0 :                   DO j = 1, SIZE(gci%lg4x6)
     348             :                      ! Reset langrange multiplier
     349           0 :                      gci%lg4x6(j)%lambda = 0.0_dp
     350             :                   END DO
     351             :                END IF
     352             :             END IF
     353             :          END IF
     354             :       END IF
     355             : 
     356          24 :       IF (has_vel) THEN
     357          24 :          CALL update_particle_set(particles%els, force_env%para_env, vel=my_vel)
     358             :       END IF
     359          24 :       DEALLOCATE (my_vel)
     360          24 :       CALL timestop(handle)
     361          24 :    END SUBROUTINE force_env_rattle
     362             : 
     363             : ! **************************************************************************************************
     364             : !> \brief Rescale forces if requested
     365             : !> \param force_env the force env to shake
     366             : !> \author tlaino
     367             : ! **************************************************************************************************
     368      198632 :    SUBROUTINE rescale_forces(force_env)
     369             :       TYPE(force_env_type), POINTER                      :: force_env
     370             : 
     371             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'rescale_forces'
     372             : 
     373             :       INTEGER                                            :: handle, iparticle
     374             :       LOGICAL                                            :: explicit
     375             :       REAL(KIND=dp)                                      :: force(3), max_value, mod_force
     376             :       TYPE(cp_subsys_type), POINTER                      :: subsys
     377             :       TYPE(particle_list_type), POINTER                  :: particles
     378             :       TYPE(section_vals_type), POINTER                   :: rescale_force_section
     379             : 
     380       99316 :       CALL timeset(routineN, handle)
     381       99316 :       CPASSERT(ASSOCIATED(force_env))
     382       99316 :       CPASSERT(force_env%ref_count > 0)
     383       99316 :       rescale_force_section => section_vals_get_subs_vals(force_env%force_env_section, "RESCALE_FORCES")
     384       99316 :       CALL section_vals_get(rescale_force_section, explicit=explicit)
     385       99316 :       IF (explicit) THEN
     386         224 :          CALL section_vals_val_get(rescale_force_section, "MAX_FORCE", r_val=max_value)
     387         224 :          CALL force_env_get(force_env, subsys=subsys)
     388         224 :          CALL cp_subsys_get(subsys, particles=particles)
     389       36262 :          DO iparticle = 1, SIZE(particles%els)
     390      144152 :             force = particles%els(iparticle)%f(:)
     391      144152 :             mod_force = SQRT(DOT_PRODUCT(force, force))
     392       36262 :             IF ((mod_force > max_value) .AND. (mod_force /= 0.0_dp)) THEN
     393       10208 :                force = force/mod_force*max_value
     394       10208 :                particles%els(iparticle)%f(:) = force
     395             :             END IF
     396             :          END DO
     397             :       END IF
     398       99316 :       CALL timestop(handle)
     399       99316 :    END SUBROUTINE rescale_forces
     400             : 
     401             : ! **************************************************************************************************
     402             : !> \brief Write forces
     403             : !>
     404             : !> \param particles ...
     405             : !> \param iw ...
     406             : !> \param label ...
     407             : !> \param ndigits ...
     408             : !> \param total_force ...
     409             : !> \param grand_total_force ...
     410             : !> \param zero_force_core_shell_atom ...
     411             : !> \author MK (06.09.2010)
     412             : ! **************************************************************************************************
     413        1811 :    SUBROUTINE write_forces(particles, iw, label, ndigits, total_force, &
     414             :                            grand_total_force, zero_force_core_shell_atom)
     415             : 
     416             :       TYPE(particle_list_type), POINTER                  :: particles
     417             :       INTEGER, INTENT(IN)                                :: iw
     418             :       CHARACTER(LEN=*), INTENT(IN)                       :: label
     419             :       INTEGER, INTENT(IN)                                :: ndigits
     420             :       REAL(KIND=dp), DIMENSION(3), INTENT(OUT)           :: total_force
     421             :       REAL(KIND=dp), DIMENSION(3), INTENT(INOUT), &
     422             :          OPTIONAL                                        :: grand_total_force
     423             :       LOGICAL, INTENT(IN), OPTIONAL                      :: zero_force_core_shell_atom
     424             : 
     425             :       CHARACTER(LEN=23)                                  :: fmtstr3
     426             :       CHARACTER(LEN=36)                                  :: fmtstr2
     427             :       CHARACTER(LEN=46)                                  :: fmtstr1
     428             :       INTEGER                                            :: i, ikind, iparticle, n
     429             :       LOGICAL                                            :: zero_force
     430             :       REAL(KIND=dp), DIMENSION(3)                        :: f
     431             : 
     432        1811 :       IF (iw > 0) THEN
     433        1811 :          CPASSERT(ASSOCIATED(particles))
     434        1811 :          n = MIN(MAX(1, ndigits), 20)
     435        1811 :          fmtstr1 = "(/,T2,A,/,/,T2,A,T11,A,T18,A,T35,A1,2(  X,A1))"
     436        1811 :          WRITE (UNIT=fmtstr1(39:40), FMT="(I2)") n + 6
     437        1811 :          fmtstr2 = "(T2,I6,1X,I6,T21,A,T28,3(1X,F  .  ))"
     438        1811 :          WRITE (UNIT=fmtstr2(33:34), FMT="(I2)") n
     439        1811 :          WRITE (UNIT=fmtstr2(30:31), FMT="(I2)") n + 6
     440        1811 :          fmtstr3 = "(T2,A,T28,4(1X,F  .  ))"
     441        1811 :          WRITE (UNIT=fmtstr3(20:21), FMT="(I2)") n
     442        1811 :          WRITE (UNIT=fmtstr3(17:18), FMT="(I2)") n + 6
     443        1811 :          IF (PRESENT(zero_force_core_shell_atom)) THEN
     444         501 :             zero_force = zero_force_core_shell_atom
     445             :          ELSE
     446             :             zero_force = .FALSE.
     447             :          END IF
     448             :          WRITE (UNIT=iw, FMT=fmtstr1) &
     449        1811 :             label//" FORCES in [a.u.]", "# Atom", "Kind", "Element", "X", "Y", "Z"
     450        1811 :          total_force(1:3) = 0.0_dp
     451      188307 :          DO iparticle = 1, particles%n_els
     452      186496 :             ikind = particles%els(iparticle)%atomic_kind%kind_number
     453      186496 :             IF (particles%els(iparticle)%atom_index /= 0) THEN
     454      186496 :                i = particles%els(iparticle)%atom_index
     455             :             ELSE
     456           0 :                i = iparticle
     457             :             END IF
     458      186496 :             IF (zero_force .AND. (particles%els(iparticle)%shell_index /= 0)) THEN
     459       49176 :                f(1:3) = 0.0_dp
     460             :             ELSE
     461      549280 :                f(1:3) = particles%els(iparticle)%f(1:3)
     462             :             END IF
     463             :             WRITE (UNIT=iw, FMT=fmtstr2) &
     464      186496 :                i, ikind, particles%els(iparticle)%atomic_kind%element_symbol, f(1:3)
     465      747795 :             total_force(1:3) = total_force(1:3) + f(1:3)
     466             :          END DO
     467             :          WRITE (UNIT=iw, FMT=fmtstr3) &
     468        9055 :             "SUM OF "//label//" FORCES", total_force(1:3), SQRT(SUM(total_force(:)**2))
     469             :       END IF
     470             : 
     471        1811 :       IF (PRESENT(grand_total_force)) THEN
     472         668 :          grand_total_force(1:3) = grand_total_force(1:3) + total_force(1:3)
     473         167 :          WRITE (UNIT=iw, FMT="(A)") ""
     474             :          WRITE (UNIT=iw, FMT=fmtstr3) &
     475         835 :             "GRAND TOTAL FORCE", grand_total_force(1:3), SQRT(SUM(grand_total_force(:)**2))
     476             :       END IF
     477             : 
     478        1811 :    END SUBROUTINE write_forces
     479             : 
     480             : ! **************************************************************************************************
     481             : !> \brief Write the atomic coordinates, types, and energies
     482             : !> \param iounit ...
     483             : !> \param particles ...
     484             : !> \param atener ...
     485             : !> \param label ...
     486             : !> \date    05.06.2023
     487             : !> \author  JGH
     488             : !> \version 1.0
     489             : ! **************************************************************************************************
     490         489 :    SUBROUTINE write_atener(iounit, particles, atener, label)
     491             : 
     492             :       INTEGER, INTENT(IN)                                :: iounit
     493             :       TYPE(particle_list_type), POINTER                  :: particles
     494             :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: atener
     495             :       CHARACTER(LEN=*), INTENT(IN)                       :: label
     496             : 
     497             :       INTEGER                                            :: i, natom
     498             : 
     499         489 :       IF (iounit > 0) THEN
     500         489 :          WRITE (UNIT=iounit, FMT="(/,T2,A)") TRIM(label)
     501             :          WRITE (UNIT=iounit, FMT="(T4,A,T30,A,T42,A,T54,A,T69,A)") &
     502         489 :             "Atom  Element", "X", "Y", "Z", "Energy[a.u.]"
     503         489 :          natom = particles%n_els
     504       17788 :          DO i = 1, natom
     505       17299 :             WRITE (iounit, "(I6,T12,A2,T24,3F12.6,F21.10)") i, &
     506       17299 :                TRIM(ADJUSTL(particles%els(i)%atomic_kind%element_symbol)), &
     507       86984 :                particles%els(i)%r(1:3)*angstrom, atener(i)
     508             :          END DO
     509         489 :          WRITE (iounit, "(A)") ""
     510             :       END IF
     511             : 
     512         489 :    END SUBROUTINE write_atener
     513             : 
     514             : END MODULE force_env_utils

Generated by: LCOV version 1.15