LCOV - code coverage report
Current view: top level - src - qmmm_image_charge.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:4c33f95) Lines: 376 418 90.0 %
Date: 2025-01-30 06:53:08 Functions: 16 17 94.1 %

          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 Routines for image charge calculation within QM/MM
      10             : !> \par History
      11             : !>      12.2011 created
      12             : !> \author Dorothea Golze
      13             : ! **************************************************************************************************
      14             : MODULE qmmm_image_charge
      15             :    USE ao_util,                         ONLY: exp_radius_very_extended
      16             :    USE cell_types,                      ONLY: cell_type,&
      17             :                                               pbc
      18             :    USE cp_control_types,                ONLY: dft_control_type
      19             :    USE cp_eri_mme_interface,            ONLY: cp_eri_mme_param,&
      20             :                                               cp_eri_mme_update_local_counts
      21             :    USE cp_files,                        ONLY: close_file,&
      22             :                                               open_file
      23             :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      24             :                                               cp_logger_type
      25             :    USE cp_output_handling,              ONLY: cp_p_file,&
      26             :                                               cp_print_key_finished_output,&
      27             :                                               cp_print_key_generate_filename,&
      28             :                                               cp_print_key_should_output,&
      29             :                                               cp_print_key_unit_nr
      30             :    USE eri_mme_integrate,               ONLY: eri_mme_2c_integrate
      31             :    USE input_constants,                 ONLY: calc_always,&
      32             :                                               calc_once,&
      33             :                                               calc_once_done,&
      34             :                                               do_eri_gpw,&
      35             :                                               do_eri_mme
      36             :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      37             :                                               section_vals_type,&
      38             :                                               section_vals_val_get
      39             :    USE kinds,                           ONLY: default_path_length,&
      40             :                                               dp
      41             :    USE mathconstants,                   ONLY: pi
      42             :    USE mathlib,                         ONLY: invmat_symm
      43             :    USE memory_utilities,                ONLY: reallocate
      44             :    USE message_passing,                 ONLY: mp_para_env_type
      45             :    USE pw_env_types,                    ONLY: pw_env_get,&
      46             :                                               pw_env_type
      47             :    USE pw_methods,                      ONLY: pw_axpy,&
      48             :                                               pw_integral_ab,&
      49             :                                               pw_scale,&
      50             :                                               pw_transfer,&
      51             :                                               pw_zero
      52             :    USE pw_poisson_methods,              ONLY: pw_poisson_solve
      53             :    USE pw_poisson_types,                ONLY: pw_poisson_type
      54             :    USE pw_pool_types,                   ONLY: pw_pool_type
      55             :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      56             :                                               pw_r3d_rs_type
      57             :    USE qmmm_types_low,                  ONLY: qmmm_env_qm_type
      58             :    USE qs_collocate_density,            ONLY: calculate_rho_metal,&
      59             :                                               calculate_rho_single_gaussian
      60             :    USE qs_energy_types,                 ONLY: qs_energy_type
      61             :    USE qs_environment_types,            ONLY: get_qs_env,&
      62             :                                               qs_environment_type
      63             :    USE qs_integrate_potential,          ONLY: integrate_pgf_product
      64             :    USE realspace_grid_types,            ONLY: realspace_grid_desc_type,&
      65             :                                               realspace_grid_type,&
      66             :                                               transfer_pw2rs
      67             :    USE util,                            ONLY: get_limit
      68             :    USE virial_types,                    ONLY: virial_type
      69             : #include "./base/base_uses.f90"
      70             : 
      71             :    IMPLICIT NONE
      72             :    PRIVATE
      73             : 
      74             :    LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
      75             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qmmm_image_charge'
      76             : 
      77             :    PUBLIC :: calculate_image_pot, &
      78             :              integrate_potential_devga_rspace, &
      79             :              conditional_calc_image_matrix, &
      80             :              add_image_pot_to_hartree_pot, &
      81             :              print_image_coefficients
      82             : 
      83             : !***
      84             : CONTAINS
      85             : ! **************************************************************************************************
      86             : !> \brief determines coefficients by solving image_matrix*coeff=-pot_const by
      87             : !>        Gaussian elimination or in an iterative fashion and calculates
      88             : !>        image/metal potential with these coefficients
      89             : !> \param v_hartree_rspace Hartree potential in real space
      90             : !> \param rho_hartree_gspace Kohn Sham density in reciprocal space
      91             : !> \param energy structure where energies are stored
      92             : !> \param qmmm_env qmmm environment
      93             : !> \param qs_env qs environment
      94             : ! **************************************************************************************************
      95          60 :    SUBROUTINE calculate_image_pot(v_hartree_rspace, rho_hartree_gspace, energy, &
      96             :                                   qmmm_env, qs_env)
      97             : 
      98             :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: v_hartree_rspace
      99             :       TYPE(pw_c1d_gs_type), INTENT(IN)                   :: rho_hartree_gspace
     100             :       TYPE(qs_energy_type), POINTER                      :: energy
     101             :       TYPE(qmmm_env_qm_type), POINTER                    :: qmmm_env
     102             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     103             : 
     104             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_image_pot'
     105             : 
     106             :       INTEGER                                            :: handle
     107             : 
     108          60 :       CALL timeset(routineN, handle)
     109             : 
     110          60 :       IF (qmmm_env%image_charge_pot%coeff_iterative) THEN
     111             :          !calculate preconditioner matrix for CG if necessary
     112          12 :          IF (qs_env%calc_image_preconditioner) THEN
     113           2 :             IF (qmmm_env%image_charge_pot%image_restart) THEN
     114             :                CALL restart_image_matrix(image_matrix=qs_env%image_matrix, &
     115           0 :                                          qs_env=qs_env, qmmm_env=qmmm_env)
     116             :             ELSE
     117             :                CALL calculate_image_matrix(image_matrix=qs_env%image_matrix, &
     118           2 :                                            qs_env=qs_env, qmmm_env=qmmm_env)
     119             :             END IF
     120             :          END IF
     121             :          CALL calc_image_coeff_iterative(v_hartree_rspace=v_hartree_rspace, &
     122             :                                          coeff=qs_env%image_coeff, qmmm_env=qmmm_env, &
     123          12 :                                          qs_env=qs_env)
     124             : 
     125             :       ELSE
     126             :          CALL calc_image_coeff_gaussalgorithm(v_hartree_rspace=v_hartree_rspace, &
     127             :                                               coeff=qs_env%image_coeff, qmmm_env=qmmm_env, &
     128          48 :                                               qs_env=qs_env)
     129             :       END IF
     130             : 
     131             :       ! calculate the image/metal potential with the optimized coefficients
     132          60 :       ALLOCATE (qs_env%ks_qmmm_env%v_metal_rspace)
     133             :       CALL calculate_potential_metal(v_metal_rspace= &
     134             :                                      qs_env%ks_qmmm_env%v_metal_rspace, coeff=qs_env%image_coeff, &
     135             :                                      rho_hartree_gspace=rho_hartree_gspace, &
     136          60 :                                      energy=energy, qs_env=qs_env)
     137             : 
     138          60 :       CALL timestop(handle)
     139             : 
     140          60 :    END SUBROUTINE calculate_image_pot
     141             : 
     142             : ! **************************************************************************************************
     143             : !> \brief determines coefficients by solving the linear set of equations
     144             : !>        image_matrix*coeff=-pot_const using a Gaussian elimination scheme
     145             : !> \param v_hartree_rspace Hartree potential in real space
     146             : !> \param coeff expansion coefficients of the image charge density, i.e.
     147             : !>        rho_metal=sum_a c_a*g_a
     148             : !> \param qmmm_env qmmm environment
     149             : !> \param qs_env qs environment
     150             : ! **************************************************************************************************
     151          48 :    SUBROUTINE calc_image_coeff_gaussalgorithm(v_hartree_rspace, coeff, qmmm_env, &
     152             :                                               qs_env)
     153             : 
     154             :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: v_hartree_rspace
     155             :       REAL(KIND=dp), DIMENSION(:), POINTER               :: coeff
     156             :       TYPE(qmmm_env_qm_type), POINTER                    :: qmmm_env
     157             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     158             : 
     159             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calc_image_coeff_gaussalgorithm'
     160             : 
     161             :       INTEGER                                            :: handle, info, natom
     162             :       REAL(KIND=dp)                                      :: eta, V0
     163             :       REAL(KIND=dp), DIMENSION(:), POINTER               :: pot_const
     164             : 
     165          48 :       CALL timeset(routineN, handle)
     166             : 
     167             :       NULLIFY (pot_const)
     168             : 
     169             :       !minus sign V0: account for the fact that v_hartree has the opposite sign
     170          48 :       V0 = -qmmm_env%image_charge_pot%V0
     171          48 :       eta = qmmm_env%image_charge_pot%eta
     172          48 :       natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
     173             : 
     174         144 :       ALLOCATE (pot_const(natom))
     175          48 :       IF (.NOT. ASSOCIATED(coeff)) THEN
     176          16 :          ALLOCATE (coeff(natom))
     177             :       END IF
     178         144 :       coeff = 0.0_dp
     179             : 
     180             :       CALL integrate_potential_ga_rspace(v_hartree_rspace, qmmm_env, qs_env, &
     181          48 :                                          pot_const)
     182             :       !add integral V0*ga(r)
     183         144 :       pot_const(:) = -pot_const(:) + V0*SQRT((pi/eta)**3)
     184             : 
     185             :       !solve linear system of equations T*coeff=-pot_const
     186             :       !LU factorization of T by DGETRF done in calculate_image_matrix
     187             :       CALL dgetrs('N', natom, 1, qs_env%image_matrix, natom, qs_env%ipiv, &
     188          48 :                   pot_const, natom, info)
     189          48 :       CPASSERT(info == 0)
     190             : 
     191         240 :       coeff = pot_const
     192             : 
     193          48 :       DEALLOCATE (pot_const)
     194             : 
     195          48 :       CALL timestop(handle)
     196             : 
     197          48 :    END SUBROUTINE calc_image_coeff_gaussalgorithm
     198             : 
     199             : ! **************************************************************************************************
     200             : !> \brief determines image coefficients iteratively
     201             : !> \param v_hartree_rspace Hartree potential in real space
     202             : !> \param coeff expansion coefficients of the image charge density, i.e.
     203             : !>        rho_metal=sum_a c_a*g_a
     204             : !> \param qmmm_env qmmm environment
     205             : !> \param qs_env qs environment
     206             : ! **************************************************************************************************
     207          12 :    SUBROUTINE calc_image_coeff_iterative(v_hartree_rspace, coeff, qmmm_env, &
     208             :                                          qs_env)
     209             : 
     210             :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: v_hartree_rspace
     211             :       REAL(KIND=dp), DIMENSION(:), POINTER               :: coeff
     212             :       TYPE(qmmm_env_qm_type), POINTER                    :: qmmm_env
     213             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     214             : 
     215             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calc_image_coeff_iterative'
     216             : 
     217             :       INTEGER                                            :: handle, iter_steps, natom, output_unit
     218             :       REAL(KIND=dp)                                      :: alpha, eta, rsnew, rsold, V0
     219          12 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: Ad, d, pot_const, r, vmetal_const, z
     220             :       TYPE(cp_logger_type), POINTER                      :: logger
     221             :       TYPE(pw_r3d_rs_type)                               :: auxpot_Ad_rspace, v_metal_rspace_guess
     222             :       TYPE(section_vals_type), POINTER                   :: input
     223             : 
     224          12 :       CALL timeset(routineN, handle)
     225             : 
     226          12 :       NULLIFY (pot_const, vmetal_const, logger, input)
     227          12 :       logger => cp_get_default_logger()
     228             : 
     229             :       !minus sign V0: account for the fact that v_hartree has the opposite sign
     230          12 :       V0 = -qmmm_env%image_charge_pot%V0
     231          12 :       eta = qmmm_env%image_charge_pot%eta
     232          12 :       natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
     233             : 
     234          36 :       ALLOCATE (pot_const(natom))
     235          24 :       ALLOCATE (vmetal_const(natom))
     236          24 :       ALLOCATE (r(natom))
     237          24 :       ALLOCATE (d(natom))
     238          24 :       ALLOCATE (z(natom))
     239          24 :       ALLOCATE (Ad(natom))
     240          12 :       IF (.NOT. ASSOCIATED(coeff)) THEN
     241           4 :          ALLOCATE (coeff(natom))
     242             :       END IF
     243             : 
     244             :       CALL integrate_potential_ga_rspace(v_hartree_rspace, qmmm_env, qs_env, &
     245          12 :                                          pot_const)
     246             : 
     247             :       !add integral V0*ga(r)
     248          36 :       pot_const(:) = -pot_const(:) + V0*SQRT((pi/eta)**3)
     249             : 
     250             :       !initial guess for coeff
     251          36 :       coeff = 1.0_dp
     252          36 :       d = 0.0_dp
     253          36 :       z = 0.0_dp
     254          36 :       r = 0.0_dp
     255          12 :       rsold = 0.0_dp
     256          12 :       rsnew = 0.0_dp
     257          12 :       iter_steps = 0
     258             : 
     259             :       !calculate first guess of image/metal potential
     260             :       CALL calculate_potential_metal(v_metal_rspace=v_metal_rspace_guess, &
     261          12 :                                      coeff=coeff, qs_env=qs_env)
     262             :       CALL integrate_potential_ga_rspace(potential=v_metal_rspace_guess, &
     263          12 :                                          qmmm_env=qmmm_env, qs_env=qs_env, int_res=vmetal_const)
     264             : 
     265             :       ! modify coefficients iteratively
     266          60 :       r = pot_const - vmetal_const
     267         276 :       z = MATMUL(qs_env%image_matrix, r)
     268          60 :       d = z
     269          36 :       rsold = DOT_PRODUCT(r, z)
     270             : 
     271           6 :       DO
     272             :          !calculate A*d
     273          54 :          Ad = 0.0_dp
     274             :          CALL calculate_potential_metal(v_metal_rspace= &
     275          18 :                                         auxpot_Ad_rspace, coeff=d, qs_env=qs_env)
     276             :          CALL integrate_potential_ga_rspace(potential= &
     277             :                                             auxpot_Ad_rspace, qmmm_env=qmmm_env, &
     278          18 :                                             qs_env=qs_env, int_res=Ad)
     279             : 
     280          54 :          alpha = rsold/DOT_PRODUCT(d, Ad)
     281          90 :          coeff = coeff + alpha*d
     282             : 
     283          90 :          r = r - alpha*Ad
     284         414 :          z = MATMUL(qs_env%image_matrix, r)
     285          54 :          rsnew = DOT_PRODUCT(r, z)
     286          18 :          iter_steps = iter_steps + 1
     287             :          ! SQRT(rsnew) < 1.0E-08
     288          18 :          IF (rsnew < 1.0E-16) THEN
     289          12 :             CALL auxpot_Ad_rspace%release()
     290             :             EXIT
     291             :          END IF
     292          30 :          d = z + rsnew/rsold*d
     293           6 :          rsold = rsnew
     294          24 :          CALL auxpot_Ad_rspace%release()
     295             :       END DO
     296             : 
     297             :       ! print iteration info
     298             :       CALL get_qs_env(qs_env=qs_env, &
     299          12 :                       input=input)
     300             :       output_unit = cp_print_key_unit_nr(logger, input, &
     301             :                                          "QMMM%PRINT%PROGRAM_RUN_INFO", &
     302          12 :                                          extension=".qmmmLog")
     303          12 :       IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T3,A,T74,I7)") &
     304           6 :          "Number of iteration steps for determination of image coefficients:", iter_steps
     305             :       CALL cp_print_key_finished_output(output_unit, logger, input, &
     306          12 :                                         "QMMM%PRINT%PROGRAM_RUN_INFO")
     307             : 
     308          12 :       IF (iter_steps .LT. 25) THEN
     309          12 :          qs_env%calc_image_preconditioner = .FALSE.
     310             :       ELSE
     311           0 :          qs_env%calc_image_preconditioner = .TRUE.
     312             :       END IF
     313             : 
     314          12 :       CALL v_metal_rspace_guess%release()
     315          12 :       DEALLOCATE (pot_const)
     316          12 :       DEALLOCATE (vmetal_const)
     317          12 :       DEALLOCATE (r)
     318          12 :       DEALLOCATE (d, z)
     319          12 :       DEALLOCATE (Ad)
     320             : 
     321          12 :       CALL timestop(handle)
     322             : 
     323          24 :    END SUBROUTINE calc_image_coeff_iterative
     324             : 
     325             : ! ****************************************************************************
     326             : !> \brief calculates the integral V(r)*ga(r)
     327             : !> \param potential any potential
     328             : !> \param qmmm_env qmmm environment
     329             : !> \param qs_env qs environment
     330             : !> \param int_res result of the integration
     331             : !> \param atom_num atom index, needed when calculating image_matrix
     332             : !> \param atom_num_ref index of reference atom, needed when calculating
     333             : !>        image_matrix
     334             : ! **************************************************************************************************
     335          98 :    SUBROUTINE integrate_potential_ga_rspace(potential, qmmm_env, qs_env, int_res, &
     336             :                                             atom_num, atom_num_ref)
     337             : 
     338             :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: potential
     339             :       TYPE(qmmm_env_qm_type), POINTER                    :: qmmm_env
     340             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     341             :       REAL(KIND=dp), DIMENSION(:), POINTER               :: int_res
     342             :       INTEGER, INTENT(IN), OPTIONAL                      :: atom_num, atom_num_ref
     343             : 
     344             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'integrate_potential_ga_rspace'
     345             : 
     346             :       INTEGER                                            :: atom_a, atom_b, atom_ref, handle, iatom, &
     347             :                                                             j, k, natom, npme
     348          98 :       INTEGER, DIMENSION(:), POINTER                     :: cores
     349             :       REAL(KIND=dp)                                      :: eps_rho_rspace, radius
     350             :       REAL(KIND=dp), DIMENSION(3)                        :: ra
     351          98 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: hab
     352             :       TYPE(cell_type), POINTER                           :: cell
     353             :       TYPE(dft_control_type), POINTER                    :: dft_control
     354             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     355             :       TYPE(pw_env_type), POINTER                         :: pw_env
     356             :       TYPE(realspace_grid_desc_type), POINTER            :: auxbas_rs_desc
     357             :       TYPE(realspace_grid_type), POINTER                 :: rs_v
     358             : 
     359          98 :       CALL timeset(routineN, handle)
     360             : 
     361          98 :       NULLIFY (cores, hab, cell, auxbas_rs_desc, pw_env, para_env, &
     362          98 :                dft_control, rs_v)
     363          98 :       ALLOCATE (hab(1, 1))
     364             : 
     365          98 :       CALL get_qs_env(qs_env=qs_env, pw_env=pw_env)
     366             :       CALL pw_env_get(pw_env=pw_env, auxbas_rs_desc=auxbas_rs_desc, &
     367          98 :                       auxbas_rs_grid=rs_v)
     368          98 :       CALL transfer_pw2rs(rs_v, potential)
     369             : 
     370             :       CALL get_qs_env(qs_env=qs_env, &
     371             :                       cell=cell, &
     372             :                       dft_control=dft_control, &
     373          98 :                       para_env=para_env, pw_env=pw_env)
     374             : 
     375          98 :       eps_rho_rspace = dft_control%qs_control%eps_rho_rspace
     376             : 
     377          98 :       natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
     378          98 :       k = 1
     379          98 :       IF (PRESENT(atom_num)) k = atom_num
     380             : 
     381          98 :       CALL reallocate(cores, 1, natom - k + 1)
     382         294 :       int_res = 0.0_dp
     383          98 :       npme = 0
     384         290 :       cores = 0
     385             : 
     386         290 :       DO iatom = k, natom
     387         290 :          IF (rs_v%desc%parallel .AND. .NOT. rs_v%desc%distributed) THEN
     388             :             ! replicated realspace grid, split the atoms up between procs
     389         192 :             IF (MODULO(iatom, rs_v%desc%group_size) == rs_v%desc%my_pos) THEN
     390          96 :                npme = npme + 1
     391          96 :                cores(npme) = iatom
     392             :             END IF
     393             :          ELSE
     394           0 :             npme = npme + 1
     395           0 :             cores(npme) = iatom
     396             :          END IF
     397             :       END DO
     398             : 
     399         194 :       DO j = 1, npme
     400             : 
     401          96 :          iatom = cores(j)
     402          96 :          atom_a = qmmm_env%image_charge_pot%image_mm_list(iatom)
     403             : 
     404          96 :          IF (PRESENT(atom_num) .AND. PRESENT(atom_num_ref)) THEN
     405             :             ! shift the function since potential only calculate for ref atom
     406           6 :             atom_b = qmmm_env%image_charge_pot%image_mm_list(k)
     407           6 :             atom_ref = qmmm_env%image_charge_pot%image_mm_list(atom_num_ref)
     408             :             ra(:) = pbc(qmmm_env%image_charge_pot%particles_all(atom_a)%r, cell) &
     409             :                     - pbc(qmmm_env%image_charge_pot%particles_all(atom_b)%r, cell) &
     410          24 :                     + pbc(qmmm_env%image_charge_pot%particles_all(atom_ref)%r, cell)
     411             : 
     412             :          ELSE
     413          90 :             ra(:) = pbc(qmmm_env%image_charge_pot%particles_all(atom_a)%r, cell)
     414             :          END IF
     415             : 
     416          96 :          hab(1, 1) = 0.0_dp
     417             : 
     418             :          radius = exp_radius_very_extended(la_min=0, la_max=0, lb_min=0, lb_max=0, &
     419             :                                            ra=ra, rb=ra, rp=ra, &
     420             :                                            zetp=qmmm_env%image_charge_pot%eta, eps=eps_rho_rspace, &
     421          96 :                                            prefactor=1.0_dp, cutoff=1.0_dp)
     422             : 
     423             :          CALL integrate_pgf_product(0, qmmm_env%image_charge_pot%eta, 0, &
     424             :                                     0, 0.0_dp, 0, ra, (/0.0_dp, 0.0_dp, 0.0_dp/), &
     425             :                                     rs_v, hab, o1=0, o2=0, &
     426             :                                     radius=radius, calculate_forces=.FALSE., &
     427          96 :                                     use_subpatch=.TRUE., subpatch_pattern=0)
     428             : 
     429         194 :          int_res(iatom) = hab(1, 1)
     430             : 
     431             :       END DO
     432             : 
     433         490 :       CALL para_env%sum(int_res)
     434             : 
     435          98 :       DEALLOCATE (hab, cores)
     436             : 
     437          98 :       CALL timestop(handle)
     438             : 
     439          98 :    END SUBROUTINE integrate_potential_ga_rspace
     440             : 
     441             : ! **************************************************************************************************
     442             : !> \brief calculates the image forces on the MM atoms
     443             : !> \param potential any potential, in this case: Hartree potential
     444             : !> \param coeff expansion coefficients of the image charge density, i.e.
     445             : !>        rho_metal=sum_a c_a*g_a
     446             : !> \param forces structure storing the force contribution of the image charges
     447             : !>        for the metal (MM) atoms
     448             : !> \param qmmm_env qmmm environment
     449             : !> \param qs_env qs environment
     450             : ! **************************************************************************************************
     451          20 :    SUBROUTINE integrate_potential_devga_rspace(potential, coeff, forces, qmmm_env, &
     452             :                                                qs_env)
     453             : 
     454             :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: potential
     455             :       REAL(KIND=dp), DIMENSION(:), POINTER               :: coeff
     456             :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: forces
     457             :       TYPE(qmmm_env_qm_type), POINTER                    :: qmmm_env
     458             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     459             : 
     460             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'integrate_potential_devga_rspace'
     461             : 
     462             :       INTEGER                                            :: atom_a, handle, iatom, j, natom, npme
     463          20 :       INTEGER, DIMENSION(:), POINTER                     :: cores
     464             :       LOGICAL                                            :: use_virial
     465             :       REAL(KIND=dp)                                      :: eps_rho_rspace, radius
     466             :       REAL(KIND=dp), DIMENSION(3)                        :: force_a, force_b, ra
     467          20 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: hab, pab
     468             :       TYPE(cell_type), POINTER                           :: cell
     469             :       TYPE(dft_control_type), POINTER                    :: dft_control
     470             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     471             :       TYPE(pw_env_type), POINTER                         :: pw_env
     472             :       TYPE(realspace_grid_desc_type), POINTER            :: auxbas_rs_desc
     473             :       TYPE(realspace_grid_type), POINTER                 :: rs_v
     474             :       TYPE(virial_type), POINTER                         :: virial
     475             : 
     476          20 :       CALL timeset(routineN, handle)
     477             : 
     478          20 :       NULLIFY (cores, hab, pab, cell, auxbas_rs_desc, pw_env, para_env, &
     479          20 :                dft_control, rs_v, virial)
     480          20 :       use_virial = .FALSE.
     481             : 
     482          20 :       ALLOCATE (hab(1, 1))
     483          20 :       ALLOCATE (pab(1, 1))
     484             : 
     485          20 :       CALL get_qs_env(qs_env=qs_env, pw_env=pw_env)
     486             :       CALL pw_env_get(pw_env=pw_env, auxbas_rs_desc=auxbas_rs_desc, &
     487          20 :                       auxbas_rs_grid=rs_v)
     488          20 :       CALL transfer_pw2rs(rs_v, potential)
     489             : 
     490             :       CALL get_qs_env(qs_env=qs_env, &
     491             :                       cell=cell, &
     492             :                       dft_control=dft_control, &
     493             :                       para_env=para_env, pw_env=pw_env, &
     494          20 :                       virial=virial)
     495             : 
     496          20 :       use_virial = virial%pv_availability .AND. (.NOT. virial%pv_numer)
     497             : 
     498             :       IF (use_virial) THEN
     499           0 :          CPABORT("Virial not implemented for image charge method")
     500             :       END IF
     501             : 
     502          20 :       eps_rho_rspace = dft_control%qs_control%eps_rho_rspace
     503             : 
     504          20 :       natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
     505             : 
     506          20 :       IF (.NOT. ASSOCIATED(forces)) THEN
     507          30 :          ALLOCATE (forces(3, natom))
     508             :       END IF
     509             : 
     510         180 :       forces(:, :) = 0.0_dp
     511             : 
     512          20 :       CALL reallocate(cores, 1, natom)
     513          20 :       npme = 0
     514          60 :       cores = 0
     515             : 
     516          60 :       DO iatom = 1, natom
     517          60 :          IF (rs_v%desc%parallel .AND. .NOT. rs_v%desc%distributed) THEN
     518             :             ! replicated realspace grid, split the atoms up between procs
     519          40 :             IF (MODULO(iatom, rs_v%desc%group_size) == rs_v%desc%my_pos) THEN
     520          20 :                npme = npme + 1
     521          20 :                cores(npme) = iatom
     522             :             END IF
     523             :          ELSE
     524           0 :             npme = npme + 1
     525           0 :             cores(npme) = iatom
     526             :          END IF
     527             :       END DO
     528             : 
     529          40 :       DO j = 1, npme
     530             : 
     531          20 :          iatom = cores(j)
     532          20 :          atom_a = qmmm_env%image_charge_pot%image_mm_list(iatom)
     533          20 :          ra(:) = pbc(qmmm_env%image_charge_pot%particles_all(atom_a)%r, cell)
     534          20 :          hab(1, 1) = 0.0_dp
     535          20 :          pab(1, 1) = 1.0_dp
     536          20 :          force_a(:) = 0.0_dp
     537          20 :          force_b(:) = 0.0_dp
     538             : 
     539             :          radius = exp_radius_very_extended(la_min=0, la_max=0, lb_min=0, lb_max=0, &
     540             :                                            ra=ra, rb=ra, rp=ra, &
     541             :                                            zetp=qmmm_env%image_charge_pot%eta, eps=eps_rho_rspace, &
     542             :                                            pab=pab, o1=0, o2=0, &  ! without map_consistent
     543          20 :                                            prefactor=1.0_dp, cutoff=1.0_dp)
     544             : 
     545             :          CALL integrate_pgf_product(0, qmmm_env%image_charge_pot%eta, 0, &
     546             :                                     0, 0.0_dp, 0, ra, (/0.0_dp, 0.0_dp, 0.0_dp/), &
     547             :                                     rs_v, hab, pab, o1=0, o2=0, &
     548             :                                     radius=radius, calculate_forces=.TRUE., &
     549             :                                     force_a=force_a, force_b=force_b, use_subpatch=.TRUE., &
     550          20 :                                     subpatch_pattern=0)
     551             : 
     552          80 :          force_a(:) = coeff(iatom)*force_a(:)
     553         100 :          forces(:, iatom) = force_a(:)
     554             : 
     555             :       END DO
     556             : 
     557         340 :       CALL para_env%sum(forces)
     558             : 
     559          20 :       DEALLOCATE (hab, pab, cores)
     560             : 
     561             :       ! print info on gradients if wanted
     562          20 :       CALL print_gradients_image_atoms(forces, qs_env)
     563             : 
     564          20 :       CALL timestop(handle)
     565             : 
     566          20 :    END SUBROUTINE integrate_potential_devga_rspace
     567             : 
     568             : !****************************************************************************
     569             : !> \brief calculate image matrix T depending on constraints on image atoms
     570             : !>        in case coefficients are estimated not iteratively
     571             : !> \param qs_env qs environment
     572             : !> \param qmmm_env qmmm environment
     573             : ! **************************************************************************************************
     574          20 :    SUBROUTINE conditional_calc_image_matrix(qs_env, qmmm_env)
     575             : 
     576             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     577             :       TYPE(qmmm_env_qm_type), POINTER                    :: qmmm_env
     578             : 
     579          20 :       IF (.NOT. qmmm_env%image_charge_pot%coeff_iterative) THEN
     580          28 :          SELECT CASE (qmmm_env%image_charge_pot%state_image_matrix)
     581             :          CASE (calc_always)
     582             :             CALL calculate_image_matrix(image_matrix=qs_env%image_matrix, &
     583          12 :                                         ipiv=qs_env%ipiv, qs_env=qs_env, qmmm_env=qmmm_env)
     584             :          CASE (calc_once)
     585             :             !if all image atoms are fully constrained, calculate image matrix
     586             :             !only for the first MD or GEO_OPT step
     587             :             CALL calculate_image_matrix(image_matrix=qs_env%image_matrix, &
     588           2 :                                         ipiv=qs_env%ipiv, qs_env=qs_env, qmmm_env=qmmm_env)
     589           2 :             qmmm_env%image_charge_pot%state_image_matrix = calc_once_done
     590           2 :             IF (qmmm_env%center_qm_subsys0) &
     591             :                CALL cp_warn(__LOCATION__, &
     592             :                             "The image atoms are fully "// &
     593             :                             "constrained and the image matrix is only calculated once. "// &
     594           0 :                             "To be safe, set CENTER to NEVER ")
     595             :          CASE (calc_once_done)
     596             :             ! do nothing image matrix is stored
     597             :          CASE DEFAULT
     598          16 :             CPABORT("No initialization for image charges available?")
     599             :          END SELECT
     600             :       END IF
     601             : 
     602          20 :    END SUBROUTINE conditional_calc_image_matrix
     603             : 
     604             : !****************************************************************************
     605             : !> \brief calculate image matrix T
     606             : !> \param image_matrix matrix T
     607             : !> \param ipiv pivoting prior to DGETRS (for Gaussian elimination)
     608             : !> \param qs_env qs environment
     609             : !> \param qmmm_env qmmm environment
     610             : ! **************************************************************************************************
     611          16 :    SUBROUTINE calculate_image_matrix(image_matrix, ipiv, qs_env, qmmm_env)
     612             : 
     613             :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: image_matrix
     614             :       INTEGER, DIMENSION(:), OPTIONAL, POINTER           :: ipiv
     615             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     616             :       TYPE(qmmm_env_qm_type), POINTER                    :: qmmm_env
     617             : 
     618             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_image_matrix'
     619             : 
     620             :       INTEGER                                            :: handle, natom, output_unit, stat
     621             :       TYPE(cp_logger_type), POINTER                      :: logger
     622             :       TYPE(section_vals_type), POINTER                   :: input
     623             : 
     624          16 :       CALL timeset(routineN, handle)
     625          16 :       NULLIFY (input, logger)
     626             : 
     627          16 :       logger => cp_get_default_logger()
     628             : 
     629          16 :       natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
     630             : 
     631          16 :       IF (.NOT. ASSOCIATED(image_matrix)) THEN
     632          40 :          ALLOCATE (image_matrix(natom, natom))
     633             :       END IF
     634          16 :       IF (PRESENT(ipiv)) THEN
     635          14 :          IF (.NOT. ASSOCIATED(ipiv)) THEN
     636          24 :             ALLOCATE (ipiv(natom))
     637             :          END IF
     638          42 :          ipiv = 0
     639             :       END IF
     640             : 
     641          16 :       CALL get_qs_env(qs_env, input=input)
     642             :       !print info
     643             :       output_unit = cp_print_key_unit_nr(logger, input, &
     644             :                                          "QMMM%PRINT%PROGRAM_RUN_INFO", &
     645          16 :                                          extension=".qmmmLog")
     646          16 :       IF (qmmm_env%image_charge_pot%coeff_iterative) THEN
     647           2 :          IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T3,A)") &
     648           1 :             "Calculating image matrix"
     649             :       ELSE
     650          14 :          IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T2,A)") &
     651           7 :             "Calculating image matrix"
     652             :       END IF
     653             :       CALL cp_print_key_finished_output(output_unit, logger, input, &
     654          16 :                                         "QMMM%PRINT%PROGRAM_RUN_INFO")
     655             : 
     656             :       ! Calculate image matrix using either GPW or MME method
     657          20 :       SELECT CASE (qmmm_env%image_charge_pot%image_matrix_method)
     658             :       CASE (do_eri_gpw)
     659           4 :          CALL calculate_image_matrix_gpw(image_matrix, qs_env, qmmm_env)
     660             :       CASE (do_eri_mme)
     661          12 :          CALL calculate_image_matrix_mme(image_matrix, qs_env, qmmm_env)
     662             :       CASE DEFAULT
     663          16 :          CPABORT("Unknown method for calculating image matrix")
     664             :       END SELECT
     665             : 
     666          16 :       IF (qmmm_env%image_charge_pot%coeff_iterative) THEN
     667             :          !inversion --> preconditioner matrix for CG
     668           2 :          CALL invmat_symm(qs_env%image_matrix)
     669           2 :          CALL write_image_matrix(qs_env%image_matrix, qs_env)
     670             :       ELSE
     671             :          !pivoting prior to DGETRS (Gaussian elimination)
     672          14 :          IF (PRESENT(ipiv)) THEN
     673          14 :             CALL dgetrf(natom, natom, image_matrix, natom, ipiv, stat)
     674          14 :             CPASSERT(stat == 0)
     675             :          END IF
     676             :       END IF
     677             : 
     678          16 :       CALL timestop(handle)
     679             : 
     680          16 :    END SUBROUTINE calculate_image_matrix
     681             : 
     682             : ! **************************************************************************************************
     683             : !> \brief calculate image matrix T using GPW method
     684             : !> \param image_matrix matrix T
     685             : !> \param qs_env qs environment
     686             : !> \param qmmm_env qmmm environment
     687             : ! **************************************************************************************************
     688           4 :    SUBROUTINE calculate_image_matrix_gpw(image_matrix, qs_env, qmmm_env)
     689             :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: image_matrix
     690             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     691             :       TYPE(qmmm_env_qm_type), POINTER                    :: qmmm_env
     692             : 
     693             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_image_matrix_gpw'
     694             : 
     695             :       INTEGER                                            :: handle, iatom, iatom_ref, natom
     696             :       REAL(KIND=dp), DIMENSION(:), POINTER               :: int_res
     697             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     698             :       TYPE(pw_c1d_gs_type)                               :: rho_gb, vb_gspace
     699             :       TYPE(pw_env_type), POINTER                         :: pw_env
     700             :       TYPE(pw_poisson_type), POINTER                     :: poisson_env
     701             :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
     702             :       TYPE(pw_r3d_rs_type)                               :: vb_rspace
     703             : 
     704           4 :       CALL timeset(routineN, handle)
     705           4 :       NULLIFY (pw_env, auxbas_pw_pool, poisson_env, para_env, int_res)
     706             : 
     707           4 :       natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
     708          12 :       ALLOCATE (int_res(natom))
     709             : 
     710          28 :       image_matrix = 0.0_dp
     711             : 
     712           4 :       CALL get_qs_env(qs_env, pw_env=pw_env, para_env=para_env)
     713             : 
     714             :       CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool, &
     715           4 :                       poisson_env=poisson_env)
     716           4 :       CALL auxbas_pw_pool%create_pw(rho_gb)
     717           4 :       CALL auxbas_pw_pool%create_pw(vb_gspace)
     718           4 :       CALL auxbas_pw_pool%create_pw(vb_rspace)
     719             : 
     720             :       ! calculate vb only once for one reference atom
     721           4 :       iatom_ref = 1 !
     722             :       !collocate gaussian of reference MM atom on grid
     723           4 :       CALL pw_zero(rho_gb)
     724           4 :       CALL calculate_rho_single_gaussian(rho_gb, qs_env, iatom_ref)
     725             :       !calculate potential vb like hartree potential
     726           4 :       CALL pw_zero(vb_gspace)
     727           4 :       CALL pw_poisson_solve(poisson_env, rho_gb, vhartree=vb_gspace)
     728           4 :       CALL pw_zero(vb_rspace)
     729           4 :       CALL pw_transfer(vb_gspace, vb_rspace)
     730           4 :       CALL pw_scale(vb_rspace, vb_rspace%pw_grid%dvol)
     731             : 
     732          12 :       DO iatom = 1, natom
     733             :          !calculate integral vb_rspace*ga
     734          24 :          int_res = 0.0_dp
     735             :          CALL integrate_potential_ga_rspace(vb_rspace, qs_env%qmmm_env_qm, &
     736             :                                             qs_env, int_res, atom_num=iatom, &
     737           8 :                                             atom_num_ref=iatom_ref)
     738          40 :          image_matrix(iatom, iatom:natom) = int_res(iatom:natom)
     739          28 :          image_matrix(iatom + 1:natom, iatom) = int_res(iatom + 1:natom)
     740             :       END DO
     741             : 
     742           4 :       CALL vb_gspace%release()
     743           4 :       CALL vb_rspace%release()
     744           4 :       CALL rho_gb%release()
     745             : 
     746           4 :       DEALLOCATE (int_res)
     747             : 
     748           4 :       CALL timestop(handle)
     749           4 :    END SUBROUTINE calculate_image_matrix_gpw
     750             : 
     751             : ! **************************************************************************************************
     752             : !> \brief calculate image matrix T using MME (MiniMax-Ewald) method
     753             : !> \param image_matrix matrix T
     754             : !> \param qs_env qs environment
     755             : !> \param qmmm_env qmmm environment
     756             : ! **************************************************************************************************
     757          12 :    SUBROUTINE calculate_image_matrix_mme(image_matrix, qs_env, qmmm_env)
     758             :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: image_matrix
     759             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     760             :       TYPE(qmmm_env_qm_type), POINTER                    :: qmmm_env
     761             : 
     762             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_image_matrix_mme'
     763             : 
     764             :       INTEGER                                            :: atom_a, handle, iatom, natom
     765             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: zeta
     766             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: ra
     767             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     768             : 
     769          12 :       CALL timeset(routineN, handle)
     770          12 :       NULLIFY (para_env)
     771             : 
     772          12 :       natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
     773          60 :       ALLOCATE (zeta(natom), ra(3, natom))
     774             : 
     775          36 :       zeta(:) = qmmm_env%image_charge_pot%eta
     776             : 
     777          36 :       DO iatom = 1, natom
     778          24 :          atom_a = qmmm_env%image_charge_pot%image_mm_list(iatom)
     779         108 :          ra(:, iatom) = qmmm_env%image_charge_pot%particles_all(atom_a)%r(:)
     780             :       END DO
     781             : 
     782          12 :       CALL get_qs_env(qs_env, para_env=para_env)
     783             : 
     784             :       CALL integrate_s_mme(qmmm_env%image_charge_pot%eri_mme_param, &
     785          12 :                            zeta, zeta, ra, ra, image_matrix, para_env)
     786             : 
     787          12 :       CALL timestop(handle)
     788          24 :    END SUBROUTINE calculate_image_matrix_mme
     789             : 
     790             : ! **************************************************************************************************
     791             : !> \brief high-level integration routine for 2c integrals over s-type functions.
     792             : !>        Parallelization over pairs of functions.
     793             : !> \param param ...
     794             : !> \param zeta ...
     795             : !> \param zetb ...
     796             : !> \param ra ...
     797             : !> \param rb ...
     798             : !> \param hab ...
     799             : !> \param para_env ...
     800             : ! **************************************************************************************************
     801          12 :    SUBROUTINE integrate_s_mme(param, zeta, zetb, ra, rb, hab, para_env)
     802             :       TYPE(cp_eri_mme_param), INTENT(INOUT)              :: param
     803             :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: zeta, zetb
     804             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: ra, rb
     805             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: hab
     806             :       TYPE(mp_para_env_type), INTENT(IN), POINTER        :: para_env
     807             : 
     808             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'integrate_s_mme'
     809             : 
     810             :       INTEGER                                            :: G_count, handle, ipgf, ipgf_prod, jpgf, &
     811             :                                                             npgf_prod, npgfa, npgfb, R_count
     812             :       INTEGER, DIMENSION(2)                              :: limits
     813             :       REAL(KIND=dp), DIMENSION(3)                        :: rab
     814             : 
     815          12 :       CALL timeset(routineN, handle)
     816          12 :       G_count = 0; R_count = 0
     817             : 
     818          84 :       hab(:, :) = 0.0_dp
     819             : 
     820          12 :       npgfa = SIZE(zeta)
     821          12 :       npgfb = SIZE(zetb)
     822          12 :       npgf_prod = npgfa*npgfb ! total number of integrals
     823             : 
     824          12 :       limits = get_limit(npgf_prod, para_env%num_pe, para_env%mepos)
     825             : 
     826          36 :       DO ipgf_prod = limits(1), limits(2)
     827          24 :          ipgf = (ipgf_prod - 1)/npgfb + 1
     828          24 :          jpgf = MOD(ipgf_prod - 1, npgfb) + 1
     829          96 :          rab(:) = ra(:, ipgf) - rb(:, jpgf)
     830             :          CALL eri_mme_2c_integrate(param%par, 0, 0, 0, 0, zeta(ipgf), &
     831          36 :                                    zetb(jpgf), rab, hab, ipgf - 1, jpgf - 1, G_count=G_count, R_count=R_count)
     832             :       END DO
     833             : 
     834          12 :       CALL cp_eri_mme_update_local_counts(param, para_env, G_count_2c=G_count, R_count_2c=R_count)
     835         156 :       CALL para_env%sum(hab)
     836          12 :       CALL timestop(handle)
     837             : 
     838          12 :    END SUBROUTINE integrate_s_mme
     839             : 
     840             : ! **************************************************************************************************
     841             : !> \brief calculates potential of the metal (image potential) given a set of
     842             : !>        coefficients coeff
     843             : !> \param v_metal_rspace potential generated by rho_metal in real space
     844             : !> \param coeff expansion coefficients of the image charge density, i.e.
     845             : !>        rho_metal=sum_a c_a*g_a
     846             : !> \param rho_hartree_gspace Kohn Sham density in reciprocal space
     847             : !> \param energy structure where energies are stored
     848             : !> \param qs_env qs environment
     849             : ! **************************************************************************************************
     850         180 :    SUBROUTINE calculate_potential_metal(v_metal_rspace, coeff, rho_hartree_gspace, energy, &
     851             :                                         qs_env)
     852             : 
     853             :       TYPE(pw_r3d_rs_type), INTENT(OUT)                  :: v_metal_rspace
     854             :       REAL(KIND=dp), DIMENSION(:), POINTER               :: coeff
     855             :       TYPE(pw_c1d_gs_type), INTENT(IN), OPTIONAL         :: rho_hartree_gspace
     856             :       TYPE(qs_energy_type), OPTIONAL, POINTER            :: energy
     857             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     858             : 
     859             :       CHARACTER(len=*), PARAMETER :: routineN = 'calculate_potential_metal'
     860             : 
     861             :       INTEGER                                            :: handle
     862             :       REAL(KIND=dp)                                      :: en_external, en_vmetal_rhohartree, &
     863             :                                                             total_rho_metal
     864             :       TYPE(pw_c1d_gs_type)                               :: rho_metal, v_metal_gspace
     865             :       TYPE(pw_env_type), POINTER                         :: pw_env
     866             :       TYPE(pw_poisson_type), POINTER                     :: poisson_env
     867             :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
     868             : 
     869          90 :       CALL timeset(routineN, handle)
     870             : 
     871          90 :       NULLIFY (pw_env, auxbas_pw_pool, poisson_env)
     872          90 :       en_vmetal_rhohartree = 0.0_dp
     873          90 :       en_external = 0.0_dp
     874             : 
     875          90 :       CALL get_qs_env(qs_env=qs_env, pw_env=pw_env)
     876             :       CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool, &
     877          90 :                       poisson_env=poisson_env)
     878             : 
     879          90 :       CALL auxbas_pw_pool%create_pw(rho_metal)
     880             : 
     881          90 :       CALL auxbas_pw_pool%create_pw(v_metal_gspace)
     882             : 
     883          90 :       CALL auxbas_pw_pool%create_pw(v_metal_rspace)
     884             : 
     885          90 :       CALL pw_zero(rho_metal)
     886             :       CALL calculate_rho_metal(rho_metal, coeff, total_rho_metal=total_rho_metal, &
     887          90 :                                qs_env=qs_env)
     888             : 
     889          90 :       CALL pw_zero(v_metal_gspace)
     890             :       CALL pw_poisson_solve(poisson_env, rho_metal, &
     891          90 :                             vhartree=v_metal_gspace)
     892             : 
     893          90 :       IF (PRESENT(rho_hartree_gspace)) THEN
     894             :          en_vmetal_rhohartree = 0.5_dp*pw_integral_ab(v_metal_gspace, &
     895          60 :                                                       rho_hartree_gspace)
     896          60 :          en_external = qs_env%qmmm_env_qm%image_charge_pot%V0*total_rho_metal
     897          60 :          energy%image_charge = en_vmetal_rhohartree - 0.5_dp*en_external
     898             :          CALL print_image_energy_terms(en_vmetal_rhohartree, en_external, &
     899          60 :                                        total_rho_metal, qs_env)
     900             :       END IF
     901             : 
     902          90 :       CALL pw_zero(v_metal_rspace)
     903          90 :       CALL pw_transfer(v_metal_gspace, v_metal_rspace)
     904          90 :       CALL pw_scale(v_metal_rspace, v_metal_rspace%pw_grid%dvol)
     905          90 :       CALL v_metal_gspace%release()
     906          90 :       CALL rho_metal%release()
     907             : 
     908          90 :       CALL timestop(handle)
     909             : 
     910          90 :    END SUBROUTINE calculate_potential_metal
     911             : 
     912             : ! ****************************************************************************
     913             : !> \brief Add potential of metal (image charge pot) to Hartree Potential
     914             : !> \param v_hartree Hartree potential (in real space)
     915             : !> \param v_metal potential generated by rho_metal (in real space)
     916             : !> \param qs_env qs environment
     917             : ! **************************************************************************************************
     918          60 :    SUBROUTINE add_image_pot_to_hartree_pot(v_hartree, v_metal, qs_env)
     919             : 
     920             :       TYPE(pw_r3d_rs_type), INTENT(INOUT)                :: v_hartree
     921             :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: v_metal
     922             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     923             : 
     924             :       CHARACTER(len=*), PARAMETER :: routineN = 'add_image_pot_to_hartree_pot'
     925             : 
     926             :       INTEGER                                            :: handle, output_unit
     927             :       TYPE(cp_logger_type), POINTER                      :: logger
     928             :       TYPE(section_vals_type), POINTER                   :: input
     929             : 
     930          60 :       CALL timeset(routineN, handle)
     931             : 
     932          60 :       NULLIFY (input, logger)
     933          60 :       logger => cp_get_default_logger()
     934             : 
     935             :       !add image charge potential
     936          60 :       CALL pw_axpy(v_metal, v_hartree)
     937             : 
     938             :       ! print info
     939             :       CALL get_qs_env(qs_env=qs_env, &
     940          60 :                       input=input)
     941             :       output_unit = cp_print_key_unit_nr(logger, input, &
     942             :                                          "QMMM%PRINT%PROGRAM_RUN_INFO", &
     943          60 :                                          extension=".qmmmLog")
     944          60 :       IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T3,A)") &
     945          30 :          "Adding image charge potential to the Hartree potential."
     946             :       CALL cp_print_key_finished_output(output_unit, logger, input, &
     947          60 :                                         "QMMM%PRINT%PROGRAM_RUN_INFO")
     948             : 
     949          60 :       CALL timestop(handle)
     950             : 
     951          60 :    END SUBROUTINE add_image_pot_to_hartree_pot
     952             : 
     953             : !****************************************************************************
     954             : !> \brief writes image matrix T to file when used as preconditioner for
     955             : !>        calculating image coefficients iteratively
     956             : !> \param image_matrix matrix T
     957             : !> \param qs_env qs environment
     958             : ! **************************************************************************************************
     959           2 :    SUBROUTINE write_image_matrix(image_matrix, qs_env)
     960             : 
     961             :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: image_matrix
     962             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     963             : 
     964             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'write_image_matrix'
     965             : 
     966             :       CHARACTER(LEN=default_path_length)                 :: filename
     967             :       INTEGER                                            :: handle, rst_unit
     968             :       TYPE(cp_logger_type), POINTER                      :: logger
     969             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     970             :       TYPE(section_vals_type), POINTER                   :: print_key, qmmm_section
     971             : 
     972           2 :       CALL timeset(routineN, handle)
     973             : 
     974           2 :       NULLIFY (qmmm_section, print_key, logger, para_env)
     975           2 :       logger => cp_get_default_logger()
     976           2 :       rst_unit = -1
     977             : 
     978             :       CALL get_qs_env(qs_env=qs_env, para_env=para_env, &
     979           2 :                       input=qmmm_section)
     980             : 
     981             :       print_key => section_vals_get_subs_vals(qmmm_section, &
     982           2 :                                               "QMMM%PRINT%IMAGE_CHARGE_RESTART")
     983             : 
     984           2 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, &
     985             :                                            qmmm_section, "QMMM%PRINT%IMAGE_CHARGE_RESTART"), &
     986             :                 cp_p_file)) THEN
     987             : 
     988             :          rst_unit = cp_print_key_unit_nr(logger, qmmm_section, &
     989             :                                          "QMMM%PRINT%IMAGE_CHARGE_RESTART", &
     990             :                                          extension=".Image", &
     991             :                                          file_status="REPLACE", &
     992             :                                          file_action="WRITE", &
     993           2 :                                          file_form="UNFORMATTED")
     994             : 
     995           2 :          IF (rst_unit > 0) filename = cp_print_key_generate_filename(logger, &
     996             :                                                                      print_key, extension=".IMAGE", &
     997           1 :                                                                      my_local=.FALSE.)
     998             : 
     999           2 :          IF (rst_unit > 0) THEN
    1000           7 :             WRITE (rst_unit) image_matrix
    1001             :          END IF
    1002             : 
    1003             :          CALL cp_print_key_finished_output(rst_unit, logger, qmmm_section, &
    1004           2 :                                            "QMMM%PRINT%IMAGE_CHARGE_RESTART")
    1005             :       END IF
    1006             : 
    1007           2 :       CALL timestop(handle)
    1008             : 
    1009           2 :    END SUBROUTINE write_image_matrix
    1010             : 
    1011             : !****************************************************************************
    1012             : !> \brief restarts image matrix T when used as preconditioner for calculating
    1013             : !>        image coefficients iteratively
    1014             : !> \param image_matrix matrix T
    1015             : !> \param qs_env qs environment
    1016             : !> \param qmmm_env qmmm environment
    1017             : ! **************************************************************************************************
    1018           0 :    SUBROUTINE restart_image_matrix(image_matrix, qs_env, qmmm_env)
    1019             : 
    1020             :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: image_matrix
    1021             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1022             :       TYPE(qmmm_env_qm_type), POINTER                    :: qmmm_env
    1023             : 
    1024             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'restart_image_matrix'
    1025             : 
    1026             :       CHARACTER(LEN=default_path_length)                 :: image_filename
    1027             :       INTEGER                                            :: handle, natom, output_unit, rst_unit
    1028             :       LOGICAL                                            :: exist
    1029             :       TYPE(cp_logger_type), POINTER                      :: logger
    1030             :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1031             :       TYPE(section_vals_type), POINTER                   :: qmmm_section
    1032             : 
    1033           0 :       CALL timeset(routineN, handle)
    1034             : 
    1035           0 :       NULLIFY (qmmm_section, logger, para_env)
    1036           0 :       logger => cp_get_default_logger()
    1037           0 :       exist = .FALSE.
    1038           0 :       rst_unit = -1
    1039             : 
    1040           0 :       natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
    1041             : 
    1042           0 :       IF (.NOT. ASSOCIATED(image_matrix)) THEN
    1043           0 :          ALLOCATE (image_matrix(natom, natom))
    1044             :       END IF
    1045             : 
    1046           0 :       image_matrix = 0.0_dp
    1047             : 
    1048             :       CALL get_qs_env(qs_env=qs_env, para_env=para_env, &
    1049           0 :                       input=qmmm_section)
    1050             : 
    1051             :       CALL section_vals_val_get(qmmm_section, "QMMM%IMAGE_CHARGE%IMAGE_RESTART_FILE_NAME", &
    1052           0 :                                 c_val=image_filename)
    1053             : 
    1054           0 :       INQUIRE (FILE=image_filename, exist=exist)
    1055             : 
    1056           0 :       IF (exist) THEN
    1057           0 :          IF (para_env%is_source()) THEN
    1058             :             CALL open_file(file_name=image_filename, &
    1059             :                            file_status="OLD", &
    1060             :                            file_form="UNFORMATTED", &
    1061             :                            file_action="READ", &
    1062           0 :                            unit_number=rst_unit)
    1063             : 
    1064           0 :             READ (rst_unit) qs_env%image_matrix
    1065             :          END IF
    1066             : 
    1067           0 :          CALL para_env%bcast(qs_env%image_matrix)
    1068             : 
    1069           0 :          IF (para_env%is_source()) CALL close_file(unit_number=rst_unit)
    1070             : 
    1071             :          output_unit = cp_print_key_unit_nr(logger, qmmm_section, &
    1072             :                                             "QMMM%PRINT%PROGRAM_RUN_INFO", &
    1073           0 :                                             extension=".qmmmLog")
    1074           0 :          IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T3,A)") &
    1075           0 :             "Restarted image matrix"
    1076             :       ELSE
    1077           0 :          CPABORT("Restart file for image matrix not found")
    1078             :       END IF
    1079             : 
    1080           0 :       qmmm_env%image_charge_pot%image_restart = .FALSE.
    1081             : 
    1082           0 :       CALL timestop(handle)
    1083             : 
    1084           0 :    END SUBROUTINE restart_image_matrix
    1085             : 
    1086             : ! ****************************************************************************
    1087             : !> \brief Print info on image gradients on image MM atoms
    1088             : !> \param forces structure storing the force contribution of the image charges
    1089             : !>        for the metal (MM) atoms (actually these are only the gradients)
    1090             : !> \param qs_env qs environment
    1091             : ! **************************************************************************************************
    1092          20 :    SUBROUTINE print_gradients_image_atoms(forces, qs_env)
    1093             : 
    1094             :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: forces
    1095             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1096             : 
    1097             :       INTEGER                                            :: atom_a, iatom, natom, output_unit
    1098             :       REAL(KIND=dp), DIMENSION(3)                        :: sum_gradients
    1099             :       TYPE(cp_logger_type), POINTER                      :: logger
    1100             :       TYPE(section_vals_type), POINTER                   :: input
    1101             : 
    1102          20 :       NULLIFY (input, logger)
    1103          20 :       logger => cp_get_default_logger()
    1104             : 
    1105          20 :       sum_gradients = 0.0_dp
    1106          20 :       natom = SIZE(qs_env%qmmm_env_qm%image_charge_pot%image_mm_list)
    1107             : 
    1108          60 :       DO iatom = 1, natom
    1109         180 :          sum_gradients(:) = sum_gradients(:) + forces(:, iatom)
    1110             :       END DO
    1111             : 
    1112          20 :       CALL get_qs_env(qs_env=qs_env, input=input)
    1113             : 
    1114             :       output_unit = cp_print_key_unit_nr(logger, input, &
    1115          20 :                                          "QMMM%PRINT%DERIVATIVES", extension=".Log")
    1116          20 :       IF (output_unit > 0) THEN
    1117             :          WRITE (unit=output_unit, fmt="(/1X,A)") &
    1118           0 :             "Image gradients [a.u.] on MM image charge atoms after QMMM calculation: "
    1119             :          WRITE (unit=output_unit, fmt="(T4,A4,T27,A1,T50,A1,T74,A1)") &
    1120           0 :             "Atom", "X", "Y", "Z"
    1121           0 :          DO iatom = 1, natom
    1122           0 :             atom_a = qs_env%qmmm_env_qm%image_charge_pot%image_mm_list(iatom)
    1123             :             WRITE (unit=output_unit, fmt="(T2,I6,T22,ES12.5,T45,ES12.5,T69,ES12.5)") &
    1124           0 :                atom_a, forces(:, iatom)
    1125             :          END DO
    1126             : 
    1127           0 :          WRITE (unit=output_unit, fmt="(T2,A)") REPEAT("-", 79)
    1128             :          WRITE (unit=output_unit, fmt="(T2,A,T22,ES12.5,T45,ES12.5,T69,ES12.5)") &
    1129           0 :             "sum gradients:", sum_gradients
    1130           0 :          WRITE (unit=output_unit, fmt="(/)")
    1131             :       END IF
    1132             : 
    1133             :       CALL cp_print_key_finished_output(output_unit, logger, input, &
    1134          20 :                                         "QMMM%PRINT%DERIVATIVES")
    1135             : 
    1136          20 :    END SUBROUTINE print_gradients_image_atoms
    1137             : 
    1138             : ! ****************************************************************************
    1139             : !> \brief Print image coefficients
    1140             : !> \param image_coeff expansion coefficients of the image charge density
    1141             : !> \param qs_env qs environment
    1142             : ! **************************************************************************************************
    1143          10 :    SUBROUTINE print_image_coefficients(image_coeff, qs_env)
    1144             : 
    1145             :       REAL(KIND=dp), DIMENSION(:), POINTER               :: image_coeff
    1146             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1147             : 
    1148             :       INTEGER                                            :: atom_a, iatom, natom, output_unit
    1149             :       REAL(KIND=dp)                                      :: normalize_factor, sum_coeff
    1150             :       TYPE(cp_logger_type), POINTER                      :: logger
    1151             :       TYPE(section_vals_type), POINTER                   :: input
    1152             : 
    1153          10 :       NULLIFY (input, logger)
    1154          10 :       logger => cp_get_default_logger()
    1155             : 
    1156          10 :       sum_coeff = 0.0_dp
    1157          10 :       natom = SIZE(qs_env%qmmm_env_qm%image_charge_pot%image_mm_list)
    1158          10 :       normalize_factor = SQRT((qs_env%qmmm_env_qm%image_charge_pot%eta/pi)**3)
    1159             : 
    1160          30 :       DO iatom = 1, natom
    1161          30 :          sum_coeff = sum_coeff + image_coeff(iatom)
    1162             :       END DO
    1163             : 
    1164          10 :       CALL get_qs_env(qs_env=qs_env, input=input)
    1165             : 
    1166             :       output_unit = cp_print_key_unit_nr(logger, input, &
    1167          10 :                                          "QMMM%PRINT%IMAGE_CHARGE_INFO", extension=".Log")
    1168          10 :       IF (output_unit > 0) THEN
    1169           2 :          WRITE (unit=output_unit, fmt="(/)")
    1170             :          WRITE (unit=output_unit, fmt="(T2,A)") &
    1171           2 :             "Image charges [a.u.] after QMMM calculation: "
    1172           2 :          WRITE (unit=output_unit, fmt="(T4,A4,T67,A)") "Atom", "Image charge"
    1173           2 :          WRITE (unit=output_unit, fmt="(T4,A,T67,A)") REPEAT("-", 4), REPEAT("-", 12)
    1174             : 
    1175           6 :          DO iatom = 1, natom
    1176           4 :             atom_a = qs_env%qmmm_env_qm%image_charge_pot%image_mm_list(iatom)
    1177             :             !opposite sign for image_coeff; during the calculation they have
    1178             :             !the 'wrong' sign to ensure consistency with v_hartree which has
    1179             :             !the opposite sign
    1180             :             WRITE (unit=output_unit, fmt="(T2,I6,T65,ES16.9)") &
    1181           6 :                atom_a, -image_coeff(iatom)/normalize_factor
    1182             :          END DO
    1183             : 
    1184           2 :          WRITE (unit=output_unit, fmt="(T2,A)") REPEAT("-", 79)
    1185             :          WRITE (unit=output_unit, fmt="(T2,A,T65,ES16.9)") &
    1186           2 :             "sum image charges:", -sum_coeff/normalize_factor
    1187             :       END IF
    1188             : 
    1189             :       CALL cp_print_key_finished_output(output_unit, logger, input, &
    1190          10 :                                         "QMMM%PRINT%IMAGE_CHARGE_INFO")
    1191             : 
    1192          10 :    END SUBROUTINE print_image_coefficients
    1193             : 
    1194             : ! ****************************************************************************
    1195             : !> \brief Print detailed image charge energies
    1196             : !> \param en_vmetal_rhohartree energy contribution of the image charges
    1197             : !>        without external potential, i.e. 0.5*integral(v_metal*rho_hartree)
    1198             : !> \param en_external additional energy contribution of the image charges due
    1199             : !>        to an external potential, i.e. V0*total_rho_metal
    1200             : !> \param total_rho_metal total induced image charge density
    1201             : !> \param qs_env qs environment
    1202             : ! **************************************************************************************************
    1203          60 :    SUBROUTINE print_image_energy_terms(en_vmetal_rhohartree, en_external, &
    1204             :                                        total_rho_metal, qs_env)
    1205             : 
    1206             :       REAL(KIND=dp), INTENT(IN)                          :: en_vmetal_rhohartree, en_external, &
    1207             :                                                             total_rho_metal
    1208             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1209             : 
    1210             :       INTEGER                                            :: output_unit
    1211             :       TYPE(cp_logger_type), POINTER                      :: logger
    1212             :       TYPE(section_vals_type), POINTER                   :: input
    1213             : 
    1214          60 :       NULLIFY (input, logger)
    1215          60 :       logger => cp_get_default_logger()
    1216             : 
    1217          60 :       CALL get_qs_env(qs_env=qs_env, input=input)
    1218             : 
    1219             :       output_unit = cp_print_key_unit_nr(logger, input, &
    1220          60 :                                          "QMMM%PRINT%IMAGE_CHARGE_INFO", extension=".Log")
    1221             : 
    1222          60 :       IF (output_unit > 0) THEN
    1223             :          WRITE (unit=output_unit, fmt="(T3,A,T56,F25.14)") &
    1224           6 :             "Total induced charge density [a.u.]:", total_rho_metal
    1225           6 :          WRITE (unit=output_unit, fmt="(T3,A)") "Image energy terms: "
    1226             :          WRITE (unit=output_unit, fmt="(T3,A,T56,F25.14)") &
    1227           6 :             "Coulomb energy of QM and image charge density [a.u.]:", en_vmetal_rhohartree
    1228             :          WRITE (unit=output_unit, fmt="(T3,A,T56,F25.14)") &
    1229           6 :             "External potential energy term [a.u.]:", -0.5_dp*en_external
    1230             :          WRITE (unit=output_unit, fmt="(T3,A,T56,F25.14)") &
    1231           6 :             "Total image charge energy [a.u.]:", en_vmetal_rhohartree - 0.5_dp*en_external
    1232             :       END IF
    1233             : 
    1234             :       CALL cp_print_key_finished_output(output_unit, logger, input, &
    1235          60 :                                         "QMMM%PRINT%IMAGE_CHARGE_INFO")
    1236             : 
    1237          60 :    END SUBROUTINE print_image_energy_terms
    1238             : 
    1239          30 : END MODULE qmmm_image_charge

Generated by: LCOV version 1.15