LCOV - code coverage report
Current view: top level - src - qmmmx_force.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 90.1 % 71 64
Test Date: 2026-07-25 06:35:44 Functions: 100.0 % 2 2

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Calculates QM/MM energy and forces with Force-Mixing
      10              : !> \par History
      11              : !>      2015 Factored out of force_env_methods.F
      12              : !> \author Ole Schuett
      13              : ! **************************************************************************************************
      14              : MODULE qmmmx_force
      15              :    USE cell_types,                      ONLY: cell_type
      16              :    USE cp_subsys_types,                 ONLY: cp_subsys_type
      17              :    USE fist_environment_types,          ONLY: fist_env_get
      18              :    USE input_constants,                 ONLY: do_fm_mom_conserv_QM,&
      19              :                                               do_fm_mom_conserv_buffer,&
      20              :                                               do_fm_mom_conserv_core,&
      21              :                                               do_fm_mom_conserv_equal_a,&
      22              :                                               do_fm_mom_conserv_equal_f,&
      23              :                                               do_fm_mom_conserv_none
      24              :    USE input_section_types,             ONLY: section_vals_type,&
      25              :                                               section_vals_val_get,&
      26              :                                               section_vals_val_set
      27              :    USE kinds,                           ONLY: default_string_length,&
      28              :                                               dp
      29              :    USE particle_types,                  ONLY: particle_type
      30              :    USE qmmm_force,                      ONLY: qmmm_calc_energy_force
      31              :    USE qmmm_types,                      ONLY: qmmm_env_get,&
      32              :                                               qmmm_env_type
      33              :    USE qmmm_types_low,                  ONLY: force_mixing_label_QM_core,&
      34              :                                               force_mixing_label_QM_dynamics,&
      35              :                                               force_mixing_label_buffer
      36              :    USE qmmm_util,                       ONLY: apply_qmmm_unwrap,&
      37              :                                               apply_qmmm_wrap
      38              :    USE qmmmx_types,                     ONLY: qmmmx_env_type
      39              :    USE qmmmx_util,                      ONLY: apply_qmmmx_translate
      40              :    USE qs_environment_types,            ONLY: get_qs_env
      41              : #include "./base/base_uses.f90"
      42              : 
      43              :    IMPLICIT NONE
      44              : 
      45              :    PRIVATE
      46              : 
      47              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qmmmx_force'
      48              : 
      49              :    PUBLIC :: qmmmx_calc_energy_force
      50              : 
      51              : CONTAINS
      52              : 
      53              : ! **************************************************************************************************
      54              : !> \brief calculates the qm/mm energy and forces
      55              : !> \param qmmmx_env ...
      56              : !> \param calc_force if also the forces should be calculated
      57              : !> \param consistent_energies ...
      58              : !> \param linres ...
      59              : !> \param require_consistent_energy_force ...
      60              : !> \par History
      61              : !>      05.2004 created [fawzi]
      62              : !> \author Fawzi Mohamed
      63              : ! **************************************************************************************************
      64          104 :    SUBROUTINE qmmmx_calc_energy_force(qmmmx_env, calc_force, consistent_energies, linres, &
      65              :                                       require_consistent_energy_force)
      66              :       TYPE(qmmmx_env_type), POINTER                      :: qmmmx_env
      67              :       LOGICAL, INTENT(IN)                                :: calc_force, consistent_energies, linres
      68              :       LOGICAL, INTENT(IN), OPTIONAL :: require_consistent_energy_force
      69              : 
      70              :       INTEGER                                            :: ip, mom_conserv_min_label, &
      71              :                                                             mom_conserv_n, mom_conserv_region, &
      72              :                                                             mom_conserv_type
      73           52 :       INTEGER, POINTER                                   :: cur_indices(:), cur_labels(:)
      74              :       REAL(dp)                                           :: delta_a(3), delta_f(3), &
      75              :                                                             mom_conserv_mass, total_f(3)
      76              :       TYPE(cp_subsys_type), POINTER                      :: subsys_primary, subsys_qmmm_core, &
      77              :                                                             subsys_qmmm_extended
      78           52 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles_primary, particles_qmmm_core, &
      79           52 :                                                             particles_qmmm_extended
      80              :       TYPE(section_vals_type), POINTER                   :: force_env_section
      81              : 
      82           52 :       IF (PRESENT(require_consistent_energy_force)) THEN
      83           48 :          IF (require_consistent_energy_force) THEN
      84              :             CALL cp_abort(__LOCATION__, &
      85            0 :                           "qmmmx_energy_and_forces got require_consistent_energy_force but force mixing is active. ")
      86              :          END IF
      87              :       END IF
      88              : 
      89              :       ! Possibly translate the system
      90           52 :       CALL apply_qmmmx_translate(qmmmx_env)
      91              : 
      92              :       ! actual energy force calculation
      93           52 :       CALL qmmmx_calc_energy_force_low(qmmmx_env%ext, calc_force, consistent_energies, linres, "ext")
      94           52 :       CALL qmmmx_calc_energy_force_low(qmmmx_env%core, calc_force, consistent_energies, linres, "core")
      95              : 
      96              :       ! get forces from subsys of each sub force env
      97           52 :       CALL qmmm_env_get(qmmmx_env%core, subsys=subsys_qmmm_core)
      98           52 :       CALL qmmm_env_get(qmmmx_env%ext, subsys=subsys_qmmm_extended)
      99              : 
     100           52 :       CALL get_qs_env(qmmmx_env%ext%qs_env, input=force_env_section)
     101           52 :       CALL section_vals_val_get(force_env_section, "QMMM%FORCE_MIXING%RESTART_INFO%INDICES", i_vals=cur_indices)
     102           52 :       CALL section_vals_val_get(force_env_section, "QMMM%FORCE_MIXING%RESTART_INFO%LABELS", i_vals=cur_labels)
     103              : 
     104           52 :       particles_qmmm_extended => subsys_qmmm_extended%particles%els
     105           52 :       particles_qmmm_core => subsys_qmmm_core%particles%els
     106         1990 :       DO ip = 1, SIZE(cur_indices)
     107         1990 :          IF (cur_labels(ip) >= force_mixing_label_QM_dynamics) THEN ! this is a QM atom
     108              :             ! copy (QM) force from extended calculation
     109         5472 :             particles_qmmm_core(cur_indices(ip))%f = particles_qmmm_extended(cur_indices(ip))%f
     110              :          END IF
     111              :       END DO
     112              : 
     113              :       ! zero momentum
     114              :       CALL section_vals_val_get(force_env_section, "QMMM%FORCE_MIXING%MOMENTUM_CONSERVATION_TYPE", &
     115           52 :                                 i_val=mom_conserv_type)
     116           52 :       IF (mom_conserv_type /= do_fm_mom_conserv_none) THEN
     117              :          CALL section_vals_val_get(force_env_section, "QMMM%FORCE_MIXING%MOMENTUM_CONSERVATION_REGION", &
     118           52 :                                    i_val=mom_conserv_region)
     119              : 
     120           52 :          IF (mom_conserv_region == do_fm_mom_conserv_core) THEN
     121              :             mom_conserv_min_label = force_mixing_label_QM_core
     122              :          ELSE IF (mom_conserv_region == do_fm_mom_conserv_QM) THEN
     123              :             mom_conserv_min_label = force_mixing_label_QM_dynamics
     124              :          ELSE IF (mom_conserv_region == do_fm_mom_conserv_buffer) THEN
     125              :             mom_conserv_min_label = force_mixing_label_buffer
     126              :          ELSE
     127            0 :             CPABORT("Got unknown MOMENTUM_CONSERVATION_REGION (not CORE, QM, or BUFFER) !")
     128              :          END IF
     129              : 
     130           52 :          total_f = 0.0_dp
     131        99838 :          DO ip = 1, SIZE(particles_qmmm_core)
     132       399196 :             total_f(1:3) = total_f(1:3) + particles_qmmm_core(ip)%f(1:3)
     133              :          END DO
     134           52 :          IF (mom_conserv_type == do_fm_mom_conserv_equal_f) THEN
     135            0 :             mom_conserv_n = COUNT(cur_labels >= mom_conserv_min_label)
     136            0 :             delta_f = total_f/mom_conserv_n
     137            0 :             DO ip = 1, SIZE(cur_indices)
     138            0 :                IF (cur_labels(ip) >= mom_conserv_min_label) THEN
     139            0 :                   particles_qmmm_core(cur_indices(ip))%f = particles_qmmm_core(cur_indices(ip))%f - delta_f
     140              :                END IF
     141              :             END DO
     142           52 :          ELSE IF (mom_conserv_type == do_fm_mom_conserv_equal_a) THEN
     143           52 :             mom_conserv_mass = 0.0_dp
     144         1990 :             DO ip = 1, SIZE(cur_indices)
     145         1990 :                IF (cur_labels(ip) >= mom_conserv_min_label) THEN
     146          684 :                   mom_conserv_mass = mom_conserv_mass + particles_qmmm_core(cur_indices(ip))%atomic_kind%mass
     147              :                END IF
     148              :             END DO
     149          208 :             delta_a = total_f/mom_conserv_mass
     150         1990 :             DO ip = 1, SIZE(cur_indices)
     151         1990 :                IF (cur_labels(ip) >= mom_conserv_min_label) THEN
     152              :                   particles_qmmm_core(cur_indices(ip))%f = particles_qmmm_core(cur_indices(ip))%f - &
     153         2736 :                                                            particles_qmmm_core(cur_indices(ip))%atomic_kind%mass*delta_a
     154              :                END IF
     155              :             END DO
     156              :          END IF
     157              :       END IF
     158              : 
     159           52 :       CALL qmmm_env_get(qmmmx_env%ext, subsys=subsys_primary)
     160           52 :       particles_primary => subsys_primary%particles%els
     161        99838 :       DO ip = 1, SIZE(particles_qmmm_core)
     162       798340 :          particles_primary(ip)%f = particles_qmmm_core(ip)%f
     163              :       END DO
     164              : 
     165           52 :    END SUBROUTINE qmmmx_calc_energy_force
     166              : 
     167              : ! **************************************************************************************************
     168              : !> \brief ...
     169              : !> \param qmmm_env ...
     170              : !> \param calc_force ...
     171              : !> \param consistent_energies ...
     172              : !> \param linres ...
     173              : !> \param label ...
     174              : ! **************************************************************************************************
     175          104 :    SUBROUTINE qmmmx_calc_energy_force_low(qmmm_env, calc_force, consistent_energies, linres, label)
     176              :       TYPE(qmmm_env_type), POINTER                       :: qmmm_env
     177              :       LOGICAL, INTENT(IN)                                :: calc_force, consistent_energies, linres
     178              :       CHARACTER(*)                                       :: label
     179              : 
     180              :       CHARACTER(default_string_length)                   :: new_restart_fn, new_restart_hist_fn, &
     181              :                                                             old_restart_fn, old_restart_hist_fn
     182          104 :       INTEGER, DIMENSION(:), POINTER                     :: qm_atom_index
     183              :       LOGICAL                                            :: saved_do_translate
     184          104 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: saved_pos
     185              :       TYPE(cell_type), POINTER                           :: mm_cell
     186              :       TYPE(cp_subsys_type), POINTER                      :: subsys_mm, subsys_qm
     187              :       TYPE(section_vals_type), POINTER                   :: force_env_section
     188              : 
     189          104 :       NULLIFY (mm_cell, subsys_qm, subsys_mm, qm_atom_index)
     190              : 
     191          104 :       CALL get_qs_env(qmmm_env%qs_env, input=force_env_section)
     192              : 
     193              :       ! rewrite RESTART%FILENAME
     194              :       CALL section_vals_val_get(force_env_section, "DFT%SCF%PRINT%RESTART%FILENAME", &
     195          104 :                                 c_val=old_restart_fn)
     196          104 :       new_restart_fn = TRIM(old_restart_fn)//"-"//TRIM(label)
     197              :       CALL section_vals_val_set(force_env_section, "DFT%SCF%PRINT%RESTART%FILENAME", &
     198          104 :                                 c_val=new_restart_fn)
     199              : 
     200              :       ! rewrite RESTART_HISTORY%FILENAME
     201              :       CALL section_vals_val_get(force_env_section, "DFT%SCF%PRINT%RESTART_HISTORY%FILENAME", &
     202          104 :                                 c_val=old_restart_hist_fn)
     203          104 :       new_restart_hist_fn = TRIM(old_restart_hist_fn)//"-"//TRIM(label)
     204              :       CALL section_vals_val_set(force_env_section, "DFT%SCF%PRINT%RESTART_HISTORY%FILENAME", &
     205          104 :                                 c_val=new_restart_hist_fn)
     206              : 
     207              :       ! wrap positions before QM/MM calculation.
     208              :       ! Required if diffusion causes atoms outside of periodic box get added to QM
     209          104 :       CALL fist_env_get(qmmm_env%fist_env, cell=mm_cell, subsys=subsys_mm)
     210          104 :       CALL get_qs_env(qmmm_env%qs_env, cp_subsys=subsys_qm)
     211          104 :       qm_atom_index => qmmm_env%qm%qm_atom_index
     212          104 :       CALL apply_qmmm_wrap(subsys_mm, mm_cell, subsys_qm, qm_atom_index, saved_pos)
     213              : 
     214              :       ! Turn off box translation, it was already performed by apply_qmmmx_translate(),
     215              :       ! the particles coordinates will still be copied from MM to QM.
     216          104 :       saved_do_translate = qmmm_env%qm%do_translate
     217          104 :       qmmm_env%qm%do_translate = .FALSE.
     218              : 
     219              :       ! actual energy force calculation
     220          104 :       CALL qmmm_calc_energy_force(qmmm_env, calc_force, consistent_energies, linres)
     221              : 
     222              :       ! restore do_translate
     223          104 :       qmmm_env%qm%do_translate = saved_do_translate
     224              : 
     225              :       ! restore unwrapped positions
     226          104 :       CALL apply_qmmm_unwrap(subsys_mm, subsys_qm, qm_atom_index, saved_pos)
     227              : 
     228              :       ! restore RESTART filenames
     229              :       CALL section_vals_val_set(force_env_section, "DFT%SCF%PRINT%RESTART%FILENAME", &
     230          104 :                                 c_val=old_restart_fn)
     231              :       CALL section_vals_val_set(force_env_section, "DFT%SCF%PRINT%RESTART_HISTORY%FILENAME", &
     232          104 :                                 c_val=old_restart_hist_fn)
     233              : 
     234          208 :    END SUBROUTINE qmmmx_calc_energy_force_low
     235              : 
     236              : END MODULE qmmmx_force
        

Generated by: LCOV version 2.0-1