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

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief 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_log_handling,                 ONLY: cp_logger_get_default_io_unit
      20              :    USE cp_subsys_types,                 ONLY: cp_subsys_get,&
      21              :                                               cp_subsys_type
      22              :    USE cp_units,                        ONLY: cp_unit_from_cp2k
      23              :    USE distribution_1d_types,           ONLY: distribution_1d_type
      24              :    USE force_env_types,                 ONLY: force_env_get,&
      25              :                                               force_env_type
      26              :    USE input_section_types,             ONLY: section_vals_get,&
      27              :                                               section_vals_get_subs_vals,&
      28              :                                               section_vals_type,&
      29              :                                               section_vals_val_get
      30              :    USE kinds,                           ONLY: default_string_length,&
      31              :                                               dp
      32              :    USE molecule_kind_list_types,        ONLY: molecule_kind_list_type
      33              :    USE molecule_list_types,             ONLY: molecule_list_type
      34              :    USE molecule_types,                  ONLY: global_constraint_type
      35              :    USE particle_list_types,             ONLY: particle_list_type
      36              :    USE particle_types,                  ONLY: update_particle_set
      37              :    USE physcon,                         ONLY: angstrom
      38              :    USE string_utilities,                ONLY: lowercase,&
      39              :                                               uppercase
      40              : #include "./base/base_uses.f90"
      41              : 
      42              :    IMPLICIT NONE
      43              : 
      44              :    PRIVATE
      45              : 
      46              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'force_env_utils'
      47              : 
      48              :    PUBLIC :: force_env_shake, &
      49              :              force_env_rattle, &
      50              :              rescale_forces, &
      51              :              write_atener, &
      52              :              write_forces
      53              : 
      54              : CONTAINS
      55              : 
      56              : ! **************************************************************************************************
      57              : !> \brief perform shake (enforcing of constraints)
      58              : !> \param force_env the force env to shake
      59              : !> \param dt the dt for shake (if you are not interested in the velocities
      60              : !>        it can be any positive number)
      61              : !> \param shake_tol the tolerance for shake
      62              : !> \param log_unit if >0 then some information on the shake is printed,
      63              : !>        defaults to -1
      64              : !> \param lagrange_mult ...
      65              : !> \param dump_lm ...
      66              : !> \param pos ...
      67              : !> \param vel ...
      68              : !> \param compold ...
      69              : !> \param reset ...
      70              : !> \author fawzi
      71              : ! **************************************************************************************************
      72           48 :    SUBROUTINE force_env_shake(force_env, dt, shake_tol, log_unit, lagrange_mult, dump_lm, &
      73           24 :                               pos, vel, compold, reset)
      74              : 
      75              :       TYPE(force_env_type), POINTER                      :: force_env
      76              :       REAL(kind=dp), INTENT(IN), OPTIONAL                :: dt
      77              :       REAL(kind=dp), INTENT(IN)                          :: shake_tol
      78              :       INTEGER, INTENT(in), OPTIONAL                      :: log_unit, lagrange_mult
      79              :       LOGICAL, INTENT(IN), OPTIONAL                      :: dump_lm
      80              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT), &
      81              :          OPTIONAL, TARGET                                :: pos, vel
      82              :       LOGICAL, INTENT(IN), OPTIONAL                      :: compold, reset
      83              : 
      84              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'force_env_shake'
      85              : 
      86              :       INTEGER :: handle, i, iparticle, iparticle_kind, iparticle_local, j, my_lagrange_mult, &
      87              :          my_log_unit, nparticle_kind, nparticle_local
      88              :       LOGICAL                                            :: has_pos, has_vel, my_dump_lm
      89              :       REAL(KIND=dp)                                      :: mydt
      90           24 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: my_pos, my_vel
      91              :       TYPE(atomic_kind_list_type), POINTER               :: atomic_kinds
      92              :       TYPE(cell_type), POINTER                           :: cell
      93              :       TYPE(cp_subsys_type), POINTER                      :: subsys
      94              :       TYPE(distribution_1d_type), POINTER                :: local_molecules, local_particles
      95              :       TYPE(global_constraint_type), POINTER              :: gci
      96              :       TYPE(molecule_kind_list_type), POINTER             :: molecule_kinds
      97              :       TYPE(molecule_list_type), POINTER                  :: molecules
      98              :       TYPE(particle_list_type), POINTER                  :: particles
      99              : 
     100           24 :       CALL timeset(routineN, handle)
     101           24 :       CPASSERT(ASSOCIATED(force_env))
     102           24 :       CPASSERT(force_env%ref_count > 0)
     103           24 :       my_log_unit = -1
     104           24 :       IF (PRESENT(log_unit)) my_log_unit = log_unit
     105           24 :       my_lagrange_mult = -1
     106           24 :       IF (PRESENT(lagrange_mult)) my_lagrange_mult = lagrange_mult
     107           24 :       my_dump_lm = .FALSE.
     108           24 :       IF (PRESENT(dump_lm)) my_dump_lm = dump_lm
     109           24 :       NULLIFY (subsys, cell, molecules, molecule_kinds, local_molecules, particles, &
     110           24 :                my_pos, my_vel, gci)
     111           24 :       IF (PRESENT(pos)) my_pos => pos
     112           24 :       IF (PRESENT(vel)) my_vel => vel
     113           24 :       mydt = 0.1_dp
     114           24 :       IF (PRESENT(dt)) mydt = dt
     115           24 :       CALL force_env_get(force_env, subsys=subsys, cell=cell)
     116              :       CALL cp_subsys_get(subsys, &
     117              :                          atomic_kinds=atomic_kinds, &
     118              :                          local_molecules=local_molecules, &
     119              :                          local_particles=local_particles, &
     120              :                          molecules=molecules, &
     121              :                          molecule_kinds=molecule_kinds, &
     122              :                          particles=particles, &
     123           24 :                          gci=gci)
     124           24 :       nparticle_kind = atomic_kinds%n_els
     125           24 :       IF (PRESENT(compold)) THEN
     126           24 :          IF (compold) THEN
     127              :             CALL getold(gci, local_molecules, molecules%els, molecule_kinds%els, &
     128           24 :                         particles%els, cell)
     129              :          END IF
     130              :       END IF
     131           24 :       has_pos = .FALSE.
     132           24 :       IF (.NOT. ASSOCIATED(my_pos)) THEN
     133           24 :          has_pos = .TRUE.
     134           72 :          ALLOCATE (my_pos(3, particles%n_els))
     135         7504 :          my_pos = 0.0_dp
     136          112 :          DO iparticle_kind = 1, nparticle_kind
     137           88 :             nparticle_local = local_particles%n_el(iparticle_kind)
     138         1047 :             DO iparticle_local = 1, nparticle_local
     139          935 :                iparticle = local_particles%list(iparticle_kind)%array(iparticle_local)
     140         3828 :                my_pos(:, iparticle) = particles%els(iparticle)%r(:)
     141              :             END DO
     142              :          END DO
     143              :       END IF
     144           24 :       has_vel = .FALSE.
     145           24 :       IF (.NOT. ASSOCIATED(my_vel)) THEN
     146           24 :          has_vel = .TRUE.
     147           72 :          ALLOCATE (my_vel(3, particles%n_els))
     148         7504 :          my_vel = 0.0_dp
     149          112 :          DO iparticle_kind = 1, nparticle_kind
     150           88 :             nparticle_local = local_particles%n_el(iparticle_kind)
     151         1047 :             DO iparticle_local = 1, nparticle_local
     152          935 :                iparticle = local_particles%list(iparticle_kind)%array(iparticle_local)
     153         3828 :                my_vel(:, iparticle) = particles%els(iparticle)%v(:)
     154              :             END DO
     155              :          END DO
     156              :       END IF
     157              : 
     158              :       CALL shake_control(gci=gci, local_molecules=local_molecules, &
     159              :                          molecule_set=molecules%els, molecule_kind_set=molecule_kinds%els, &
     160              :                          particle_set=particles%els, pos=my_pos, vel=my_vel, dt=mydt, &
     161              :                          shake_tol=shake_tol, log_unit=my_log_unit, lagrange_mult=my_lagrange_mult, &
     162              :                          dump_lm=my_dump_lm, cell=cell, group=force_env%para_env, &
     163           24 :                          local_particles=local_particles)
     164              : 
     165              :       ! Possibly reset the lagrange multipliers
     166           24 :       IF (PRESENT(reset)) THEN
     167            0 :          IF (reset) THEN
     168              :             ! Reset Intramolecular constraints
     169            0 :             DO i = 1, SIZE(molecules%els)
     170            0 :                IF (ASSOCIATED(molecules%els(i)%lci%lcolv)) THEN
     171            0 :                   DO j = 1, SIZE(molecules%els(i)%lci%lcolv)
     172              :                      ! Reset langrange multiplier
     173            0 :                      molecules%els(i)%lci%lcolv(j)%lambda = 0.0_dp
     174              :                   END DO
     175              :                END IF
     176            0 :                IF (ASSOCIATED(molecules%els(i)%lci%lg3x3)) THEN
     177            0 :                   DO j = 1, SIZE(molecules%els(i)%lci%lg3x3)
     178              :                      ! Reset langrange multiplier
     179            0 :                      molecules%els(i)%lci%lg3x3(j)%lambda = 0.0_dp
     180              :                   END DO
     181              :                END IF
     182            0 :                IF (ASSOCIATED(molecules%els(i)%lci%lg4x6)) THEN
     183            0 :                   DO j = 1, SIZE(molecules%els(i)%lci%lg4x6)
     184              :                      ! Reset langrange multiplier
     185            0 :                      molecules%els(i)%lci%lg4x6(j)%lambda = 0.0_dp
     186              :                   END DO
     187              :                END IF
     188              :             END DO
     189              :             ! Reset Intermolecular constraints
     190            0 :             IF (ASSOCIATED(gci)) THEN
     191            0 :                IF (ASSOCIATED(gci%lcolv)) THEN
     192            0 :                   DO j = 1, SIZE(gci%lcolv)
     193              :                      ! Reset langrange multiplier
     194            0 :                      gci%lcolv(j)%lambda = 0.0_dp
     195              :                   END DO
     196              :                END IF
     197            0 :                IF (ASSOCIATED(gci%lg3x3)) THEN
     198            0 :                   DO j = 1, SIZE(gci%lg3x3)
     199              :                      ! Reset langrange multiplier
     200            0 :                      gci%lg3x3(j)%lambda = 0.0_dp
     201              :                   END DO
     202              :                END IF
     203            0 :                IF (ASSOCIATED(gci%lg4x6)) THEN
     204            0 :                   DO j = 1, SIZE(gci%lg4x6)
     205              :                      ! Reset langrange multiplier
     206            0 :                      gci%lg4x6(j)%lambda = 0.0_dp
     207              :                   END DO
     208              :                END IF
     209              :             END IF
     210              :          END IF
     211              :       END IF
     212              : 
     213           24 :       IF (has_pos) THEN
     214           24 :          CALL update_particle_set(particles%els, force_env%para_env, pos=my_pos)
     215           24 :          DEALLOCATE (my_pos)
     216              :       END IF
     217           24 :       IF (has_vel) THEN
     218           24 :          CALL update_particle_set(particles%els, force_env%para_env, vel=my_vel)
     219           24 :          DEALLOCATE (my_vel)
     220              :       END IF
     221           24 :       CALL timestop(handle)
     222           24 :    END SUBROUTINE force_env_shake
     223              : 
     224              : ! **************************************************************************************************
     225              : !> \brief perform rattle (enforcing of constraints on velocities)
     226              : !>      This routine can be easily adapted to performe rattle on whatever
     227              : !>      other vector different from forces..
     228              : !> \param force_env the force env to shake
     229              : !> \param dt the dt for shake (if you are not interested in the velocities
     230              : !>        it can be any positive number)
     231              : !> \param shake_tol the tolerance for shake
     232              : !> \param log_unit if >0 then some information on the shake is printed,
     233              : !>        defaults to -1
     234              : !> \param lagrange_mult ...
     235              : !> \param dump_lm ...
     236              : !> \param vel ...
     237              : !> \param reset ...
     238              : !> \author tlaino
     239              : ! **************************************************************************************************
     240           48 :    SUBROUTINE force_env_rattle(force_env, dt, shake_tol, log_unit, lagrange_mult, dump_lm, &
     241           24 :                                vel, reset)
     242              : 
     243              :       TYPE(force_env_type), POINTER                      :: force_env
     244              :       REAL(kind=dp), INTENT(in), OPTIONAL                :: dt
     245              :       REAL(kind=dp), INTENT(in)                          :: shake_tol
     246              :       INTEGER, INTENT(in), OPTIONAL                      :: log_unit, lagrange_mult
     247              :       LOGICAL, INTENT(IN), OPTIONAL                      :: dump_lm
     248              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT), &
     249              :          OPTIONAL, TARGET                                :: vel
     250              :       LOGICAL, INTENT(IN), OPTIONAL                      :: reset
     251              : 
     252              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'force_env_rattle'
     253              : 
     254              :       INTEGER :: handle, i, iparticle, iparticle_kind, iparticle_local, j, my_lagrange_mult, &
     255              :          my_log_unit, nparticle_kind, nparticle_local
     256              :       LOGICAL                                            :: has_vel, my_dump_lm
     257              :       REAL(KIND=dp)                                      :: mydt
     258           24 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: my_vel
     259              :       TYPE(atomic_kind_list_type), POINTER               :: atomic_kinds
     260              :       TYPE(cell_type), POINTER                           :: cell
     261              :       TYPE(cp_subsys_type), POINTER                      :: subsys
     262              :       TYPE(distribution_1d_type), POINTER                :: local_molecules, local_particles
     263              :       TYPE(global_constraint_type), POINTER              :: gci
     264              :       TYPE(molecule_kind_list_type), POINTER             :: molecule_kinds
     265              :       TYPE(molecule_list_type), POINTER                  :: molecules
     266              :       TYPE(particle_list_type), POINTER                  :: particles
     267              : 
     268           24 :       CALL timeset(routineN, handle)
     269           24 :       CPASSERT(ASSOCIATED(force_env))
     270           24 :       CPASSERT(force_env%ref_count > 0)
     271           24 :       my_log_unit = -1
     272           24 :       IF (PRESENT(log_unit)) my_log_unit = log_unit
     273           24 :       my_lagrange_mult = -1
     274           24 :       IF (PRESENT(lagrange_mult)) my_lagrange_mult = lagrange_mult
     275           24 :       my_dump_lm = .FALSE.
     276           24 :       IF (PRESENT(dump_lm)) my_dump_lm = dump_lm
     277           24 :       NULLIFY (subsys, cell, molecules, molecule_kinds, local_molecules, particles, &
     278           24 :                my_vel)
     279           24 :       IF (PRESENT(vel)) my_vel => vel
     280           24 :       mydt = 0.1_dp
     281           24 :       IF (PRESENT(dt)) mydt = dt
     282           24 :       CALL force_env_get(force_env, subsys=subsys, cell=cell)
     283              :       CALL cp_subsys_get(subsys, &
     284              :                          atomic_kinds=atomic_kinds, &
     285              :                          local_molecules=local_molecules, &
     286              :                          local_particles=local_particles, &
     287              :                          molecules=molecules, &
     288              :                          molecule_kinds=molecule_kinds, &
     289              :                          particles=particles, &
     290           24 :                          gci=gci)
     291           24 :       nparticle_kind = atomic_kinds%n_els
     292           24 :       has_vel = .FALSE.
     293           24 :       IF (.NOT. ASSOCIATED(my_vel)) THEN
     294           24 :          has_vel = .TRUE.
     295           72 :          ALLOCATE (my_vel(3, particles%n_els))
     296         7504 :          my_vel = 0.0_dp
     297          112 :          DO iparticle_kind = 1, nparticle_kind
     298           88 :             nparticle_local = local_particles%n_el(iparticle_kind)
     299         1047 :             DO iparticle_local = 1, nparticle_local
     300          935 :                iparticle = local_particles%list(iparticle_kind)%array(iparticle_local)
     301         3828 :                my_vel(:, iparticle) = particles%els(iparticle)%v(:)
     302              :             END DO
     303              :          END DO
     304              :       END IF
     305              : 
     306              :       CALL rattle_control(gci=gci, local_molecules=local_molecules, &
     307              :                           molecule_set=molecules%els, molecule_kind_set=molecule_kinds%els, &
     308              :                           particle_set=particles%els, vel=my_vel, dt=mydt, &
     309              :                           rattle_tol=shake_tol, log_unit=my_log_unit, lagrange_mult=my_lagrange_mult, &
     310              :                           dump_lm=my_dump_lm, cell=cell, group=force_env%para_env, &
     311           24 :                           local_particles=local_particles)
     312              : 
     313              :       ! Possibly reset the lagrange multipliers
     314           24 :       IF (PRESENT(reset)) THEN
     315           24 :          IF (reset) THEN
     316              :             ! Reset Intramolecular constraints
     317          500 :             DO i = 1, SIZE(molecules%els)
     318          476 :                IF (ASSOCIATED(molecules%els(i)%lci%lcolv)) THEN
     319           28 :                   DO j = 1, SIZE(molecules%els(i)%lci%lcolv)
     320              :                      ! Reset langrange multiplier
     321           28 :                      molecules%els(i)%lci%lcolv(j)%lambda = 0.0_dp
     322              :                   END DO
     323              :                END IF
     324          476 :                IF (ASSOCIATED(molecules%els(i)%lci%lg3x3)) THEN
     325          890 :                   DO j = 1, SIZE(molecules%els(i)%lci%lg3x3)
     326              :                      ! Reset langrange multiplier
     327         2216 :                      molecules%els(i)%lci%lg3x3(j)%lambda = 0.0_dp
     328              :                   END DO
     329              :                END IF
     330          500 :                IF (ASSOCIATED(molecules%els(i)%lci%lg4x6)) THEN
     331           12 :                   DO j = 1, SIZE(molecules%els(i)%lci%lg4x6)
     332              :                      ! Reset langrange multiplier
     333           36 :                      molecules%els(i)%lci%lg4x6(j)%lambda = 0.0_dp
     334              :                   END DO
     335              :                END IF
     336              :             END DO
     337              :             ! Reset Intermolecular constraints
     338           24 :             IF (ASSOCIATED(gci)) THEN
     339           24 :                IF (ASSOCIATED(gci%lcolv)) THEN
     340            0 :                   DO j = 1, SIZE(gci%lcolv)
     341              :                      ! Reset langrange multiplier
     342            0 :                      gci%lcolv(j)%lambda = 0.0_dp
     343              :                   END DO
     344              :                END IF
     345           24 :                IF (ASSOCIATED(gci%lg3x3)) THEN
     346            0 :                   DO j = 1, SIZE(gci%lg3x3)
     347              :                      ! Reset langrange multiplier
     348            0 :                      gci%lg3x3(j)%lambda = 0.0_dp
     349              :                   END DO
     350              :                END IF
     351           24 :                IF (ASSOCIATED(gci%lg4x6)) THEN
     352            0 :                   DO j = 1, SIZE(gci%lg4x6)
     353              :                      ! Reset langrange multiplier
     354            0 :                      gci%lg4x6(j)%lambda = 0.0_dp
     355              :                   END DO
     356              :                END IF
     357              :             END IF
     358              :          END IF
     359              :       END IF
     360              : 
     361           24 :       IF (has_vel) THEN
     362           24 :          CALL update_particle_set(particles%els, force_env%para_env, vel=my_vel)
     363              :       END IF
     364           24 :       DEALLOCATE (my_vel)
     365           24 :       CALL timestop(handle)
     366           24 :    END SUBROUTINE force_env_rattle
     367              : 
     368              : ! **************************************************************************************************
     369              : !> \brief Rescale forces if requested
     370              : !> \param force_env the force env to shake
     371              : !> \author tlaino
     372              : ! **************************************************************************************************
     373       195142 :    SUBROUTINE rescale_forces(force_env)
     374              :       TYPE(force_env_type), POINTER                      :: force_env
     375              : 
     376              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'rescale_forces'
     377              : 
     378              :       INTEGER                                            :: handle, iparticle
     379              :       LOGICAL                                            :: explicit
     380              :       REAL(KIND=dp)                                      :: force(3), max_value, mod_force
     381              :       TYPE(cp_subsys_type), POINTER                      :: subsys
     382              :       TYPE(particle_list_type), POINTER                  :: particles
     383              :       TYPE(section_vals_type), POINTER                   :: rescale_force_section
     384              : 
     385        97571 :       CALL timeset(routineN, handle)
     386        97571 :       CPASSERT(ASSOCIATED(force_env))
     387        97571 :       CPASSERT(force_env%ref_count > 0)
     388        97571 :       rescale_force_section => section_vals_get_subs_vals(force_env%force_env_section, "RESCALE_FORCES")
     389        97571 :       CALL section_vals_get(rescale_force_section, explicit=explicit)
     390        97571 :       IF (explicit) THEN
     391          224 :          CALL section_vals_val_get(rescale_force_section, "MAX_FORCE", r_val=max_value)
     392          224 :          CALL force_env_get(force_env, subsys=subsys)
     393          224 :          CALL cp_subsys_get(subsys, particles=particles)
     394        36262 :          DO iparticle = 1, SIZE(particles%els)
     395       144152 :             force = particles%els(iparticle)%f(:)
     396       144152 :             mod_force = SQRT(DOT_PRODUCT(force, force))
     397        36262 :             IF ((mod_force > max_value) .AND. (mod_force /= 0.0_dp)) THEN
     398        10208 :                force = force/mod_force*max_value
     399        10208 :                particles%els(iparticle)%f(:) = force
     400              :             END IF
     401              :          END DO
     402              :       END IF
     403        97571 :       CALL timestop(handle)
     404        97571 :    END SUBROUTINE rescale_forces
     405              : 
     406              : ! **************************************************************************************************
     407              : !> \brief Write forces either to the screen or to a file.
     408              : !> \param particles ...
     409              : !> \param iw ...
     410              : !> \param label ...
     411              : !> \param ndigits ...
     412              : !> \param unit_string ...
     413              : !> \param total_force ...
     414              : !> \param grand_total_force ...
     415              : !> \param zero_force_core_shell_atom ...
     416              : !> \author Ole Schuett
     417              : ! **************************************************************************************************
     418         1835 :    SUBROUTINE write_forces(particles, iw, label, ndigits, unit_string, total_force, &
     419              :                            grand_total_force, zero_force_core_shell_atom)
     420              : 
     421              :       TYPE(particle_list_type), POINTER                  :: particles
     422              :       INTEGER, INTENT(IN)                                :: iw
     423              :       CHARACTER(LEN=*), INTENT(IN)                       :: label
     424              :       INTEGER, INTENT(IN)                                :: ndigits
     425              :       CHARACTER(LEN=default_string_length), INTENT(IN)   :: unit_string
     426              :       REAL(KIND=dp), DIMENSION(3), INTENT(OUT)           :: total_force
     427              :       REAL(KIND=dp), DIMENSION(3), INTENT(INOUT), &
     428              :          OPTIONAL                                        :: grand_total_force
     429              :       LOGICAL, INTENT(IN), OPTIONAL                      :: zero_force_core_shell_atom
     430              : 
     431         1835 :       IF (iw == cp_logger_get_default_io_unit()) THEN
     432              :          CALL write_forces_to_screen(particles, iw, label, ndigits, unit_string, total_force, &
     433         1830 :                                      grand_total_force, zero_force_core_shell_atom)
     434              :       ELSE
     435              :          CALL write_forces_to_file(particles, iw, label, ndigits, total_force, &
     436            5 :                                    grand_total_force, zero_force_core_shell_atom)
     437              :       END IF
     438         1835 :    END SUBROUTINE write_forces
     439              : 
     440              : ! **************************************************************************************************
     441              : !> \brief Write forces to the screen.
     442              : !>
     443              : !> \param particles ...
     444              : !> \param iw ...
     445              : !> \param label ...
     446              : !> \param ndigits ...
     447              : !> \param unit_string ...
     448              : !> \param total_force ...
     449              : !> \param grand_total_force ...
     450              : !> \param zero_force_core_shell_atom ...
     451              : !> \author MK (06.09.2010)
     452              : ! **************************************************************************************************
     453         1830 :    SUBROUTINE write_forces_to_screen(particles, iw, label, ndigits, unit_string, total_force, &
     454              :                                      grand_total_force, zero_force_core_shell_atom)
     455              : 
     456              :       TYPE(particle_list_type), POINTER                  :: particles
     457              :       INTEGER, INTENT(IN)                                :: iw
     458              :       CHARACTER(LEN=*), INTENT(IN)                       :: label
     459              :       INTEGER, INTENT(IN)                                :: ndigits
     460              :       CHARACTER(LEN=default_string_length), INTENT(IN)   :: unit_string
     461              :       REAL(KIND=dp), DIMENSION(3), INTENT(OUT)           :: total_force
     462              :       REAL(KIND=dp), DIMENSION(3), INTENT(INOUT), &
     463              :          OPTIONAL                                        :: grand_total_force
     464              :       LOGICAL, INTENT(IN), OPTIONAL                      :: zero_force_core_shell_atom
     465              : 
     466              :       CHARACTER(LEN=18)                                  :: fmtstr4
     467              :       CHARACTER(LEN=29)                                  :: fmtstr3
     468              :       CHARACTER(LEN=38)                                  :: fmtstr2
     469              :       CHARACTER(LEN=49)                                  :: fmtstr1
     470              :       CHARACTER(LEN=7)                                   :: tag
     471         1830 :       CHARACTER(LEN=LEN_TRIM(label))                     :: lc_label
     472              :       INTEGER                                            :: i, iparticle, n
     473              :       LOGICAL                                            :: zero_force
     474              :       REAL(KIND=dp)                                      :: fconv
     475              :       REAL(KIND=dp), DIMENSION(3)                        :: f
     476              : 
     477         1830 :       IF (iw > 0) THEN
     478         1830 :          CPASSERT(ASSOCIATED(particles))
     479         1830 :          tag = "FORCES|"
     480         1830 :          lc_label = TRIM(label)
     481         1830 :          CALL lowercase(lc_label)
     482         1830 :          n = MIN(MAX(1, ndigits), 20)
     483         1830 :          fmtstr1 = "(/,T2,A,1X,A,/,T2,A,3X,A,T20,A3,2(  X,A3),  X,A3)"
     484         1830 :          WRITE (UNIT=fmtstr1(35:36), FMT="(I2)") n + 5
     485         1830 :          WRITE (UNIT=fmtstr1(43:44), FMT="(I2)") n + 6
     486         1830 :          fmtstr2 = "(T2,A,I7,T16,3(1X,ES  .  ),2X,ES  .  )"
     487         1830 :          WRITE (UNIT=fmtstr2(21:22), FMT="(I2)") n + 7
     488         1830 :          WRITE (UNIT=fmtstr2(24:25), FMT="(I2)") n
     489         1830 :          WRITE (UNIT=fmtstr2(33:34), FMT="(I2)") n + 7
     490         1830 :          WRITE (UNIT=fmtstr2(36:37), FMT="(I2)") n
     491         1830 :          fmtstr3 = "(T2,A,T16,3(1X,ES  .  ))"
     492         1830 :          WRITE (UNIT=fmtstr3(18:19), FMT="(I2)") n + 7
     493         1830 :          WRITE (UNIT=fmtstr3(21:22), FMT="(I2)") n
     494         1830 :          fmtstr4 = "(T2,A,T  ,ES  .  )"
     495         1830 :          WRITE (UNIT=fmtstr4(8:9), FMT="(I2)") 3*(n + 8) + 18
     496         1830 :          WRITE (UNIT=fmtstr4(13:14), FMT="(I2)") n + 7
     497         1830 :          WRITE (UNIT=fmtstr4(16:17), FMT="(I2)") n
     498         1830 :          IF (PRESENT(zero_force_core_shell_atom)) THEN
     499          495 :             zero_force = zero_force_core_shell_atom
     500              :          ELSE
     501              :             zero_force = .FALSE.
     502              :          END IF
     503         1830 :          fconv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_string))
     504              :          WRITE (UNIT=iw, FMT=fmtstr1) &
     505         1830 :             tag, label//" forces ["//TRIM(ADJUSTL(unit_string))//"]", &
     506         3660 :             tag, "Atom", " x ", " y ", " z ", "|f|"
     507         1830 :          total_force(1:3) = 0.0_dp
     508       188619 :          DO iparticle = 1, particles%n_els
     509       186789 :             IF (particles%els(iparticle)%atom_index /= 0) THEN
     510       186789 :                i = particles%els(iparticle)%atom_index
     511              :             ELSE
     512            0 :                i = iparticle
     513              :             END IF
     514       186789 :             IF (zero_force .AND. (particles%els(iparticle)%shell_index /= 0)) THEN
     515        49172 :                f(1:3) = 0.0_dp
     516              :             ELSE
     517       550468 :                f(1:3) = particles%els(iparticle)%f(1:3)*fconv
     518              :             END IF
     519              :             WRITE (UNIT=iw, FMT=fmtstr2) &
     520       933945 :                tag, i, f(1:3), SQRT(SUM(f(1:3)**2))
     521       748986 :             total_force(1:3) = total_force(1:3) + f(1:3)
     522              :          END DO
     523              :          WRITE (UNIT=iw, FMT=fmtstr3) &
     524         1830 :             tag//" Sum", total_force(1:3)
     525              :          WRITE (UNIT=iw, FMT=fmtstr4) &
     526         1830 :             tag//" Total "//TRIM(ADJUSTL(lc_label))//" force", &
     527         9150 :             SQRT(SUM(total_force(1:3)**2))
     528              :       END IF
     529              : 
     530         1830 :       IF (PRESENT(grand_total_force)) THEN
     531          660 :          grand_total_force(1:3) = grand_total_force(1:3) + total_force(1:3)
     532          165 :          WRITE (UNIT=iw, FMT="(A)") ""
     533              :          WRITE (UNIT=iw, FMT=fmtstr4) &
     534          165 :             tag//" Grand total force ["//TRIM(ADJUSTL(unit_string))//"]", &
     535          825 :             SQRT(SUM(grand_total_force(1:3)**2))
     536              :       END IF
     537              : 
     538         1830 :    END SUBROUTINE write_forces_to_screen
     539              : 
     540              : ! **************************************************************************************************
     541              : !> \brief Write forces to a file using our stable legacy format. Please don't change the format.
     542              : !>
     543              : !> \param particles ...
     544              : !> \param iw ...
     545              : !> \param label ...
     546              : !> \param ndigits ...
     547              : !> \param total_force ...
     548              : !> \param grand_total_force ...
     549              : !> \param zero_force_core_shell_atom ...
     550              : !> \author MK (06.09.2010)
     551              : ! **************************************************************************************************
     552            5 :    SUBROUTINE write_forces_to_file(particles, iw, label, ndigits, total_force, &
     553              :                                    grand_total_force, zero_force_core_shell_atom)
     554              : 
     555              :       TYPE(particle_list_type), POINTER                  :: particles
     556              :       INTEGER, INTENT(IN)                                :: iw
     557              :       CHARACTER(LEN=*), INTENT(IN)                       :: label
     558              :       INTEGER, INTENT(IN)                                :: ndigits
     559              :       REAL(KIND=dp), DIMENSION(3), INTENT(OUT)           :: total_force
     560              :       REAL(KIND=dp), DIMENSION(3), INTENT(INOUT), &
     561              :          OPTIONAL                                        :: grand_total_force
     562              :       LOGICAL, INTENT(IN), OPTIONAL                      :: zero_force_core_shell_atom
     563              : 
     564              :       CHARACTER(LEN=23)                                  :: fmtstr3
     565              :       CHARACTER(LEN=36)                                  :: fmtstr2
     566              :       CHARACTER(LEN=46)                                  :: fmtstr1
     567            5 :       CHARACTER(LEN=LEN_TRIM(label))                     :: uc_label
     568              :       INTEGER                                            :: i, ikind, iparticle, n
     569              :       LOGICAL                                            :: zero_force
     570              :       REAL(KIND=dp), DIMENSION(3)                        :: f
     571              : 
     572            5 :       IF (iw > 0) THEN
     573            5 :          CPASSERT(ASSOCIATED(particles))
     574            5 :          n = MIN(MAX(1, ndigits), 20)
     575            5 :          fmtstr1 = "(/,T2,A,/,/,T2,A,T11,A,T18,A,T35,A1,2(  X,A1))"
     576            5 :          WRITE (UNIT=fmtstr1(39:40), FMT="(I2)") n + 6
     577            5 :          fmtstr2 = "(T2,I6,1X,I6,T21,A,T28,3(1X,F  .  ))"
     578            5 :          WRITE (UNIT=fmtstr2(33:34), FMT="(I2)") n
     579            5 :          WRITE (UNIT=fmtstr2(30:31), FMT="(I2)") n + 6
     580            5 :          fmtstr3 = "(T2,A,T28,4(1X,F  .  ))"
     581            5 :          WRITE (UNIT=fmtstr3(20:21), FMT="(I2)") n
     582            5 :          WRITE (UNIT=fmtstr3(17:18), FMT="(I2)") n + 6
     583            5 :          IF (PRESENT(zero_force_core_shell_atom)) THEN
     584            0 :             zero_force = zero_force_core_shell_atom
     585              :          ELSE
     586              :             zero_force = .FALSE.
     587              :          END IF
     588            5 :          uc_label = TRIM(label)
     589            5 :          CALL uppercase(uc_label)
     590              :          WRITE (UNIT=iw, FMT=fmtstr1) &
     591            5 :             uc_label//" FORCES in [a.u.]", "# Atom", "Kind", "Element", "X", "Y", "Z"
     592            5 :          total_force(1:3) = 0.0_dp
     593          110 :          DO iparticle = 1, particles%n_els
     594          105 :             ikind = particles%els(iparticle)%atomic_kind%kind_number
     595          105 :             IF (particles%els(iparticle)%atom_index /= 0) THEN
     596          105 :                i = particles%els(iparticle)%atom_index
     597              :             ELSE
     598            0 :                i = iparticle
     599              :             END IF
     600          105 :             IF (zero_force .AND. (particles%els(iparticle)%shell_index /= 0)) THEN
     601            0 :                f(1:3) = 0.0_dp
     602              :             ELSE
     603          420 :                f(1:3) = particles%els(iparticle)%f(1:3)
     604              :             END IF
     605              :             WRITE (UNIT=iw, FMT=fmtstr2) &
     606          105 :                i, ikind, particles%els(iparticle)%atomic_kind%element_symbol, f(1:3)
     607          425 :             total_force(1:3) = total_force(1:3) + f(1:3)
     608              :          END DO
     609              :          WRITE (UNIT=iw, FMT=fmtstr3) &
     610           25 :             "SUM OF "//uc_label//" FORCES", total_force(1:3), SQRT(SUM(total_force(:)**2))
     611              :       END IF
     612              : 
     613            5 :       IF (PRESENT(grand_total_force)) THEN
     614            0 :          grand_total_force(1:3) = grand_total_force(1:3) + total_force(1:3)
     615            0 :          WRITE (UNIT=iw, FMT="(A)") ""
     616              :          WRITE (UNIT=iw, FMT=fmtstr3) &
     617            0 :             "GRAND TOTAL FORCE", grand_total_force(1:3), SQRT(SUM(grand_total_force(:)**2))
     618              :       END IF
     619              : 
     620            5 :    END SUBROUTINE write_forces_to_file
     621              : 
     622              : ! **************************************************************************************************
     623              : !> \brief Write the atomic coordinates, types, and energies
     624              : !> \param iounit ...
     625              : !> \param particles ...
     626              : !> \param atener ...
     627              : !> \param label ...
     628              : !> \date    05.06.2023
     629              : !> \author  JGH
     630              : !> \version 1.0
     631              : ! **************************************************************************************************
     632          489 :    SUBROUTINE write_atener(iounit, particles, atener, label)
     633              : 
     634              :       INTEGER, INTENT(IN)                                :: iounit
     635              :       TYPE(particle_list_type), POINTER                  :: particles
     636              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: atener
     637              :       CHARACTER(LEN=*), INTENT(IN)                       :: label
     638              : 
     639              :       INTEGER                                            :: i, natom
     640              : 
     641          489 :       IF (iounit > 0) THEN
     642          489 :          WRITE (UNIT=iounit, FMT="(/,T2,A)") TRIM(label)
     643              :          WRITE (UNIT=iounit, FMT="(T4,A,T30,A,T42,A,T54,A,T69,A)") &
     644          489 :             "Atom  Element", "X", "Y", "Z", "Energy[a.u.]"
     645          489 :          natom = particles%n_els
     646        17788 :          DO i = 1, natom
     647        17299 :             WRITE (iounit, "(I6,T12,A2,T24,3F12.6,F21.10)") i, &
     648        17299 :                TRIM(ADJUSTL(particles%els(i)%atomic_kind%element_symbol)), &
     649        86984 :                particles%els(i)%r(1:3)*angstrom, atener(i)
     650              :          END DO
     651          489 :          WRITE (iounit, "(A)") ""
     652              :       END IF
     653              : 
     654          489 :    END SUBROUTINE write_atener
     655              : 
     656              : END MODULE force_env_utils
        

Generated by: LCOV version 2.0-1