LCOV - code coverage report
Current view: top level - src - cp2k_debug.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:ccc2433) Lines: 244 264 92.4 %
Date: 2024-04-25 07:09:54 Functions: 2 2 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 Debug energy and derivatives w.r.t. finite differences
      10             : !> \note
      11             : !>      Use INTERPOLATION USE_GUESS, in order to perform force and energy
      12             : !>      calculations with the same density. This is not compulsory when iterating
      13             : !>      to selfconsistency, but essential in the non-selfconsistent case [08.2005,TdK].
      14             : !> \par History
      15             : !>      12.2004 created [tlaino]
      16             : !>      08.2005 consistent_energies option added, to allow FD calculations
      17             : !>              with the correct energies in the non-selfconsistent case, but
      18             : !>              keep in mind, that the QS energies and forces are then NOT
      19             : !>              consistent to each other [TdK].
      20             : !>      08.2005 In case the Harris functional is used, consistent_energies is
      21             : !>              et to .FALSE., otherwise the QS energies are spuriously used [TdK].
      22             : !>      01.2015 Remove Harris functional option
      23             : !>      - Revised (20.11.2013,MK)
      24             : !> \author Teodoro Laino
      25             : ! **************************************************************************************************
      26             : MODULE cp2k_debug
      27             :    USE cell_types,                      ONLY: cell_type
      28             :    USE cp_control_types,                ONLY: dft_control_type
      29             :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      30             :                                               cp_logger_type
      31             :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      32             :                                               cp_print_key_unit_nr
      33             :    USE cp_result_methods,               ONLY: get_results,&
      34             :                                               test_for_result
      35             :    USE cp_result_types,                 ONLY: cp_result_type
      36             :    USE cp_subsys_types,                 ONLY: cp_subsys_get,&
      37             :                                               cp_subsys_type
      38             :    USE force_env_methods,               ONLY: force_env_calc_energy_force,&
      39             :                                               force_env_calc_num_pressure
      40             :    USE force_env_types,                 ONLY: force_env_get,&
      41             :                                               force_env_type,&
      42             :                                               use_qs_force
      43             :    USE input_constants,                 ONLY: do_stress_analytical,&
      44             :                                               do_stress_diagonal_anal,&
      45             :                                               do_stress_diagonal_numer,&
      46             :                                               do_stress_numerical
      47             :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      48             :                                               section_vals_type,&
      49             :                                               section_vals_val_get
      50             :    USE kinds,                           ONLY: default_string_length,&
      51             :                                               dp
      52             :    USE message_passing,                 ONLY: mp_para_env_type
      53             :    USE particle_methods,                ONLY: write_fist_particle_coordinates,&
      54             :                                               write_qs_particle_coordinates
      55             :    USE particle_types,                  ONLY: particle_type
      56             :    USE qs_environment_types,            ONLY: get_qs_env
      57             :    USE qs_kind_types,                   ONLY: qs_kind_type
      58             :    USE string_utilities,                ONLY: uppercase
      59             :    USE virial_types,                    ONLY: virial_set,&
      60             :                                               virial_type
      61             : #include "./base/base_uses.f90"
      62             : 
      63             :    IMPLICIT NONE
      64             :    PRIVATE
      65             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp2k_debug'
      66             : 
      67             :    PUBLIC :: cp2k_debug_energy_and_forces
      68             : 
      69             : CONTAINS
      70             : 
      71             : ! **************************************************************************************************
      72             : !> \brief ...
      73             : !> \param force_env ...
      74             : ! **************************************************************************************************
      75         424 :    SUBROUTINE cp2k_debug_energy_and_forces(force_env)
      76             : 
      77             :       TYPE(force_env_type), POINTER                      :: force_env
      78             : 
      79             :       CHARACTER(LEN=3)                                   :: cval1
      80             :       CHARACTER(LEN=3*default_string_length)             :: message
      81             :       CHARACTER(LEN=60)                                  :: line
      82         424 :       CHARACTER(LEN=80), DIMENSION(:), POINTER           :: cval2
      83             :       CHARACTER(LEN=default_string_length)               :: description
      84             :       INTEGER                                            :: i, ip, irep, iw, j, k, np, nrep, &
      85             :                                                             stress_tensor
      86             :       LOGICAL                                            :: check_failed, debug_dipole, &
      87             :                                                             debug_forces, debug_polar, &
      88             :                                                             debug_stress_tensor, skip, &
      89             :                                                             stop_on_mismatch
      90         424 :       LOGICAL, ALLOCATABLE, DIMENSION(:, :)              :: do_dof_atom_coor
      91             :       LOGICAL, DIMENSION(3)                              :: do_dof_dipole
      92             :       REAL(KIND=dp)                                      :: amplitude, dd, de, derr, difference, dx, &
      93             :                                                             eps_no_error_check, errmax, maxerr, &
      94             :                                                             std_value, sum_of_differences
      95             :       REAL(KIND=dp), DIMENSION(2)                        :: numer_energy
      96             :       REAL(KIND=dp), DIMENSION(3)                        :: dipole_moment, dipole_numer, err, &
      97             :                                                             my_maxerr, poldir
      98             :       REAL(KIND=dp), DIMENSION(3, 2)                     :: dipn
      99             :       REAL(KIND=dp), DIMENSION(3, 3)                     :: polar_analytic, polar_numeric
     100             :       REAL(KIND=dp), DIMENSION(9)                        :: pvals
     101         424 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: analyt_forces, numer_forces
     102             :       TYPE(cell_type), POINTER                           :: cell
     103             :       TYPE(cp_logger_type), POINTER                      :: logger
     104             :       TYPE(cp_result_type), POINTER                      :: results
     105             :       TYPE(cp_subsys_type), POINTER                      :: subsys
     106             :       TYPE(dft_control_type), POINTER                    :: dft_control
     107             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     108         424 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     109         424 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     110             :       TYPE(section_vals_type), POINTER                   :: root_section, subsys_section
     111             : 
     112         424 :       NULLIFY (analyt_forces, numer_forces, subsys, particles)
     113             : 
     114         424 :       root_section => force_env%root_section
     115             : 
     116         424 :       CALL force_env_get(force_env, para_env=para_env, subsys=subsys, cell=cell)
     117             :       subsys_section => section_vals_get_subs_vals(force_env%force_env_section, &
     118         424 :                                                    "SUBSYS")
     119             : 
     120             :       CALL section_vals_val_get(root_section, "DEBUG%DEBUG_STRESS_TENSOR", &
     121         424 :                                 l_val=debug_stress_tensor)
     122             :       CALL section_vals_val_get(root_section, "DEBUG%DEBUG_FORCES", &
     123         424 :                                 l_val=debug_forces)
     124             :       CALL section_vals_val_get(root_section, "DEBUG%DEBUG_DIPOLE", &
     125         424 :                                 l_val=debug_dipole)
     126             :       CALL section_vals_val_get(root_section, "DEBUG%DEBUG_POLARIZABILITY", &
     127         424 :                                 l_val=debug_polar)
     128             :       CALL section_vals_val_get(root_section, "DEBUG%DX", &
     129         424 :                                 r_val=dx)
     130             :       CALL section_vals_val_get(root_section, "DEBUG%DE", &
     131         424 :                                 r_val=de)
     132             :       CALL section_vals_val_get(root_section, "DEBUG%CHECK_DIPOLE_DIRS", &
     133         424 :                                 c_val=cval1)
     134         424 :       dx = ABS(dx)
     135             :       CALL section_vals_val_get(root_section, "DEBUG%MAX_RELATIVE_ERROR", &
     136         424 :                                 r_val=maxerr)
     137             :       CALL section_vals_val_get(root_section, "DEBUG%EPS_NO_ERROR_CHECK", &
     138         424 :                                 r_val=eps_no_error_check)
     139         424 :       eps_no_error_check = MAX(eps_no_error_check, EPSILON(0.0_dp))
     140             :       CALL section_vals_val_get(root_section, "DEBUG%STOP_ON_MISMATCH", &
     141         424 :                                 l_val=stop_on_mismatch)
     142             : 
     143             :       ! set active DOF
     144         424 :       CALL uppercase(cval1)
     145         424 :       do_dof_dipole(1) = (INDEX(cval1, "X") /= 0)
     146         424 :       do_dof_dipole(2) = (INDEX(cval1, "Y") /= 0)
     147         424 :       do_dof_dipole(3) = (INDEX(cval1, "Z") /= 0)
     148         424 :       NULLIFY (cval2)
     149         424 :       IF (debug_forces) THEN
     150         262 :          np = subsys%particles%n_els
     151         786 :          ALLOCATE (do_dof_atom_coor(3, np))
     152         262 :          CALL section_vals_val_get(root_section, "DEBUG%CHECK_ATOM_FORCE", n_rep_val=nrep)
     153         262 :          IF (nrep > 0) THEN
     154         674 :             do_dof_atom_coor = .FALSE.
     155         102 :             DO irep = 1, nrep
     156             :                CALL section_vals_val_get(root_section, "DEBUG%CHECK_ATOM_FORCE", i_rep_val=irep, &
     157          52 :                                          c_vals=cval2)
     158          52 :                READ (cval2(1), FMT="(I10)") k
     159          52 :                CALL uppercase(cval2(2))
     160          52 :                do_dof_atom_coor(1, k) = (INDEX(cval2(2), "X") /= 0)
     161          52 :                do_dof_atom_coor(2, k) = (INDEX(cval2(2), "Y") /= 0)
     162         102 :                do_dof_atom_coor(3, k) = (INDEX(cval2(2), "Z") /= 0)
     163             :             END DO
     164             :          ELSE
     165        3996 :             do_dof_atom_coor = .TRUE.
     166             :          END IF
     167             :       END IF
     168             : 
     169         424 :       logger => cp_get_default_logger()
     170             :       iw = cp_print_key_unit_nr(logger, root_section, "DEBUG%PROGRAM_RUN_INFO", &
     171         424 :                                 extension=".log")
     172         424 :       IF (debug_stress_tensor) THEN
     173             :          ! To debug stress tensor the stress tensor calculation must be
     174             :          ! first enabled..
     175             :          CALL section_vals_val_get(force_env%force_env_section, "STRESS_TENSOR", &
     176         166 :                                    i_val=stress_tensor)
     177         166 :          skip = .FALSE.
     178           0 :          SELECT CASE (stress_tensor)
     179             :          CASE (do_stress_analytical, do_stress_diagonal_anal)
     180             :             ! OK
     181             :          CASE (do_stress_numerical, do_stress_diagonal_numer)
     182             :             ! Nothing to check
     183             :             CALL cp_warn(__LOCATION__, "Numerical stress tensor was requested in "// &
     184           0 :                          "the FORCE_EVAL section. Nothing to debug!")
     185         114 :             skip = .TRUE.
     186             :          CASE DEFAULT
     187             :             CALL cp_warn(__LOCATION__, "Stress tensor calculation was not enabled in "// &
     188         114 :                          "the FORCE_EVAL section. Nothing to debug!")
     189         166 :             skip = .TRUE.
     190             :          END SELECT
     191             : 
     192             :          IF (.NOT. skip) THEN
     193             : 
     194             :             BLOCK
     195             :                TYPE(virial_type) :: virial_analytical, virial_numerical
     196             :                TYPE(virial_type), POINTER :: virial
     197             : 
     198             :                ! Compute the analytical stress tensor
     199          52 :                CALL cp_subsys_get(subsys, virial=virial)
     200          52 :                CALL virial_set(virial, pv_numer=.FALSE.)
     201             :                CALL force_env_calc_energy_force(force_env, &
     202             :                                                 calc_force=.TRUE., &
     203          52 :                                                 calc_stress_tensor=.TRUE.)
     204             : 
     205             :                ! Retrieve the analytical virial
     206          52 :                virial_analytical = virial
     207             : 
     208             :                ! Debug stress tensor (numerical vs analytical)
     209          52 :                CALL virial_set(virial, pv_numer=.TRUE.)
     210          52 :                CALL force_env_calc_num_pressure(force_env, dx=dx)
     211             : 
     212             :                ! Retrieve the numerical virial
     213          52 :                CALL cp_subsys_get(subsys, virial=virial)
     214          52 :                virial_numerical = virial
     215             : 
     216             :                ! Print results
     217          52 :                IF (iw > 0) THEN
     218             :                   WRITE (UNIT=iw, FMT="((T2,A))") &
     219          26 :                      "DEBUG| Numerical pv_virial [a.u.]"
     220             :                   WRITE (UNIT=iw, FMT="((T2,A,T21,3(1X,F19.12)))") &
     221         104 :                      ("DEBUG|", virial_numerical%pv_virial(i, 1:3), i=1, 3)
     222             :                   WRITE (UNIT=iw, FMT="(/,(T2,A))") &
     223          26 :                      "DEBUG| Analytical pv_virial [a.u.]"
     224             :                   WRITE (UNIT=iw, FMT="((T2,A,T21,3(1X,F19.12)))") &
     225         104 :                      ("DEBUG|", virial_analytical%pv_virial(i, 1:3), i=1, 3)
     226             :                   WRITE (UNIT=iw, FMT="(/,(T2,A))") &
     227          26 :                      "DEBUG| Difference pv_virial [a.u.]"
     228             :                   WRITE (UNIT=iw, FMT="((T2,A,T21,3(1X,F19.12)))") &
     229         338 :                      ("DEBUG|", virial_numerical%pv_virial(i, 1:3) - virial_analytical%pv_virial(i, 1:3), i=1, 3)
     230             :                   WRITE (UNIT=iw, FMT="(T2,A,T61,F20.12)") &
     231          26 :                      "DEBUG| Sum of differences", &
     232         364 :                      SUM(ABS(virial_numerical%pv_virial(:, :) - virial_analytical%pv_virial(:, :)))
     233             :                END IF
     234             : 
     235             :                ! Check and abort on failure
     236          52 :                check_failed = .FALSE.
     237          52 :                IF (iw > 0) THEN
     238             :                   WRITE (UNIT=iw, FMT="(/T2,A)") &
     239          26 :                      "DEBUG| Relative error pv_virial"
     240             :                   WRITE (UNIT=iw, FMT="(T2,A,T61,ES20.8)") &
     241          26 :                      "DEBUG| Threshold value for error check [a.u.]", eps_no_error_check
     242             :                END IF
     243         208 :                DO i = 1, 3
     244         156 :                   err(:) = 0.0_dp
     245         624 :                   DO k = 1, 3
     246         624 :                      IF (ABS(virial_analytical%pv_virial(i, k)) >= eps_no_error_check) THEN
     247             :                         err(k) = 100.0_dp*(virial_numerical%pv_virial(i, k) - virial_analytical%pv_virial(i, k))/ &
     248         424 :                                  virial_analytical%pv_virial(i, k)
     249         424 :                         WRITE (UNIT=line(20*(k - 1) + 1:20*k), FMT="(1X,F17.2,A2)") err(k), " %"
     250             :                      ELSE
     251          44 :                         WRITE (UNIT=line(20*(k - 1) + 1:20*k), FMT="(17X,A3)") "- %"
     252             :                      END IF
     253             :                   END DO
     254         156 :                   IF (iw > 0) THEN
     255             :                      WRITE (UNIT=iw, FMT="(T2,A,T21,A60)") &
     256          78 :                         "DEBUG|", line
     257             :                   END IF
     258         676 :                   IF (ANY(ABS(err(1:3)) > maxerr)) check_failed = .TRUE.
     259             :                END DO
     260          52 :                IF (iw > 0) THEN
     261             :                   WRITE (UNIT=iw, FMT="(T2,A,T61,F18.2,A2)") &
     262          26 :                      "DEBUG| Maximum accepted error", maxerr, " %"
     263             :                END IF
     264       23816 :                IF (check_failed) THEN
     265             :                   message = "A mismatch between the analytical and the numerical "// &
     266             :                             "stress tensor has been detected. Check the implementation "// &
     267           0 :                             "of the stress tensor"
     268           0 :                   IF (stop_on_mismatch) THEN
     269           0 :                      CPABORT(TRIM(message))
     270             :                   ELSE
     271           0 :                      CPWARN(TRIM(message))
     272             :                   END IF
     273             :                END IF
     274             :             END BLOCK
     275             :          END IF
     276             :       END IF
     277             : 
     278         424 :       IF (debug_forces) THEN
     279             :          ! Debug forces (numerical vs analytical)
     280         262 :          particles => subsys%particles%els
     281         428 :          SELECT CASE (force_env%in_use)
     282             :          CASE (use_qs_force)
     283         166 :             CALL get_qs_env(force_env%qs_env, qs_kind_set=qs_kind_set)
     284         166 :             CALL write_qs_particle_coordinates(particles, qs_kind_set, subsys_section, "DEBUG")
     285             :          CASE DEFAULT
     286         262 :             CALL write_fist_particle_coordinates(particles, subsys_section)
     287             :          END SELECT
     288             :          ! First evaluate energy and forces
     289             :          CALL force_env_calc_energy_force(force_env, &
     290             :                                           calc_force=.TRUE., &
     291         262 :                                           calc_stress_tensor=.FALSE.)
     292             :          ! Copy forces in array and start the numerical calculation
     293             :          IF (ASSOCIATED(analyt_forces)) DEALLOCATE (analyt_forces)
     294         262 :          np = subsys%particles%n_els
     295         786 :          ALLOCATE (analyt_forces(np, 3))
     296        1364 :          DO ip = 1, np
     297        4670 :             analyt_forces(ip, 1:3) = particles(ip)%f(1:3)
     298             :          END DO
     299             :          ! Loop on atoms and coordinates
     300             :          IF (ASSOCIATED(numer_forces)) DEALLOCATE (numer_forces)
     301         786 :          ALLOCATE (numer_forces(subsys%particles%n_els, 3))
     302        1364 :          Atom: DO ip = 1, np
     303        4408 :             Coord: DO k = 1, 3
     304        4408 :                IF (do_dof_atom_coor(k, ip)) THEN
     305        2890 :                   numer_energy = 0.0_dp
     306        2890 :                   std_value = particles(ip)%r(k)
     307        8670 :                   DO j = 1, 2
     308        5780 :                      particles(ip)%r(k) = std_value - (-1.0_dp)**j*dx
     309        8464 :                      SELECT CASE (force_env%in_use)
     310             :                      CASE (use_qs_force)
     311        2684 :                         CALL get_qs_env(force_env%qs_env, qs_kind_set=qs_kind_set)
     312        2684 :                         CALL write_qs_particle_coordinates(particles, qs_kind_set, subsys_section, "DEBUG")
     313             :                      CASE DEFAULT
     314        5780 :                         CALL write_fist_particle_coordinates(particles, subsys_section)
     315             :                      END SELECT
     316             :                      ! Compute energy
     317             :                      CALL force_env_calc_energy_force(force_env, &
     318             :                                                       calc_force=.FALSE., &
     319             :                                                       calc_stress_tensor=.FALSE., &
     320        5780 :                                                       consistent_energies=.TRUE.)
     321        8670 :                      CALL force_env_get(force_env, potential_energy=numer_energy(j))
     322             :                   END DO
     323        2890 :                   particles(ip)%r(k) = std_value
     324        2890 :                   numer_forces(ip, k) = -0.5_dp*(numer_energy(1) - numer_energy(2))/dx
     325        2890 :                   IF (iw > 0) THEN
     326             :                      WRITE (UNIT=iw, FMT="(/,T2,A,T17,A,F7.4,A,T34,A,F7.4,A,T52,A,T68,A)") &
     327        1445 :                         "DEBUG| Atom", "E("//ACHAR(119 + k)//" +", dx, ")", &
     328        1445 :                         "E("//ACHAR(119 + k)//" -", dx, ")", &
     329        2890 :                         "f(numerical)", "f(analytical)"
     330             :                      WRITE (UNIT=iw, FMT="(T2,A,I5,4(1X,F16.8))") &
     331        1445 :                         "DEBUG|", ip, numer_energy(1:2), numer_forces(ip, k), analyt_forces(ip, k)
     332             :                   END IF
     333             :                ELSE
     334         416 :                   numer_forces(ip, k) = 0.0_dp
     335             :                END IF
     336             :             END DO Coord
     337             :             ! Check analytical forces using the numerical forces as reference
     338        4408 :             my_maxerr = maxerr
     339        1102 :             err(1:3) = 0.0_dp
     340        4408 :             DO k = 1, 3
     341        4408 :                IF (do_dof_atom_coor(k, ip)) THEN
     342             :                   ! Calculate percentage but ignore very small force values
     343        2890 :                   IF (ABS(analyt_forces(ip, k)) >= eps_no_error_check) THEN
     344        2218 :                      err(k) = 100.0_dp*(numer_forces(ip, k) - analyt_forces(ip, k))/analyt_forces(ip, k)
     345             :                   END IF
     346             :                   ! Increase error tolerance for small force values
     347        2890 :                   IF (ABS(analyt_forces(ip, k)) <= 0.0001_dp) my_maxerr(k) = 5.0_dp*my_maxerr(k)
     348             :                ELSE
     349         416 :                   err(k) = 0.0_dp
     350             :                END IF
     351             :             END DO
     352        1102 :             IF (iw > 0) THEN
     353         755 :                IF (ANY(do_dof_atom_coor(1:3, ip))) THEN
     354             :                   WRITE (UNIT=iw, FMT="(/,T2,A)") &
     355         499 :                      "DEBUG| Atom  Coordinate   f(numerical)   f(analytical)   Difference   Error [%]"
     356             :                END IF
     357        2204 :                DO k = 1, 3
     358        2204 :                   IF (do_dof_atom_coor(k, ip)) THEN
     359        1445 :                      difference = analyt_forces(ip, k) - numer_forces(ip, k)
     360        1445 :                      IF (ABS(analyt_forces(ip, k)) >= eps_no_error_check) THEN
     361             :                         WRITE (UNIT=iw, FMT="(T2,A,I5,T19,A1,T26,F14.8,T42,F14.8,T57,F12.8,T71,F10.2)") &
     362        1109 :                            "DEBUG|", ip, ACHAR(119 + k), numer_forces(ip, k), analyt_forces(ip, k), difference, err(k)
     363             :                      ELSE
     364             :                         WRITE (UNIT=iw, FMT="(T2,A,I5,T19,A1,T26,F14.8,T42,F14.8,T57,F12.8,T80,A1)") &
     365         336 :                            "DEBUG|", ip, ACHAR(119 + k), numer_forces(ip, k), analyt_forces(ip, k), difference, "-"
     366             :                      END IF
     367             :                   END IF
     368             :                END DO
     369             :             END IF
     370        4670 :             IF (ANY(ABS(err(1:3)) > my_maxerr(1:3))) THEN
     371             :                message = "A mismatch between analytical and numerical forces "// &
     372             :                          "has been detected. Check the implementation of the "// &
     373           0 :                          "analytical force calculation"
     374           0 :                IF (stop_on_mismatch) THEN
     375           0 :                   CPABORT(message)
     376             :                ELSE
     377           0 :                   CPWARN(message)
     378             :                END IF
     379             :             END IF
     380             :          END DO Atom
     381             :          ! Print summary
     382         262 :          IF (iw > 0) THEN
     383             :             WRITE (UNIT=iw, FMT="(/,(T2,A))") &
     384         131 :                "DEBUG|======================== BEGIN OF SUMMARY ===============================", &
     385         262 :                "DEBUG| Atom  Coordinate   f(numerical)   f(analytical)   Difference   Error [%]"
     386         131 :             sum_of_differences = 0.0_dp
     387         131 :             errmax = 0.0_dp
     388         682 :             DO ip = 1, np
     389         551 :                err(1:3) = 0.0_dp
     390        2335 :                DO k = 1, 3
     391        2204 :                   IF (do_dof_atom_coor(k, ip)) THEN
     392        1445 :                      difference = analyt_forces(ip, k) - numer_forces(ip, k)
     393        1445 :                      IF (ABS(analyt_forces(ip, k)) >= eps_no_error_check) THEN
     394        1109 :                         err(k) = 100_dp*(numer_forces(ip, k) - analyt_forces(ip, k))/analyt_forces(ip, k)
     395        1109 :                         errmax = MAX(errmax, ABS(err(k)))
     396             :                         WRITE (UNIT=iw, FMT="(T2,A,I5,T19,A1,T26,F14.8,T42,F14.8,T57,F12.8,T71,F10.2)") &
     397        1109 :                            "DEBUG|", ip, ACHAR(119 + k), numer_forces(ip, k), analyt_forces(ip, k), difference, err(k)
     398             :                      ELSE
     399             :                         WRITE (UNIT=iw, FMT="(T2,A,I5,T19,A1,T26,F14.8,T42,F14.8,T57,F12.8,T80,A1)") &
     400         336 :                            "DEBUG|", ip, ACHAR(119 + k), numer_forces(ip, k), analyt_forces(ip, k), difference, "-"
     401             :                      END IF
     402        1445 :                      sum_of_differences = sum_of_differences + ABS(difference)
     403             :                   END IF
     404             :                END DO
     405             :             END DO
     406             :             WRITE (UNIT=iw, FMT="(T2,A,T57,F12.8,T71,F10.2)") &
     407         131 :                "DEBUG| Sum of differences:", sum_of_differences, errmax
     408             :             WRITE (UNIT=iw, FMT="(T2,A)") &
     409         131 :                "DEBUG|======================== END OF SUMMARY ================================="
     410             :          END IF
     411             :          ! Release work storage
     412         262 :          IF (ASSOCIATED(analyt_forces)) DEALLOCATE (analyt_forces)
     413         262 :          IF (ASSOCIATED(numer_forces)) DEALLOCATE (numer_forces)
     414         262 :          DEALLOCATE (do_dof_atom_coor)
     415             :       END IF
     416             : 
     417         424 :       IF (debug_dipole) THEN
     418          78 :          IF (force_env%in_use == use_qs_force) THEN
     419          78 :             CALL get_qs_env(force_env%qs_env, dft_control=dft_control)
     420          78 :             poldir = (/0.0_dp, 0.0_dp, 1.0_dp/)
     421          78 :             amplitude = 0.0_dp
     422          78 :             CALL set_efield(dft_control, amplitude, poldir)
     423          78 :             CALL force_env_calc_energy_force(force_env, calc_force=.TRUE.)
     424          78 :             CALL get_qs_env(force_env%qs_env, results=results)
     425          78 :             description = "[DIPOLE]"
     426          78 :             IF (test_for_result(results, description=description)) THEN
     427          78 :                CALL get_results(results, description=description, values=dipole_moment)
     428             :             ELSE
     429           0 :                CALL cp_warn(__LOCATION__, "Debug of dipole moments needs DFT/PRINT/MOMENTS section enabled")
     430           0 :                CPABORT("DEBUG")
     431             :             END IF
     432          78 :             amplitude = de
     433         312 :             DO k = 1, 3
     434         312 :                IF (do_dof_dipole(k)) THEN
     435         166 :                   poldir = 0.0_dp
     436         166 :                   poldir(k) = 1.0_dp
     437         498 :                   DO j = 1, 2
     438        1328 :                      poldir = -1.0_dp*poldir
     439         332 :                      CALL set_efield(dft_control, amplitude, poldir)
     440         332 :                      CALL force_env_calc_energy_force(force_env, calc_force=.FALSE.)
     441         498 :                      CALL force_env_get(force_env, potential_energy=numer_energy(j))
     442             :                   END DO
     443         166 :                   dipole_numer(k) = 0.5_dp*(numer_energy(1) - numer_energy(2))/de
     444             :                ELSE
     445          68 :                   dipole_numer(k) = 0.0_dp
     446             :                END IF
     447             :             END DO
     448          78 :             IF (iw > 0) THEN
     449             :                WRITE (UNIT=iw, FMT="(/,(T2,A))") &
     450          39 :                   "DEBUG|========================= DIPOLE MOMENTS ================================", &
     451          78 :                   "DEBUG| Coordinate      D(numerical)    D(analytical)    Difference    Error [%]"
     452          39 :                err(1:3) = 0.0_dp
     453         156 :                DO k = 1, 3
     454         156 :                   IF (do_dof_dipole(k)) THEN
     455          83 :                      dd = dipole_moment(k) - dipole_numer(k)
     456          83 :                      IF (ABS(dipole_moment(k)) > eps_no_error_check) THEN
     457          40 :                         derr = 100._dp*dd/dipole_moment(k)
     458             :                         WRITE (UNIT=iw, FMT="(T2,A,T13,A1,T21,F16.8,T38,F16.8,T56,G12.3,T72,F9.3)") &
     459          40 :                            "DEBUG|", ACHAR(119 + k), dipole_numer(k), dipole_moment(k), dd, derr
     460             :                      ELSE
     461          43 :                         derr = 0.0_dp
     462             :                         WRITE (UNIT=iw, FMT="(T2,A,T13,A1,T21,F16.8,T38,F16.8,T56,G12.3)") &
     463          43 :                            "DEBUG|", ACHAR(119 + k), dipole_numer(k), dipole_moment(k), dd
     464             :                      END IF
     465          83 :                      err(k) = derr
     466             :                   ELSE
     467             :                      WRITE (UNIT=iw, FMT="(T2,A,T13,A1,T21,A16,T38,F16.8)") &
     468          34 :                         "DEBUG|", ACHAR(119 + k), "         skipped", dipole_moment(k)
     469             :                   END IF
     470             :                END DO
     471             :                WRITE (UNIT=iw, FMT="((T2,A))") &
     472          39 :                   "DEBUG|========================================================================="
     473         156 :                WRITE (UNIT=iw, FMT="(T2,A,T61,E20.12)") 'DIPOLE : CheckSum  =', SUM(dipole_moment)
     474         153 :                IF (ANY(ABS(err(1:3)) > maxerr)) THEN
     475             :                   message = "A mismatch between analytical and numerical dipoles "// &
     476             :                             "has been detected. Check the implementation of the "// &
     477           1 :                             "analytical dipole calculation"
     478           1 :                   IF (stop_on_mismatch) THEN
     479           0 :                      CPABORT(message)
     480             :                   ELSE
     481           1 :                      CPWARN(message)
     482             :                   END IF
     483             :                END IF
     484             :             END IF
     485             : 
     486             :          ELSE
     487           0 :             CALL cp_warn(__LOCATION__, "Debug of dipole moments only for Quickstep code available")
     488             :          END IF
     489             :       END IF
     490             : 
     491         424 :       IF (debug_polar) THEN
     492          52 :          IF (force_env%in_use == use_qs_force) THEN
     493          52 :             CALL get_qs_env(force_env%qs_env, dft_control=dft_control)
     494          52 :             poldir = (/0.0_dp, 0.0_dp, 1.0_dp/)
     495          52 :             amplitude = 0.0_dp
     496          52 :             CALL set_efield(dft_control, amplitude, poldir)
     497          52 :             CALL force_env_calc_energy_force(force_env, calc_force=.FALSE.)
     498          52 :             CALL get_qs_env(force_env%qs_env, results=results)
     499          52 :             description = "[POLAR]"
     500          52 :             IF (test_for_result(results, description=description)) THEN
     501          52 :                CALL get_results(results, description=description, values=pvals)
     502          52 :                polar_analytic(1:3, 1:3) = RESHAPE(pvals(1:9), (/3, 3/))
     503             :             ELSE
     504           0 :                CALL cp_warn(__LOCATION__, "Debug of polarizabilities needs PROPERTIES/LINRES/POLAR section enabled")
     505           0 :                CPABORT("DEBUG")
     506             :             END IF
     507          52 :             description = "[DIPOLE]"
     508          52 :             IF (.NOT. test_for_result(results, description=description)) THEN
     509           0 :                CALL cp_warn(__LOCATION__, "Debug of polarizabilities need DFT/PRINT/MOMENTS section enabled")
     510           0 :                CPABORT("DEBUG")
     511             :             END IF
     512          52 :             amplitude = de
     513         208 :             DO k = 1, 3
     514         156 :                poldir = 0.0_dp
     515         156 :                poldir(k) = 1.0_dp
     516         468 :                DO j = 1, 2
     517        1248 :                   poldir = -1.0_dp*poldir
     518         312 :                   CALL set_efield(dft_control, amplitude, poldir)
     519         312 :                   CALL force_env_calc_energy_force(force_env, calc_force=.FALSE., linres=.TRUE.)
     520         468 :                   CALL get_results(results, description=description, values=dipn(1:3, j))
     521             :                END DO
     522         676 :                polar_numeric(1:3, k) = 0.5_dp*(dipn(1:3, 2) - dipn(1:3, 1))/de
     523             :             END DO
     524          52 :             IF (iw > 0) THEN
     525             :                WRITE (UNIT=iw, FMT="(/,(T2,A))") &
     526          26 :                   "DEBUG|========================= POLARIZABILITY ================================", &
     527          52 :                   "DEBUG| Coordinates     P(numerical)    P(analytical)    Difference    Error [%]"
     528         104 :                DO k = 1, 3
     529         338 :                   DO j = 1, 3
     530         234 :                      dd = polar_analytic(k, j) - polar_numeric(k, j)
     531         312 :                      IF (ABS(polar_analytic(k, j)) > eps_no_error_check) THEN
     532         170 :                         derr = 100._dp*dd/polar_analytic(k, j)
     533             :                         WRITE (UNIT=iw, FMT="(T2,A,T12,A1,A1,T21,F16.8,T38,F16.8,T56,G12.3,T72,F9.3)") &
     534         170 :                            "DEBUG|", ACHAR(119 + k), ACHAR(119 + j), polar_numeric(k, j), polar_analytic(k, j), dd, derr
     535             :                      ELSE
     536             :                         WRITE (UNIT=iw, FMT="(T2,A,T12,A1,A1,T21,F16.8,T38,F16.8,T56,G12.3)") &
     537          64 :                            "DEBUG|", ACHAR(119 + k), ACHAR(119 + j), polar_numeric(k, j), polar_analytic(k, j), dd
     538             :                      END IF
     539             :                   END DO
     540             :                END DO
     541             :                WRITE (UNIT=iw, FMT="((T2,A))") &
     542          26 :                   "DEBUG|========================================================================="
     543         338 :                WRITE (UNIT=iw, FMT="(T2,A,T61,E20.12)") ' POLAR : CheckSum  =', SUM(polar_analytic)
     544             :             END IF
     545             :          ELSE
     546           0 :             CALL cp_warn(__LOCATION__, "Debug of polarizabilities only for Quickstep code available")
     547             :          END IF
     548             :       END IF
     549             : 
     550         424 :       CALL cp_print_key_finished_output(iw, logger, root_section, "DEBUG%PROGRAM_RUN_INFO")
     551             : 
     552         848 :    END SUBROUTINE cp2k_debug_energy_and_forces
     553             : 
     554             : ! **************************************************************************************************
     555             : !> \brief ...
     556             : !> \param dft_control ...
     557             : !> \param amplitude ...
     558             : !> \param poldir ...
     559             : ! **************************************************************************************************
     560         774 :    SUBROUTINE set_efield(dft_control, amplitude, poldir)
     561             :       TYPE(dft_control_type), POINTER                    :: dft_control
     562             :       REAL(KIND=dp), INTENT(IN)                          :: amplitude
     563             :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: poldir
     564             : 
     565         774 :       IF (dft_control%apply_efield) THEN
     566         746 :          dft_control%efield_fields(1)%efield%strength = amplitude
     567        2984 :          dft_control%efield_fields(1)%efield%polarisation(1:3) = poldir(1:3)
     568          28 :       ELSEIF (dft_control%apply_period_efield) THEN
     569          28 :          dft_control%period_efield%strength = amplitude
     570         112 :          dft_control%period_efield%polarisation(1:3) = poldir(1:3)
     571             :       ELSE
     572           0 :          CPABORT("No EFIELD definition available")
     573             :       END IF
     574             : 
     575         774 :    END SUBROUTINE set_efield
     576             : 
     577             : END MODULE cp2k_debug

Generated by: LCOV version 1.15