LCOV - code coverage report
Current view: top level - src - qs_sccs.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:c24029e) Lines: 73.0 % 470 343
Test Date: 2026-07-04 06:36:57 Functions: 87.5 % 8 7

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief   Self-consistent continuum solvation (SCCS) model implementation
      10              : !> \author  Matthias Krack (MK)
      11              : !> \version 1.0
      12              : !> \par Literature:
      13              : !>      - J.-L. Fattebert and F. Gygi,
      14              : !>        Density functional theory for efficient ab initio molecular dynamics
      15              : !>        simulations in solution, J. Comput. Chem. 23, 662-666 (2002)
      16              : !>      - O. Andreussi, I. Dabo, and N. Marzari,
      17              : !>        Revised self-consistent continuum solvation in electronic-structure
      18              : !>        calculations, J. Chem. Phys. 136, 064102-20 (2012)
      19              : !> \par History:
      20              : !>      - Creation (10.10.2013,MK)
      21              : !>      - Derivatives using finite differences (26.11.2013,MK)
      22              : !>      - Cube file dump of the dielectric function (19.12.2013,MK)
      23              : !>      - Cube file dump of the polarisation potential (20.12.2013,MK)
      24              : !>      - Calculation of volume and surface of the cavity (21.12.2013,MK)
      25              : !>      - Functional derivative of the cavitation energy (28.12.2013,MK)
      26              : !>      - Update printout (11.11.2022,MK)
      27              : ! **************************************************************************************************
      28              : 
      29              : MODULE qs_sccs
      30              : 
      31              :    USE cp_control_types,                ONLY: dft_control_type,&
      32              :                                               sccs_control_type
      33              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      34              :                                               cp_logger_type
      35              :    USE cp_output_handling,              ONLY: cp_p_file,&
      36              :                                               cp_print_key_finished_output,&
      37              :                                               cp_print_key_should_output,&
      38              :                                               cp_print_key_unit_nr,&
      39              :                                               low_print_level
      40              :    USE cp_realspace_grid_cube,          ONLY: cp_pw_to_cube
      41              :    USE cp_realspace_grid_init,          ONLY: init_input_type
      42              :    USE cp_subsys_types,                 ONLY: cp_subsys_get,&
      43              :                                               cp_subsys_type
      44              :    USE cp_units,                        ONLY: cp_unit_from_cp2k
      45              :    USE input_constants,                 ONLY: sccs_andreussi,&
      46              :                                               sccs_derivative_cd3,&
      47              :                                               sccs_derivative_cd5,&
      48              :                                               sccs_derivative_cd7,&
      49              :                                               sccs_derivative_fft,&
      50              :                                               sccs_fattebert_gygi,&
      51              :                                               sccs_saa_andreussi
      52              :    USE input_section_types,             ONLY: section_get_ivals,&
      53              :                                               section_get_lval,&
      54              :                                               section_vals_get_subs_vals,&
      55              :                                               section_vals_type
      56              :    USE kinds,                           ONLY: default_path_length,&
      57              :                                               default_string_length,&
      58              :                                               dp,&
      59              :                                               int_8
      60              :    USE mathconstants,                   ONLY: fourpi,&
      61              :                                               pi,&
      62              :                                               twopi
      63              :    USE message_passing,                 ONLY: mp_para_env_type
      64              :    USE particle_list_types,             ONLY: particle_list_type
      65              :    USE pw_env_types,                    ONLY: pw_env_get,&
      66              :                                               pw_env_type
      67              :    USE pw_methods,                      ONLY: pw_axpy,&
      68              :                                               pw_copy,&
      69              :                                               pw_derive,&
      70              :                                               pw_integral_ab,&
      71              :                                               pw_integrate_function,&
      72              :                                               pw_scale,&
      73              :                                               pw_transfer,&
      74              :                                               pw_zero
      75              :    USE pw_poisson_methods,              ONLY: pw_func_u_convolution,&
      76              :                                               pw_poisson_solve
      77              :    USE pw_poisson_types,                ONLY: pw_poisson_analytic,&
      78              :                                               pw_poisson_mt,&
      79              :                                               pw_poisson_type
      80              :    USE pw_pool_types,                   ONLY: pw_pool_p_type,&
      81              :                                               pw_pool_type
      82              :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      83              :                                               pw_r3d_rs_type
      84              :    USE qs_energy_types,                 ONLY: qs_energy_type
      85              :    USE qs_environment_types,            ONLY: get_qs_env,&
      86              :                                               qs_environment_type
      87              :    USE qs_rho_types,                    ONLY: qs_rho_get,&
      88              :                                               qs_rho_type
      89              :    USE qs_scf_types,                    ONLY: qs_scf_env_type
      90              :    USE realspace_grid_types,            ONLY: realspace_grid_desc_type,&
      91              :                                               realspace_grid_input_type,&
      92              :                                               realspace_grid_type,&
      93              :                                               rs_grid_create,&
      94              :                                               rs_grid_create_descriptor,&
      95              :                                               rs_grid_release,&
      96              :                                               rs_grid_release_descriptor
      97              :    USE rs_methods,                      ONLY: derive_fdm_cd3,&
      98              :                                               derive_fdm_cd5,&
      99              :                                               derive_fdm_cd7
     100              : #include "./base/base_uses.f90"
     101              : 
     102              :    IMPLICIT NONE
     103              : 
     104              :    PRIVATE
     105              : 
     106              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_sccs'
     107              : 
     108              :    PUBLIC :: print_sccs_results, sccs
     109              : 
     110              : CONTAINS
     111              : 
     112              : ! **************************************************************************************************
     113              : !> \brief   Self-consistent continuum solvation (SCCS) model implementation
     114              : !> \param qs_env ...
     115              : !> \param rho_tot_gspace ...
     116              : !> \param v_hartree_gspace ...
     117              : !> \param v_sccs ...
     118              : !> \param h_stress ...
     119              : !> \par History:
     120              : !>      - Creation (10.10.2013,MK)
     121              : !> \author  Matthias Krack (MK)
     122              : !> \version 1.0
     123              : ! **************************************************************************************************
     124              : 
     125          160 :    SUBROUTINE sccs(qs_env, rho_tot_gspace, v_hartree_gspace, v_sccs, h_stress)
     126              : 
     127              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     128              :       TYPE(pw_c1d_gs_type), INTENT(INOUT)                :: rho_tot_gspace, v_hartree_gspace
     129              :       TYPE(pw_r3d_rs_type), INTENT(INOUT)                :: v_sccs
     130              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT), &
     131              :          OPTIONAL                                        :: h_stress
     132              : 
     133              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'sccs'
     134              :       REAL(KIND=dp), PARAMETER                           :: epstol = 1.0E-8_dp
     135              : 
     136              :       CHARACTER(LEN=4*default_string_length)             :: message, my_pos_cube
     137              :       CHARACTER(LEN=default_path_length)                 :: cube_path, filename, mpi_filename, &
     138              :                                                             print_path
     139              :       INTEGER                                            :: cube_unit, handle, i, ispin, iter, j, k, &
     140              :                                                             nspin, output_unit, print_level
     141              :       INTEGER(KIND=int_8)                                :: ngpts
     142              :       INTEGER, DIMENSION(3)                              :: lb, ub
     143              :       LOGICAL                                            :: append_cube, calculate_stress_tensor, &
     144              :                                                             do_kpoints, mpi_io, should_output
     145              :       REAL(KIND=dp) :: alpha_zeta, cavity_surface, cavity_volume, cell_volume, delta_eta, &
     146              :          delta_zeta, dphi2, dvol, e_tot, epsilon_solvent, f, f0, polarisation_charge, r, R_solv, &
     147              :          rho_delta, rho_delta_avg, rho_delta_max, rho_iter_new, tot_rho_elec, tot_rho_solute
     148              :       REAL(KIND=dp), DIMENSION(3)                        :: abc, lxyz, uxyz
     149              :       TYPE(cp_logger_type), POINTER                      :: logger
     150              :       TYPE(cp_subsys_type), POINTER                      :: cp_subsys
     151              :       TYPE(dft_control_type), POINTER                    :: dft_control
     152              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     153              :       TYPE(particle_list_type), POINTER                  :: particles
     154              :       TYPE(pw_env_type), POINTER                         :: pw_env
     155              :       TYPE(pw_poisson_type), POINTER                     :: poisson_env
     156          160 :       TYPE(pw_pool_p_type), DIMENSION(:), POINTER        :: pw_pools
     157              :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
     158              :       TYPE(pw_r3d_rs_type)                               :: d_s_rhoel, deps_elec, dtf, eps_elec, ff, &
     159              :                                                             p_e_interface, s, t, tem_convolution, &
     160              :                                                             tem_func, u
     161         1120 :       TYPE(pw_r3d_rs_type), DIMENSION(3)                 :: dln_eps_elec, dphi_tot
     162          160 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER        :: rho_pw_r
     163              :       TYPE(pw_r3d_rs_type), POINTER                      :: rho_pw_r_sccs
     164              :       TYPE(qs_energy_type), POINTER                      :: energy
     165              :       TYPE(qs_rho_type), POINTER                         :: rho
     166              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
     167              :       TYPE(sccs_control_type), POINTER                   :: sccs_control
     168              :       TYPE(section_vals_type), POINTER                   :: input
     169              : 
     170          160 :       CALL timeset(routineN, handle)
     171              : 
     172          160 :       NULLIFY (auxbas_pw_pool)
     173          160 :       NULLIFY (cp_subsys)
     174          160 :       NULLIFY (dft_control)
     175          160 :       NULLIFY (energy)
     176          160 :       NULLIFY (input)
     177          160 :       NULLIFY (logger)
     178          160 :       NULLIFY (para_env)
     179          160 :       NULLIFY (particles)
     180          160 :       NULLIFY (poisson_env)
     181          160 :       NULLIFY (pw_env)
     182          160 :       NULLIFY (pw_pools)
     183          160 :       NULLIFY (rho)
     184          160 :       NULLIFY (sccs_control)
     185          160 :       NULLIFY (scf_env)
     186              : 
     187              :       ! Load data from Quickstep environment
     188              :       CALL get_qs_env(qs_env=qs_env, &
     189              :                       cp_subsys=cp_subsys, &
     190              :                       do_kpoints=do_kpoints, &
     191              :                       dft_control=dft_control, &
     192              :                       energy=energy, &
     193              :                       input=input, &
     194              :                       para_env=para_env, &
     195              :                       pw_env=pw_env, &
     196              :                       rho=rho, &
     197          160 :                       scf_env=scf_env)
     198          160 :       CALL cp_subsys_get(cp_subsys, particles=particles)
     199              : 
     200          160 :       sccs_control => dft_control%sccs_control
     201              : 
     202          160 :       CPASSERT(ASSOCIATED(qs_env))
     203              : 
     204          160 :       IF (do_kpoints) THEN
     205            0 :          CPWARN("SCCS with k-points has not yet been fully validated")
     206              :       END IF
     207              : 
     208          160 :       IF (PRESENT(h_stress)) THEN
     209            0 :          calculate_stress_tensor = .TRUE.
     210            0 :          h_stress(:, :) = 0.0_dp
     211            0 :          CPWARN("The stress tensor for SCCS has not yet been fully validated")
     212              :       ELSE
     213              :          calculate_stress_tensor = .FALSE.
     214              :       END IF
     215              : 
     216              :       ! Get access to the PW grid pool
     217              :       CALL pw_env_get(pw_env, &
     218              :                       auxbas_pw_pool=auxbas_pw_pool, &
     219              :                       pw_pools=pw_pools, &
     220          160 :                       poisson_env=poisson_env)
     221              : 
     222          160 :       CALL pw_zero(v_sccs)
     223              : 
     224              :       ! Calculate no SCCS contribution, if the requested SCF convergence threshold is not reached yet
     225          160 :       IF (.NOT. sccs_control%sccs_activated) THEN
     226           54 :          IF (sccs_control%eps_scf > 0.0_dp) THEN
     227           52 :             IF ((scf_env%iter_delta > sccs_control%eps_scf) .OR. &
     228              :                 ((qs_env%scf_env%outer_scf%iter_count == 0) .AND. &
     229              :                  (qs_env%scf_env%iter_count <= 1))) THEN
     230           42 :                IF (calculate_stress_tensor) THEN
     231              :                   ! Request also the calculation of the stress tensor contribution
     232              :                   CALL pw_poisson_solve(poisson_env=poisson_env, &
     233              :                                         density=rho_tot_gspace, &
     234              :                                         ehartree=energy%hartree, &
     235              :                                         vhartree=v_hartree_gspace, &
     236            0 :                                         h_stress=h_stress)
     237              :                ELSE
     238              :                   CALL pw_poisson_solve(poisson_env=poisson_env, &
     239              :                                         density=rho_tot_gspace, &
     240              :                                         ehartree=energy%hartree, &
     241           42 :                                         vhartree=v_hartree_gspace)
     242              :                END IF
     243           42 :                energy%sccs_pol = 0.0_dp
     244           42 :                energy%sccs_cav = 0.0_dp
     245           42 :                energy%sccs_dis = 0.0_dp
     246           42 :                energy%sccs_rep = 0.0_dp
     247           42 :                energy%sccs_sol = 0.0_dp
     248           42 :                energy%sccs_hartree = energy%hartree
     249           42 :                CALL timestop(handle)
     250           42 :                RETURN
     251              :             END IF
     252              :          END IF
     253           12 :          sccs_control%sccs_activated = .TRUE.
     254              :       END IF
     255              : 
     256          118 :       nspin = dft_control%nspins
     257              : 
     258              :       ! Manage print output control
     259          118 :       logger => cp_get_default_logger()
     260          118 :       print_level = logger%iter_info%print_level
     261          118 :       print_path = "DFT%PRINT%SCCS"
     262              :       should_output = (BTEST(cp_print_key_should_output(logger%iter_info, input, &
     263          118 :                                                         TRIM(print_path)), cp_p_file))
     264              :       output_unit = cp_print_key_unit_nr(logger, input, TRIM(print_path), &
     265              :                                          extension=".sccs", &
     266              :                                          ignore_should_output=should_output, &
     267          118 :                                          log_filename=.FALSE.)
     268              : 
     269              :       ! Get rho
     270              :       CALL qs_rho_get(rho_struct=rho, &
     271              :                       rho_r=rho_pw_r, &
     272          118 :                       rho_r_sccs=rho_pw_r_sccs)
     273              : 
     274              :       ! Retrieve the last rho_iter from the previous SCCS cycle if available
     275          118 :       CPASSERT(ASSOCIATED(rho_pw_r_sccs))
     276              : 
     277              :       ! Retrieve the total electronic density in r-space
     278              :       BLOCK
     279              :          TYPE(pw_r3d_rs_type) :: rho_elec
     280          118 :          CALL auxbas_pw_pool%create_pw(rho_elec)
     281              : 
     282              :          ! Retrieve grid parameters
     283          118 :          ngpts = rho_elec%pw_grid%ngpts
     284          118 :          dvol = rho_elec%pw_grid%dvol
     285          118 :          cell_volume = rho_elec%pw_grid%vol
     286          472 :          abc(1:3) = REAL(rho_elec%pw_grid%npts(1:3), KIND=dp)*rho_elec%pw_grid%dr(1:3)
     287          472 :          lb(1:3) = rho_elec%pw_grid%bounds_local(1, 1:3)
     288          472 :          ub(1:3) = rho_elec%pw_grid%bounds_local(2, 1:3)
     289              : 
     290          118 :          CALL pw_copy(rho_pw_r(1), rho_elec)
     291          144 :          DO ispin = 2, nspin
     292          144 :             CALL pw_axpy(rho_pw_r(ispin), rho_elec)
     293              :          END DO
     294          118 :          tot_rho_elec = pw_integrate_function(rho_elec)
     295              : 
     296              :          ! Calculate the dielectric (smoothed) function of rho_elec in r-space
     297          118 :          CALL auxbas_pw_pool%create_pw(eps_elec)
     298          118 :          CALL auxbas_pw_pool%create_pw(deps_elec)
     299          118 :          IF (sccs_control%method_id == sccs_saa_andreussi) THEN
     300            0 :             CALL auxbas_pw_pool%create_pw(s)
     301            0 :             CALL auxbas_pw_pool%create_pw(d_s_rhoel)
     302            0 :             CALL auxbas_pw_pool%create_pw(u)
     303            0 :             CALL auxbas_pw_pool%create_pw(ff)
     304            0 :             CALL auxbas_pw_pool%create_pw(t)
     305            0 :             CALL auxbas_pw_pool%create_pw(dtf)
     306            0 :             f0 = sccs_control%f0
     307            0 :             delta_eta = sccs_control%delta_eta
     308            0 :             alpha_zeta = sccs_control%alpha_zeta
     309            0 :             R_solv = sccs_control%R_solv
     310            0 :             delta_zeta = sccs_control%delta_zeta
     311              :          END IF
     312              : 
     313              :          ! Relative permittivity or dielectric constant of the solvent (medium)
     314          118 :          epsilon_solvent = sccs_control%epsilon_solvent
     315          214 :          SELECT CASE (sccs_control%method_id)
     316              :          CASE (sccs_andreussi)
     317              :             CALL andreussi(rho_elec, eps_elec, deps_elec, epsilon_solvent, sccs_control%rho_max, &
     318           96 :                            sccs_control%rho_min)
     319              :          CASE (sccs_fattebert_gygi)
     320              :             CALL fattebert_gygi(rho_elec, eps_elec, deps_elec, epsilon_solvent, sccs_control%beta, &
     321           22 :                                 sccs_control%rho_zero)
     322              :          CASE (sccs_saa_andreussi)
     323              :             CALL sa_andreussi(rho_elec, eps_elec, deps_elec, epsilon_solvent, sccs_control%rho_max, &
     324            0 :                               sccs_control%rho_min, s, d_s_rhoel)
     325              :          CASE DEFAULT
     326          118 :             CPABORT("Invalid method specified for SCCS model")
     327              :          END SELECT
     328              : 
     329          118 :          IF (sccs_control%method_id /= sccs_saa_andreussi) THEN
     330              :             ! Optional output of the dielectric function in cube file format
     331          118 :             filename = "DIELECTRIC_FUNCTION"
     332          118 :             cube_path = TRIM(print_path)//"%"//TRIM(filename)
     333          118 :             IF (BTEST(cp_print_key_should_output(logger%iter_info, input, TRIM(cube_path)), &
     334              :                       cp_p_file)) THEN
     335            4 :                append_cube = section_get_lval(input, TRIM(cube_path)//"%APPEND")
     336            4 :                my_pos_cube = "REWIND"
     337            4 :                IF (append_cube) my_pos_cube = "APPEND"
     338            4 :                mpi_io = .TRUE.
     339              :                cube_unit = cp_print_key_unit_nr(logger, input, TRIM(cube_path), &
     340              :                                                 extension=".cube", middle_name=TRIM(filename), &
     341              :                                                 file_position=my_pos_cube, log_filename=.FALSE., &
     342            4 :                                                 mpi_io=mpi_io, fout=mpi_filename)
     343            4 :                IF (output_unit > 0) THEN
     344            2 :                   IF (.NOT. mpi_io) THEN
     345            0 :                      INQUIRE (UNIT=cube_unit, NAME=filename)
     346              :                   ELSE
     347            2 :                      filename = mpi_filename
     348              :                   END IF
     349              :                   WRITE (UNIT=output_unit, FMT="(T3,A)") &
     350            2 :                      "SCCS| The dielectric function is written in cube file format to the file:", &
     351            4 :                      "SCCS| "//TRIM(filename)
     352              :                END IF
     353              :                CALL cp_pw_to_cube(eps_elec, cube_unit, TRIM(filename), particles=particles, &
     354              :                                   stride=section_get_ivals(input, TRIM(cube_path)//"%STRIDE"), &
     355            4 :                                   mpi_io=mpi_io)
     356            4 :                CALL cp_print_key_finished_output(cube_unit, logger, input, TRIM(cube_path), mpi_io=mpi_io)
     357              :             END IF
     358              :          END IF
     359              : 
     360              :          ! Calculate the (quantum) volume and surface of the solute cavity
     361          118 :          cavity_surface = 0.0_dp
     362          118 :          cavity_volume = 0.0_dp
     363              : 
     364          118 :          IF (ABS(epsilon_solvent - 1.0_dp) > epstol) THEN
     365              : 
     366              :             BLOCK
     367              :                TYPE(pw_r3d_rs_type) :: theta, norm_drho_elec
     368          472 :                TYPE(pw_r3d_rs_type), DIMENSION(3)                        :: drho_elec
     369          118 :                CALL auxbas_pw_pool%create_pw(theta)
     370          118 :                CALL pw_zero(theta)
     371              : 
     372              :                ! Calculate the (quantum) volume of the solute cavity
     373          118 :                f = 1.0_dp/(epsilon_solvent - 1.0_dp)
     374              : !$OMP    PARALLEL DO DEFAULT(NONE) &
     375              : !$OMP                PRIVATE(i,j,k) &
     376          118 : !$OMP                SHARED(epsilon_solvent,eps_elec,f,lb,theta,ub)
     377              :                DO k = lb(3), ub(3)
     378              :                   DO j = lb(2), ub(2)
     379              :                      DO i = lb(1), ub(1)
     380              :                         theta%array(i, j, k) = f*(epsilon_solvent - eps_elec%array(i, j, k))
     381              :                      END DO
     382              :                   END DO
     383              :                END DO
     384              : !$OMP    END PARALLEL DO
     385          118 :                cavity_volume = pw_integrate_function(theta)
     386              : 
     387              :                ! Calculate the derivative of the electronic density in r-space
     388              :                ! TODO: Could be retrieved from the QS environment
     389          472 :                DO i = 1, 3
     390          472 :                   CALL auxbas_pw_pool%create_pw(drho_elec(i))
     391              :                END DO
     392          118 :                CALL derive(rho_elec, drho_elec, sccs_derivative_fft, pw_env, input)
     393              : 
     394          118 :                CALL auxbas_pw_pool%create_pw(norm_drho_elec)
     395              : 
     396              :                ! Calculate the norm of the gradient of the electronic density in r-space
     397              : !$OMP    PARALLEL DO DEFAULT(NONE) &
     398              : !$OMP                PRIVATE(i,j,k) &
     399          118 : !$OMP                SHARED(drho_elec,lb,norm_drho_elec,ub)
     400              :                DO k = lb(3), ub(3)
     401              :                   DO j = lb(2), ub(2)
     402              :                      DO i = lb(1), ub(1)
     403              :                         norm_drho_elec%array(i, j, k) = SQRT(drho_elec(1)%array(i, j, k)* &
     404              :                                                              drho_elec(1)%array(i, j, k) + &
     405              :                                                              drho_elec(2)%array(i, j, k)* &
     406              :                                                              drho_elec(2)%array(i, j, k) + &
     407              :                                                              drho_elec(3)%array(i, j, k)* &
     408              :                                                              drho_elec(3)%array(i, j, k))
     409              :                      END DO
     410              :                   END DO
     411              :                END DO
     412              : !$OMP    END PARALLEL DO
     413              : 
     414              :                ! Optional output of the norm of the density gradient in cube file format
     415          118 :                filename = "DENSITY_GRADIENT"
     416          118 :                cube_path = TRIM(print_path)//"%"//TRIM(filename)
     417          118 :                IF (BTEST(cp_print_key_should_output(logger%iter_info, input, TRIM(cube_path)), &
     418              :                          cp_p_file)) THEN
     419            0 :                   append_cube = section_get_lval(input, TRIM(cube_path)//"%APPEND")
     420            0 :                   my_pos_cube = "REWIND"
     421            0 :                   IF (append_cube) my_pos_cube = "APPEND"
     422            0 :                   mpi_io = .TRUE.
     423              :                   cube_unit = cp_print_key_unit_nr(logger, input, TRIM(cube_path), &
     424              :                                                    extension=".cube", middle_name=TRIM(filename), &
     425              :                                                    file_position=my_pos_cube, log_filename=.FALSE., &
     426            0 :                                                    mpi_io=mpi_io, fout=mpi_filename)
     427            0 :                   IF (output_unit > 0) THEN
     428            0 :                      IF (.NOT. mpi_io) THEN
     429            0 :                         INQUIRE (UNIT=cube_unit, NAME=filename)
     430              :                      ELSE
     431            0 :                         filename = mpi_filename
     432              :                      END IF
     433              :                      WRITE (UNIT=output_unit, FMT="(T3,A)") &
     434            0 :                         "SCCS| The norm of the density gradient is written in cube file format to the file:", &
     435            0 :                         "SCCS| "//TRIM(filename)
     436              :                   END IF
     437              :                   CALL cp_pw_to_cube(norm_drho_elec, cube_unit, TRIM(filename), particles=particles, &
     438              :                                      stride=section_get_ivals(input, TRIM(cube_path)//"%STRIDE"), &
     439            0 :                                      mpi_io=mpi_io)
     440            0 :                   CALL cp_print_key_finished_output(cube_unit, logger, input, TRIM(cube_path), mpi_io=mpi_io)
     441              :                END IF
     442              : 
     443              :                ! Calculate the (quantum) surface of the solute cavity
     444          214 :                SELECT CASE (sccs_control%method_id)
     445              :                CASE (sccs_andreussi)
     446              :                   CALL surface_andreussi(rho_elec, norm_drho_elec, theta, epsilon_solvent, &
     447              :                                          sccs_control%rho_max, sccs_control%rho_min, &
     448           96 :                                          sccs_control%delta_rho)
     449              :                CASE (sccs_fattebert_gygi)
     450              :                   CALL surface_fattebert_gygi(rho_elec, norm_drho_elec, theta, epsilon_solvent, &
     451              :                                               sccs_control%beta, sccs_control%rho_zero, &
     452           22 :                                               sccs_control%delta_rho)
     453              :                CASE (sccs_saa_andreussi)
     454              :                CASE DEFAULT
     455          118 :                   CPABORT("Invalid method specified for SCCS model")
     456              :                END SELECT
     457          118 :                cavity_surface = pw_integrate_function(theta)
     458              : 
     459              :                ! Release storage
     460          118 :                CALL auxbas_pw_pool%give_back_pw(theta)
     461          118 :                CALL auxbas_pw_pool%give_back_pw(norm_drho_elec)
     462          590 :                DO i = 1, 3
     463          472 :                   CALL auxbas_pw_pool%give_back_pw(drho_elec(i))
     464              :                END DO
     465              :             END BLOCK
     466              : 
     467              :          END IF ! epsilon_solvent > 1
     468              : 
     469          118 :          CALL auxbas_pw_pool%give_back_pw(rho_elec)
     470              :       END BLOCK
     471              : 
     472              :       BLOCK
     473              :          TYPE(pw_r3d_rs_type) :: rho_tot, phi_tot, rho_solute, rho_tot_zero
     474              :          ! Retrieve the total charge density (core + elec) of the solute in r-space
     475          118 :          CALL auxbas_pw_pool%create_pw(rho_solute)
     476          118 :          CALL pw_zero(rho_solute)
     477          118 :          CALL pw_transfer(rho_tot_gspace, rho_solute)
     478          118 :          tot_rho_solute = pw_integrate_function(rho_solute)
     479              : 
     480              :          ! Check total charge
     481          118 :          IF (ABS(tot_rho_solute) >= 1.0E-6_dp) THEN
     482           92 :             IF ((poisson_env%parameters%solver /= pw_poisson_analytic) .AND. &
     483              :                 (poisson_env%parameters%solver /= pw_poisson_mt)) THEN
     484              :                WRITE (UNIT=message, FMT="(A,SP,F0.6,A)") &
     485           92 :                   "The system (solute) has a non-negligible charge of ", -tot_rho_solute, &
     486              :                   ". It is recommended to use non-periodic boundary conditions (PERIODIC none) "// &
     487          184 :                   "combined with an appropriate Poisson solver (POISSON_SOLVER MT or analytic)"
     488           92 :                CPWARN(message)
     489              :             END IF
     490              :          END IF
     491              : 
     492              :          ! Reassign work storage to rho_tot_zero, because rho_elec is no longer needed
     493          118 :          CALL auxbas_pw_pool%create_pw(rho_tot_zero)
     494              : 
     495          118 :          IF (sccs_control%method_id /= sccs_saa_andreussi) THEN
     496              : 
     497              :             ! Build the initial (rho_iter = 0) total charge density (solute plus polarisation) in r-space
     498              :             ! eps_elec <- ln(eps_elec)
     499              : !$OMP PARALLEL DO DEFAULT(NONE) &
     500              : !$OMP             PRIVATE(i,j,k) &
     501              : !$OMP             SHARED(eps_elec,lb,message,output_unit,para_env,ub) &
     502          118 : !$OMP             SHARED(rho_solute,rho_tot_zero)
     503              :             DO k = lb(3), ub(3)
     504              :                DO j = lb(2), ub(2)
     505              :                   DO i = lb(1), ub(1)
     506              :                      IF (eps_elec%array(i, j, k) < 1.0_dp) THEN
     507              :                         WRITE (UNIT=message, FMT="(A,ES12.3,A,3(I0,A))") &
     508              :                            "SCCS| Invalid dielectric function value ", eps_elec%array(i, j, k), &
     509              :                            " encountered at grid point (", i, ",", j, ",", k, ")"
     510              :                         CPABORT(message)
     511              :                      END IF
     512              :                      rho_tot_zero%array(i, j, k) = rho_solute%array(i, j, k)/eps_elec%array(i, j, k)
     513              :                      eps_elec%array(i, j, k) = LOG(eps_elec%array(i, j, k))
     514              :                   END DO
     515              :                END DO
     516              :             END DO
     517              : !$OMP END PARALLEL DO
     518              : 
     519              :          ELSE
     520              : 
     521            0 :             lxyz(:) = REAL(u%pw_grid%bounds(1, :), dp)
     522            0 :             uxyz(:) = REAL(u%pw_grid%bounds(2, :), dp)
     523              : !$OMP PARALLEL DO DEFAULT(NONE) &
     524              : !$OMP             PRIVATE(i,j,k,r) &
     525              : !$OMP             SHARED(lb,message,output_unit,para_env,ub,dtf,uxyz,lxyz) &
     526            0 : !$OMP             SHARED(u, alpha_zeta, R_solv, delta_zeta, eps_elec)
     527              :             DO k = lb(3), ub(3)
     528              :                DO j = lb(2), ub(2)
     529              :                   DO i = lb(1), ub(1)
     530              :                      IF (eps_elec%array(i, j, k) < 1.0_dp) THEN
     531              :                         WRITE (UNIT=message, FMT="(A,ES12.3,A,3(I0,A))") &
     532              :                            "SCCS| Invalid dielectric function value ", eps_elec%array(i, j, k), &
     533              :                            " encountered at grid point (", i, ",", j, ",", k, ")"
     534              :                         CPABORT(message)
     535              :                      END IF
     536              :                      IF (i > -1) r = ((REAL(uxyz(1), dp) - REAL(i, dp) + 0.5_dp)*u%pw_grid%dr(1))**2.0_dp
     537              :                      IF (i < 0) r = ((REAL(i, dp) - REAL(lxyz(1), dp) + 0.5_dp)*u%pw_grid%dr(1))**2.0_dp
     538              :                      IF (j > -1) r = ((REAL(uxyz(2), dp) - REAL(j, dp) + 0.5_dp)*u%pw_grid%dr(2))**2.0_dp + r
     539              :                      IF (j < 0) r = ((REAL(j, dp) - REAL(lxyz(2), dp) + 0.5_dp)*u%pw_grid%dr(2))**2.0_dp + r
     540              :                      IF (k > -1) r = ((REAL(uxyz(3), dp) - REAL(k, dp) + 0.5_dp)*u%pw_grid%dr(3))**2.0_dp + r
     541              :                      IF (k < 0) r = ((REAL(k, dp) - REAL(lxyz(3), dp) + 0.5_dp)*u%pw_grid%dr(3))**2.0_dp + r
     542              :                      r = SQRT(r)
     543              :                      u%array(i, j, k) = (1.0_dp/2.0_dp)*erfc((r - alpha_zeta*R_solv)/delta_zeta)
     544              :                      dtf%array(i, j, k) = 1.0_dp
     545              :                   END DO
     546              :                END DO
     547              :             END DO
     548              : !$OMP END PARALLEL DO
     549              : 
     550            0 :             CALL pw_func_u_convolution(poisson_env=poisson_env, func=dtf, convolution=ff, u=u)
     551            0 :             CALL pw_scale(u, 1.0_dp/ff%array(0, 0, 0))
     552            0 :             CALL pw_func_u_convolution(poisson_env=poisson_env, func=s, convolution=ff, u=u)
     553              : 
     554              : !$OMP PARALLEL DO DEFAULT(NONE) &
     555              : !$OMP             PRIVATE(i,j,k) &
     556              : !$OMP             SHARED(lb,para_env,ub, delta_eta, f0, epsilon_solvent) &
     557            0 : !$OMP             SHARED(ff, t, dtf, eps_elec, rho_tot_zero, rho_solute, s)
     558              :             DO k = lb(3), ub(3)
     559              :                DO j = lb(2), ub(2)
     560              :                   DO i = lb(1), ub(1)
     561              :                      t%array(i, j, k) = 0.5_dp*(1.0_dp + erf((ff%array(i, j, k) - f0)/delta_eta))
     562              :                      dtf%array(i, j, k) = (1.0_dp/SQRT(pi))*EXP(-(ff%array(i, j, k) - f0)**2.0/(delta_eta**2.0))
     563              :                      eps_elec%array(i, j, k) = EXP(LOG(epsilon_solvent)*(1 - (s%array(i, j, k) &
     564              :                                                                               + (1 - s%array(i, j, k))*t%array(i, j, k))))
     565              :                      rho_tot_zero%array(i, j, k) = rho_solute%array(i, j, k)/eps_elec%array(i, j, k)
     566              : !                     eps_elec%array(i, j, k) = LOG(eps_elec%array(i, j, k))
     567              :                   END DO
     568              :                END DO
     569              :             END DO
     570              : !$OMP END PARALLEL DO
     571              : 
     572              :             ! Optional output of the dielectric function in cube file format (solvent aware algorithm case)
     573            0 :             filename = "DIELECTRIC_FUNCTION"
     574            0 :             cube_path = TRIM(print_path)//"%"//TRIM(filename)
     575            0 :             IF (BTEST(cp_print_key_should_output(logger%iter_info, input, TRIM(cube_path)), &
     576              :                       cp_p_file)) THEN
     577            0 :                append_cube = section_get_lval(input, TRIM(cube_path)//"%APPEND")
     578            0 :                my_pos_cube = "REWIND"
     579            0 :                IF (append_cube) my_pos_cube = "APPEND"
     580            0 :                mpi_io = .TRUE.
     581              :                cube_unit = cp_print_key_unit_nr(logger, input, TRIM(cube_path), &
     582              :                                                 extension=".cube", middle_name=TRIM(filename), &
     583              :                                                 file_position=my_pos_cube, log_filename=.FALSE., &
     584            0 :                                                 mpi_io=mpi_io, fout=mpi_filename)
     585            0 :                IF (output_unit > 0) THEN
     586            0 :                   IF (.NOT. mpi_io) THEN
     587            0 :                      INQUIRE (UNIT=cube_unit, NAME=filename)
     588              :                   ELSE
     589            0 :                      filename = mpi_filename
     590              :                   END IF
     591              :                   WRITE (UNIT=output_unit, FMT="(T3,A)") &
     592            0 :                      "SCCS| The dielectric function is written in cube file format to the file:", &
     593            0 :                      "SCCS| "//TRIM(filename)
     594              :                END IF
     595              :                CALL cp_pw_to_cube(eps_elec, cube_unit, TRIM(filename), particles=particles, &
     596              :                                   stride=section_get_ivals(input, TRIM(cube_path)//"%STRIDE"), &
     597            0 :                                   mpi_io=mpi_io)
     598            0 :                CALL cp_print_key_finished_output(cube_unit, logger, input, TRIM(cube_path), mpi_io=mpi_io)
     599              :             END IF
     600              : 
     601              : !$OMP PARALLEL DO DEFAULT(NONE) &
     602              : !$OMP             PRIVATE(i,j,k) &
     603              : !$OMP             SHARED(lb,para_env,ub, delta_eta, f0, epsilon_solvent) &
     604            0 : !$OMP             SHARED(ff, t, dtf, eps_elec, rho_tot_zero, rho_solute, s)
     605              :             DO k = lb(3), ub(3)
     606              :                DO j = lb(2), ub(2)
     607              :                   DO i = lb(1), ub(1)
     608              :                      eps_elec%array(i, j, k) = LOG(eps_elec%array(i, j, k))
     609              :                   END DO
     610              :                END DO
     611              :             END DO
     612              : !$OMP END PARALLEL DO
     613              : 
     614              :          END IF
     615              : 
     616              :          ! Build the derivative of LOG(eps_elec)
     617          472 :          DO i = 1, 3
     618          354 :             CALL auxbas_pw_pool%create_pw(dln_eps_elec(i))
     619          472 :             CALL pw_zero(dln_eps_elec(i))
     620              :          END DO
     621          118 :          CALL derive(eps_elec, dln_eps_elec, sccs_control%derivative_method, pw_env, input)
     622          118 :          IF (sccs_control%method_id /= sccs_saa_andreussi) THEN
     623          118 :             CALL auxbas_pw_pool%give_back_pw(eps_elec)
     624              :          END IF
     625              : 
     626              :          ! Print header for the SCCS cycle
     627          118 :          IF (should_output .AND. (output_unit > 0)) THEN
     628           46 :             IF (print_level > low_print_level) THEN
     629              :                WRITE (UNIT=output_unit, FMT="(T3,A,T56,F25.12)") &
     630           46 :                   "SCCS| Total electronic charge density ", -tot_rho_elec, &
     631           92 :                   "SCCS| Total charge density (solute)   ", -tot_rho_solute
     632              :                WRITE (UNIT=output_unit, FMT="(T3,A,T56,F25.3)") &
     633           46 :                   "SCCS| Volume of the cell           [bohr^3]", cell_volume, &
     634           46 :                   "SCCS|                              [angstrom^3]", &
     635           92 :                   cp_unit_from_cp2k(cell_volume, "angstrom^3")
     636           46 :                IF (ABS(epsilon_solvent - 1.0_dp) > epstol) THEN
     637              :                   WRITE (UNIT=output_unit, FMT="(T3,A,T56,F25.3)") &
     638           46 :                      "SCCS| Volume of the solute cavity  [bohr^3]", cavity_volume, &
     639           46 :                      "SCCS|                              [angstrom^3]", &
     640           46 :                      cp_unit_from_cp2k(cavity_volume, "angstrom^3"), &
     641           46 :                      "SCCS| Surface of the solute cavity [bohr^2]", cavity_surface, &
     642           46 :                      "SCCS|                              [angstrom^2]", &
     643           92 :                      cp_unit_from_cp2k(cavity_surface, "angstrom^2")
     644              :                END IF
     645              :                WRITE (UNIT=output_unit, FMT="(T3,A)") &
     646           46 :                   "SCCS|", &
     647           92 :                   "SCCS|   Step    Average residual    Maximum residual         E(Hartree) [a.u.]"
     648              :             END IF
     649              :          END IF
     650              : 
     651              :          ! Get storage for the derivative of the total potential (field) in r-space
     652          472 :          DO i = 1, 3
     653          472 :             CALL auxbas_pw_pool%create_pw(dphi_tot(i))
     654              :          END DO
     655              : 
     656              :          ! Initialise the total charge density in r-space rho_tot with rho_tot_zero + rho_iter_zero
     657          118 :          CALL auxbas_pw_pool%create_pw(rho_tot)
     658          118 :          CALL pw_copy(rho_tot_zero, rho_tot)
     659          118 :          CALL pw_axpy(rho_pw_r_sccs, rho_tot)
     660              : 
     661          118 :          CALL auxbas_pw_pool%create_pw(phi_tot)
     662          118 :          CALL pw_zero(phi_tot)
     663              : 
     664          118 :          IF (sccs_control%method_id == sccs_saa_andreussi) THEN
     665            0 :             CALL auxbas_pw_pool%create_pw(p_e_interface)
     666            0 :             CALL pw_zero(p_e_interface)
     667              :          END IF
     668              : 
     669              :          ! Main SCCS iteration loop
     670          118 :          iter = 0
     671              : 
     672              :          iter_loop: DO
     673              : 
     674              :             ! Increment iteration counter
     675          692 :             iter = iter + 1
     676              : 
     677              :             ! Check if the requested maximum number of SCCS iterations is reached
     678          692 :             IF (iter > sccs_control%max_iter) THEN
     679            0 :                IF (output_unit > 0) THEN
     680              :                   WRITE (UNIT=output_unit, FMT="(T3,A,/,T3,A,I0,A)") &
     681            0 :                      "SCCS| Maximum number of SCCS iterations reached", &
     682            0 :                      "SCCS| Iteration cycle did not converge in ", sccs_control%max_iter, " steps"
     683              :                ELSE
     684              :                   WRITE (UNIT=message, FMT="(A,I0,A)") &
     685            0 :                      "The SCCS iteration cycle did not converge in ", sccs_control%max_iter, " steps"
     686            0 :                   CPWARN(message)
     687              :                END IF
     688              :                EXIT iter_loop
     689              :             END IF
     690              : 
     691              :             ! Calculate derivative of the current total potential in r-space
     692              :             CALL pw_poisson_solve(poisson_env=poisson_env, &
     693              :                                   density=rho_tot, &
     694              :                                   vhartree=phi_tot, &
     695          692 :                                   dvhartree=dphi_tot)
     696          692 :             energy%sccs_hartree = 0.5_dp*pw_integral_ab(rho_solute, phi_tot)
     697              : 
     698              :             ! Update total charge density (solute plus polarisation) in r-space
     699              :             ! based on the iterated polarisation charge density
     700          692 :             f = 1.0_dp/fourpi
     701          692 :             rho_delta_avg = 0.0_dp
     702          692 :             rho_delta_max = 0.0_dp
     703              : !$OMP    PARALLEL DO DEFAULT(NONE) &
     704              : !$OMP                PRIVATE(i,j,k,rho_delta,rho_iter_new) &
     705              : !$OMP                SHARED(dln_eps_elec,dphi_tot,f,lb,rho_pw_r_sccs,ub) &
     706              : !$OMP                SHARED(rho_tot,rho_tot_zero,sccs_control) &
     707              : !$OMP                REDUCTION(+:rho_delta_avg) &
     708          692 : !$OMP                REDUCTION(MAX:rho_delta_max)
     709              :             DO k = lb(3), ub(3)
     710              :                DO j = lb(2), ub(2)
     711              :                   DO i = lb(1), ub(1)
     712              :                      rho_iter_new = (dln_eps_elec(1)%array(i, j, k)*dphi_tot(1)%array(i, j, k) + &
     713              :                                      dln_eps_elec(2)%array(i, j, k)*dphi_tot(2)%array(i, j, k) + &
     714              :                                      dln_eps_elec(3)%array(i, j, k)*dphi_tot(3)%array(i, j, k))*f
     715              :                      rho_iter_new = rho_pw_r_sccs%array(i, j, k) + &
     716              :                                     sccs_control%mixing*(rho_iter_new - rho_pw_r_sccs%array(i, j, k))
     717              :                      rho_delta = ABS(rho_iter_new - rho_pw_r_sccs%array(i, j, k))
     718              :                      rho_delta_max = MAX(rho_delta, rho_delta_max)
     719              :                      rho_delta_avg = rho_delta_avg + rho_delta
     720              :                      rho_tot%array(i, j, k) = rho_tot_zero%array(i, j, k) + rho_iter_new
     721              :                      rho_pw_r_sccs%array(i, j, k) = rho_iter_new
     722              :                   END DO
     723              :                END DO
     724              :             END DO
     725              : !$OMP    END PARALLEL DO
     726              : 
     727          692 :             CALL para_env%sum(rho_delta_avg)
     728          692 :             rho_delta_avg = rho_delta_avg/REAL(ngpts, KIND=dp)
     729          692 :             CALL para_env%max(rho_delta_max)
     730              : 
     731          692 :             IF (should_output .AND. (output_unit > 0)) THEN
     732          147 :                IF (print_level > low_print_level) THEN
     733          147 :                   IF ((ABS(rho_delta_avg) < 1.0E-8_dp) .OR. &
     734          147 :                       (ABS(rho_delta_avg) >= 1.0E5_dp)) THEN
     735              :                      WRITE (UNIT=output_unit, FMT="(T3,A,I6,4X,ES16.4,4X,ES16.4,1X,F25.12)") &
     736            0 :                         "SCCS| ", iter, rho_delta_avg, rho_delta_max, energy%sccs_hartree
     737              :                   ELSE
     738              :                      WRITE (UNIT=output_unit, FMT="(T3,A,I6,4X,F16.8,4X,F16.8,1X,F25.12)") &
     739          147 :                         "SCCS| ", iter, rho_delta_avg, rho_delta_max, energy%sccs_hartree
     740              :                   END IF
     741              :                END IF
     742              :             END IF
     743              : 
     744              :             ! Check if the SCCS iteration cycle is converged to the requested tolerance
     745          692 :             IF (rho_delta_max <= sccs_control%eps_sccs) THEN
     746          118 :                IF (should_output .AND. (output_unit > 0)) THEN
     747              :                   WRITE (UNIT=output_unit, FMT="(T3,A,I0,A)") &
     748           46 :                      "SCCS| Iteration cycle converged in ", iter, " steps"
     749              :                END IF
     750              :                EXIT iter_loop
     751              :             END IF
     752              : 
     753              :          END DO iter_loop
     754              : 
     755          118 :          IF (sccs_control%method_id == sccs_saa_andreussi) THEN
     756            0 :             CALL auxbas_pw_pool%create_pw(tem_convolution)
     757            0 :             CALL auxbas_pw_pool%create_pw(tem_func)
     758              : 
     759              : !$OMP PARALLEL DO DEFAULT(NONE) &
     760              : !$OMP                PRIVATE(i,j,k,dphi2) &
     761              : !$OMP                SHARED(lb,ub, tem_func, s, dtf) &
     762            0 : !$OMP                SHARED(dphi_tot, p_e_interface, eps_elec, epsilon_solvent)
     763              :             DO k = lb(3), ub(3)
     764              :                DO j = lb(2), ub(2)
     765              :                   DO i = lb(1), ub(1)
     766              :                      p_e_interface%array(i, j, k) = 1.0_dp/(4.0_dp*twopi)*(EXP(eps_elec%array(i, j, k))*LOG(epsilon_solvent))
     767              :                      dphi2 = dphi_tot(1)%array(i, j, k)*dphi_tot(1)%array(i, j, k) + &
     768              :                              dphi_tot(2)%array(i, j, k)*dphi_tot(2)%array(i, j, k) + &
     769              :                              dphi_tot(3)%array(i, j, k)*dphi_tot(3)%array(i, j, k)
     770              :                      p_e_interface%array(i, j, k) = p_e_interface%array(i, j, k)*dphi2
     771              :                      tem_func%array(i, j, k) = (1.0_dp - s%array(i, j, k))*p_e_interface%array(i, j, k)*dtf%array(i, j, k)
     772              :                   END DO
     773              :                END DO
     774              :             END DO
     775              : !$OMP END PARALLEL DO
     776              : 
     777            0 :             CALL pw_func_u_convolution(poisson_env=poisson_env, func=tem_func, convolution=tem_convolution, u=u)
     778              : 
     779              : !$OMP PARALLEL DO DEFAULT(NONE) &
     780              : !$OMP                PRIVATE(i,j,k) &
     781              : !$OMP                SHARED(lb,ub) &
     782            0 : !$OMP                SHARED(p_e_interface, t, tem_convolution, phi_tot, d_s_rhoel)
     783              :             DO k = lb(3), ub(3)
     784              :                DO j = lb(2), ub(2)
     785              :                   DO i = lb(1), ub(1)
     786              :                      p_e_interface%array(i, j, k) = p_e_interface%array(i, j, k)*(1.0_dp - t%array(i, j, k)) &
     787              :                                                     + tem_convolution%array(i, j, k)
     788              :                   END DO
     789              :                END DO
     790              :             END DO
     791              : !$OMP END PARALLEL DO
     792              : 
     793              :          END IF
     794              : 
     795              :          ! Release work storage which is no longer needed
     796          118 :          CALL auxbas_pw_pool%give_back_pw(rho_tot_zero)
     797          472 :          DO i = 1, 3
     798          472 :             CALL auxbas_pw_pool%give_back_pw(dln_eps_elec(i))
     799              :          END DO
     800              : 
     801              :          ! Optional output of the total charge density in cube file format
     802          118 :          filename = "TOTAL_CHARGE_DENSITY"
     803          118 :          cube_path = TRIM(print_path)//"%"//TRIM(filename)
     804          118 :          IF (BTEST(cp_print_key_should_output(logger%iter_info, input, TRIM(cube_path)), cp_p_file)) THEN
     805            0 :             append_cube = section_get_lval(input, TRIM(cube_path)//"%APPEND")
     806            0 :             my_pos_cube = "REWIND"
     807            0 :             IF (append_cube) my_pos_cube = "APPEND"
     808            0 :             mpi_io = .TRUE.
     809              :             cube_unit = cp_print_key_unit_nr(logger, input, TRIM(cube_path), &
     810              :                                              extension=".cube", middle_name=TRIM(filename), &
     811              :                                              file_position=my_pos_cube, log_filename=.FALSE., &
     812            0 :                                              mpi_io=mpi_io, fout=mpi_filename)
     813            0 :             IF (output_unit > 0) THEN
     814            0 :                IF (.NOT. mpi_io) THEN
     815            0 :                   INQUIRE (UNIT=cube_unit, NAME=filename)
     816              :                ELSE
     817            0 :                   filename = mpi_filename
     818              :                END IF
     819              :                WRITE (UNIT=output_unit, FMT="(T3,A)") &
     820            0 :                   "SCCS| The total SCCS charge density is written in cube file format to the file:", &
     821            0 :                   "SCCS| "//TRIM(filename)
     822              :             END IF
     823              :             CALL cp_pw_to_cube(rho_tot, cube_unit, TRIM(filename), particles=particles, &
     824            0 :                                stride=section_get_ivals(input, TRIM(cube_path)//"%STRIDE"), mpi_io=mpi_io)
     825            0 :             CALL cp_print_key_finished_output(cube_unit, logger, input, TRIM(cube_path), mpi_io=mpi_io)
     826              :          END IF
     827              : 
     828              :          ! Calculate the total SCCS Hartree energy, potential, and its
     829              :          ! derivatives of the solute and the implicit solvent
     830          118 :          CALL pw_transfer(rho_tot, rho_tot_gspace)
     831          118 :          IF (calculate_stress_tensor) THEN
     832              :             ! Request also the calculation of the stress tensor contribution
     833              :             CALL pw_poisson_solve(poisson_env=poisson_env, &
     834              :                                   density=rho_tot_gspace, &
     835              :                                   ehartree=e_tot, &
     836              :                                   vhartree=v_hartree_gspace, &
     837              :                                   dvhartree=dphi_tot, &
     838            0 :                                   h_stress=h_stress)
     839              :          ELSE
     840              :             CALL pw_poisson_solve(poisson_env=poisson_env, &
     841              :                                   density=rho_tot_gspace, &
     842              :                                   ehartree=e_tot, &
     843              :                                   vhartree=v_hartree_gspace, &
     844          118 :                                   dvhartree=dphi_tot)
     845              :          END IF
     846          118 :          CALL pw_transfer(v_hartree_gspace, phi_tot)
     847          118 :          energy%sccs_hartree = 0.5_dp*pw_integral_ab(rho_solute, phi_tot)
     848              : 
     849              :          ! Calculate the Hartree energy and potential of the solute only
     850              :          BLOCK
     851              :             TYPE(pw_r3d_rs_type) :: phi_solute
     852          118 :             CALL auxbas_pw_pool%create_pw(phi_solute)
     853          118 :             CALL pw_zero(phi_solute)
     854              :             CALL pw_poisson_solve(poisson_env=poisson_env, &
     855              :                                   density=rho_solute, &
     856              :                                   ehartree=energy%hartree, &
     857          118 :                                   vhartree=phi_solute)
     858              : 
     859              :             ! Calculate the polarisation potential (store it in phi_tot)
     860              :             ! phi_pol = phi_tot - phi_solute
     861          118 :             CALL pw_axpy(phi_solute, phi_tot, alpha=-1.0_dp)
     862          118 :             CALL auxbas_pw_pool%give_back_pw(phi_solute)
     863              :          END BLOCK
     864              : 
     865              :          ! Optional output of the SCCS polarisation potential in cube file format
     866          118 :          filename = "POLARISATION_POTENTIAL"
     867          118 :          cube_path = TRIM(print_path)//"%"//TRIM(filename)
     868          118 :          IF (BTEST(cp_print_key_should_output(logger%iter_info, input, TRIM(cube_path)), &
     869              :                    cp_p_file)) THEN
     870            4 :             append_cube = section_get_lval(input, TRIM(cube_path)//"%APPEND")
     871            4 :             my_pos_cube = "REWIND"
     872            4 :             IF (append_cube) my_pos_cube = "APPEND"
     873            4 :             mpi_io = .TRUE.
     874              :             cube_unit = cp_print_key_unit_nr(logger, input, TRIM(cube_path), &
     875              :                                              extension=".cube", middle_name=TRIM(filename), &
     876              :                                              file_position=my_pos_cube, log_filename=.FALSE., &
     877            4 :                                              mpi_io=mpi_io, fout=mpi_filename)
     878            4 :             IF (output_unit > 0) THEN
     879            2 :                IF (.NOT. mpi_io) THEN
     880            0 :                   INQUIRE (UNIT=cube_unit, NAME=filename)
     881              :                ELSE
     882            2 :                   filename = mpi_filename
     883              :                END IF
     884              :                WRITE (UNIT=output_unit, FMT="(T3,A)") &
     885            2 :                   "SCCS| The SCCS polarisation potential is written in cube file format to the file:", &
     886            4 :                   "SCCS| "//TRIM(filename)
     887              :             END IF
     888              :             CALL cp_pw_to_cube(phi_tot, cube_unit, TRIM(filename), particles=particles, &
     889            4 :                                stride=section_get_ivals(input, TRIM(cube_path)//"%STRIDE"), mpi_io=mpi_io)
     890            4 :             CALL cp_print_key_finished_output(cube_unit, logger, input, TRIM(cube_path), mpi_io=mpi_io)
     891              :          END IF
     892              : 
     893              :          ! Calculate the polarisation charge (store it in rho_tot)
     894              :          ! rho_pol = rho_tot - rho_solute
     895          118 :          CALL pw_axpy(rho_solute, rho_tot, alpha=-1.0_dp)
     896          118 :          polarisation_charge = pw_integrate_function(rho_tot)
     897              : 
     898              :          ! Optional output of the SCCS polarisation charge in cube file format
     899          118 :          filename = "POLARISATION_CHARGE_DENSITY"
     900          118 :          cube_path = TRIM(print_path)//"%"//TRIM(filename)
     901          118 :          IF (BTEST(cp_print_key_should_output(logger%iter_info, input, TRIM(cube_path)), &
     902              :                    cp_p_file)) THEN
     903            0 :             append_cube = section_get_lval(input, TRIM(cube_path)//"%APPEND")
     904            0 :             my_pos_cube = "REWIND"
     905            0 :             IF (append_cube) my_pos_cube = "APPEND"
     906            0 :             mpi_io = .TRUE.
     907              :             cube_unit = cp_print_key_unit_nr(logger, input, TRIM(cube_path), &
     908              :                                              extension=".cube", middle_name=TRIM(filename), &
     909              :                                              file_position=my_pos_cube, log_filename=.FALSE., &
     910            0 :                                              mpi_io=mpi_io, fout=mpi_filename)
     911            0 :             IF (output_unit > 0) THEN
     912            0 :                IF (.NOT. mpi_io) THEN
     913            0 :                   INQUIRE (UNIT=cube_unit, NAME=filename)
     914              :                ELSE
     915            0 :                   filename = mpi_filename
     916              :                END IF
     917              :                WRITE (UNIT=output_unit, FMT="(T3,A)") &
     918            0 :                   "SCCS| The SCCS polarisation charge density is written in cube file format to the file:", &
     919            0 :                   "SCCS| "//TRIM(filename)
     920              :             END IF
     921              :             CALL cp_pw_to_cube(rho_tot, cube_unit, TRIM(filename), particles=particles, &
     922            0 :                                stride=section_get_ivals(input, TRIM(cube_path)//"%STRIDE"), mpi_io=mpi_io)
     923            0 :             CALL cp_print_key_finished_output(cube_unit, logger, input, TRIM(cube_path), mpi_io=mpi_io)
     924              :          END IF
     925              : 
     926              :          ! Calculate SCCS polarisation energy
     927          118 :          energy%sccs_pol = 0.5_dp*pw_integral_ab(rho_solute, phi_tot)
     928          118 :          CALL auxbas_pw_pool%give_back_pw(rho_solute)
     929          118 :          CALL auxbas_pw_pool%give_back_pw(phi_tot)
     930          118 :          CALL auxbas_pw_pool%give_back_pw(rho_tot)
     931          236 :          IF (sccs_control%method_id == sccs_saa_andreussi) THEN
     932            0 :             CALL auxbas_pw_pool%give_back_pw(s)
     933            0 :             CALL auxbas_pw_pool%give_back_pw(u)
     934            0 :             CALL auxbas_pw_pool%give_back_pw(ff)
     935            0 :             CALL auxbas_pw_pool%give_back_pw(t)
     936            0 :             CALL auxbas_pw_pool%give_back_pw(dtf)
     937            0 :             CALL auxbas_pw_pool%give_back_pw(tem_convolution)
     938            0 :             CALL auxbas_pw_pool%give_back_pw(tem_func)
     939            0 :             CALL auxbas_pw_pool%give_back_pw(eps_elec)
     940              :          END IF
     941              :       END BLOCK
     942              : 
     943              :       ! Calculate additional solvation terms
     944          118 :       energy%sccs_cav = sccs_control%gamma_solvent*cavity_surface
     945          118 :       energy%sccs_dis = sccs_control%beta_solvent*cavity_volume
     946          118 :       energy%sccs_rep = sccs_control%alpha_solvent*cavity_surface
     947              :       ! Calculate solvation free energy: \delta G^el + (alpha + gamma)*S + beta*V
     948          118 :       energy%sccs_sol = energy%sccs_pol + energy%sccs_rep + energy%sccs_cav + energy%sccs_dis
     949              : 
     950          118 :       IF (should_output .AND. (output_unit > 0)) THEN
     951              :          WRITE (UNIT=output_unit, FMT="(T3,A)") &
     952           46 :             "SCCS|"
     953              :          WRITE (UNIT=output_unit, FMT="(T3,A,T56,F25.12)") &
     954           46 :             "SCCS| Polarisation charge", polarisation_charge
     955              :          !MK   "SCCS| Total interaction energy [a.u.]", e_tot
     956              :          WRITE (UNIT=output_unit, FMT="(T3,A)") &
     957           46 :             "SCCS|"
     958           46 :          CALL print_sccs_results(energy, sccs_control, output_unit)
     959              :       END IF
     960              : 
     961              :       ! Calculate SCCS contribution to the Kohn-Sham potential
     962          118 :       IF (sccs_control%method_id /= sccs_saa_andreussi) THEN
     963              : 
     964          118 :          f = -0.5_dp*dvol/fourpi
     965              : !$OMP PARALLEL DO DEFAULT(NONE) &
     966              : !$OMP             PRIVATE(dphi2,i,j,k) &
     967              : !$OMP             SHARED(f,deps_elec,dphi_tot) &
     968          118 : !$OMP             SHARED(lb,ub,v_sccs)
     969              :          DO k = lb(3), ub(3)
     970              :             DO j = lb(2), ub(2)
     971              :                DO i = lb(1), ub(1)
     972              :                   dphi2 = dphi_tot(1)%array(i, j, k)*dphi_tot(1)%array(i, j, k) + &
     973              :                           dphi_tot(2)%array(i, j, k)*dphi_tot(2)%array(i, j, k) + &
     974              :                           dphi_tot(3)%array(i, j, k)*dphi_tot(3)%array(i, j, k)
     975              :                   v_sccs%array(i, j, k) = v_sccs%array(i, j, k) + f*deps_elec%array(i, j, k)*dphi2
     976              :                END DO
     977              :             END DO
     978              :          END DO
     979              : !$OMP END PARALLEL DO
     980              : 
     981              :       ELSE
     982              : 
     983              : !$OMP PARALLEL DO DEFAULT(NONE) &
     984              : !$OMP                PRIVATE(i,j,k) &
     985              : !$OMP                SHARED(lb,ub, dvol) &
     986            0 : !$OMP                SHARED(p_E_interface, v_sccs, d_s_rhoel)
     987              :          DO k = lb(3), ub(3)
     988              :             DO j = lb(2), ub(2)
     989              :                DO i = lb(1), ub(1)
     990              :                   v_sccs%array(i, j, k) = dvol*d_s_rhoel%array(i, j, k)*p_E_interface%array(i, j, k)
     991              :                END DO
     992              :             END DO
     993              :          END DO
     994              : !$OMP END PARALLEL DO
     995              : 
     996            0 :          CALL auxbas_pw_pool%give_back_pw(d_s_rhoel)
     997            0 :          CALL auxbas_pw_pool%give_back_pw(p_E_interface)
     998              : 
     999              :       END IF
    1000              : 
    1001          118 :       CALL auxbas_pw_pool%give_back_pw(deps_elec)
    1002          472 :       DO i = 1, 3
    1003          472 :          CALL auxbas_pw_pool%give_back_pw(dphi_tot(i))
    1004              :       END DO
    1005              : 
    1006              :       ! Release the SCCS printout environment
    1007              :       CALL cp_print_key_finished_output(output_unit, logger, input, TRIM(print_path), &
    1008          118 :                                         ignore_should_output=should_output)
    1009              : 
    1010          118 :       CALL timestop(handle)
    1011              : 
    1012          320 :    END SUBROUTINE sccs
    1013              : 
    1014              : ! **************************************************************************************************
    1015              : !> \brief      Calculate the smoothed dielectric function of Andreussi et al.
    1016              : !> \param rho_elec ...
    1017              : !> \param eps_elec ...
    1018              : !> \param deps_elec ...
    1019              : !> \param epsilon_solvent ...
    1020              : !> \param rho_max ...
    1021              : !> \param rho_min ...
    1022              : !> \par History:
    1023              : !>      - Creation (16.10.2013,MK)
    1024              : !>      - Finite difference of isosurfaces implemented (21.12.2013,MK)
    1025              : !> \author     Matthias Krack (MK)
    1026              : !> \version    1.1
    1027              : ! **************************************************************************************************
    1028           96 :    SUBROUTINE andreussi(rho_elec, eps_elec, deps_elec, epsilon_solvent, rho_max, &
    1029              :                         rho_min)
    1030              : 
    1031              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: rho_elec, eps_elec, deps_elec
    1032              :       REAL(KIND=dp), INTENT(IN)                          :: epsilon_solvent, rho_max, rho_min
    1033              : 
    1034              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'andreussi'
    1035              :       REAL(KIND=dp), PARAMETER                           :: rhotol = 1.0E-12_dp
    1036              : 
    1037              :       INTEGER                                            :: handle, i, j, k
    1038              :       INTEGER, DIMENSION(3)                              :: lb, ub
    1039              :       REAL(KIND=dp)                                      :: diff, dq, dt, f, ln_rho_max, ln_rho_min, &
    1040              :                                                             q, rho, t, x, y
    1041              : 
    1042           96 :       CALL timeset(routineN, handle)
    1043              : 
    1044           96 :       f = LOG(epsilon_solvent)/twopi
    1045           96 :       diff = rho_max - rho_min
    1046           96 :       IF (diff < SQRT(rhotol)) CPABORT("SCCS: Difference between rho(min) and rho(max) is too small")
    1047           96 :       IF (rho_min >= rhotol) THEN
    1048           96 :          ln_rho_max = LOG(rho_max)
    1049           96 :          ln_rho_min = LOG(rho_min)
    1050           96 :          q = twopi/(ln_rho_max - ln_rho_min)
    1051           96 :          dq = -f*q
    1052              :       END IF
    1053              : 
    1054          384 :       lb(1:3) = rho_elec%pw_grid%bounds_local(1, 1:3)
    1055          384 :       ub(1:3) = rho_elec%pw_grid%bounds_local(2, 1:3)
    1056              : 
    1057              :       ! Calculate the dielectric function and its derivative
    1058              : !$OMP PARALLEL DO DEFAULT(NONE) &
    1059              : !$OMP             PRIVATE(dt,i,j,k,rho,t,x,y) &
    1060              : !$OMP             SHARED(deps_elec,dq,eps_elec,epsilon_solvent,f,lb,ub) &
    1061           96 : !$OMP             SHARED(ln_rho_max,rho_elec,q,rho_max,rho_min)
    1062              :       DO k = lb(3), ub(3)
    1063              :          DO j = lb(2), ub(2)
    1064              :             DO i = lb(1), ub(1)
    1065              :                rho = rho_elec%array(i, j, k)
    1066              :                IF (rho < rho_min) THEN
    1067              :                   eps_elec%array(i, j, k) = epsilon_solvent
    1068              :                   deps_elec%array(i, j, k) = 0.0_dp
    1069              :                ELSE IF (rho <= rho_max) THEN
    1070              :                   x = LOG(rho)
    1071              :                   y = q*(ln_rho_max - x)
    1072              :                   t = f*(y - SIN(y))
    1073              :                   eps_elec%array(i, j, k) = EXP(t)
    1074              :                   dt = dq*(1.0_dp - COS(y))
    1075              :                   deps_elec%array(i, j, k) = eps_elec%array(i, j, k)*dt/rho
    1076              :                ELSE
    1077              :                   eps_elec%array(i, j, k) = 1.0_dp
    1078              :                   deps_elec%array(i, j, k) = 0.0_dp
    1079              :                END IF
    1080              :             END DO
    1081              :          END DO
    1082              :       END DO
    1083              : !$OMP END PARALLEL DO
    1084              : 
    1085           96 :       CALL timestop(handle)
    1086              : 
    1087           96 :    END SUBROUTINE andreussi
    1088              : 
    1089              : ! **************************************************************************************************
    1090              : !> \brief      Calculate the smoothed dielectric function of Fattebert and Gygi
    1091              : !> \param rho_elec ...
    1092              : !> \param eps_elec ...
    1093              : !> \param deps_elec ...
    1094              : !> \param epsilon_solvent ...
    1095              : !> \param beta ...
    1096              : !> \param rho_zero ...
    1097              : !> \par History:
    1098              : !>      - Creation (15.10.2013,MK)
    1099              : !> \author     Matthias Krack (MK)
    1100              : !> \version    1.0
    1101              : ! **************************************************************************************************
    1102           22 :    SUBROUTINE fattebert_gygi(rho_elec, eps_elec, deps_elec, epsilon_solvent, beta, &
    1103              :                              rho_zero)
    1104              : 
    1105              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: rho_elec, eps_elec, deps_elec
    1106              :       REAL(KIND=dp), INTENT(IN)                          :: epsilon_solvent, beta, rho_zero
    1107              : 
    1108              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'fattebert_gygi'
    1109              :       REAL(KIND=dp), PARAMETER                           :: rhotol = 1.0E-12_dp
    1110              : 
    1111              :       INTEGER                                            :: handle, i, j, k
    1112              :       INTEGER, DIMENSION(3)                              :: lb, ub
    1113              :       REAL(KIND=dp)                                      :: df, f, p, q, rho, s, t, twobeta
    1114              : 
    1115           22 :       CALL timeset(routineN, handle)
    1116              : 
    1117           22 :       df = (1.0_dp - epsilon_solvent)/rho_zero
    1118           22 :       f = 0.5_dp*(epsilon_solvent - 1.0_dp)
    1119           22 :       q = 1.0_dp/rho_zero
    1120           22 :       twobeta = 2.0_dp*beta
    1121              : 
    1122           88 :       lb(1:3) = rho_elec%pw_grid%bounds_local(1, 1:3)
    1123           88 :       ub(1:3) = rho_elec%pw_grid%bounds_local(2, 1:3)
    1124              : 
    1125              :       ! Calculate the smoothed dielectric function and its derivative
    1126              : !$OMP PARALLEL DO DEFAULT(NONE) &
    1127              : !$OMP             PRIVATE(i,j,k,p,rho,s,t) &
    1128              : !$OMP             SHARED(df,deps_elec,eps_elec,epsilon_solvent,f,lb,ub) &
    1129           22 : !$OMP             SHARED(q,rho_elec,twobeta)
    1130              :       DO k = lb(3), ub(3)
    1131              :          DO j = lb(2), ub(2)
    1132              :             DO i = lb(1), ub(1)
    1133              :                rho = rho_elec%array(i, j, k)
    1134              :                IF (rho < rhotol) THEN
    1135              :                   eps_elec%array(i, j, k) = epsilon_solvent
    1136              :                   deps_elec%array(i, j, k) = 0.0_dp
    1137              :                ELSE
    1138              :                   s = rho*q
    1139              :                   p = s**twobeta
    1140              :                   t = 1.0_dp/(1.0_dp + p)
    1141              :                   eps_elec%array(i, j, k) = 1.0_dp + f*(1.0_dp + (1.0_dp - p)*t)
    1142              :                   deps_elec%array(i, j, k) = df*twobeta*t*t*p/s
    1143              :                END IF
    1144              :             END DO
    1145              :          END DO
    1146              :       END DO
    1147              : !$OMP END PARALLEL DO
    1148              : 
    1149           22 :       CALL timestop(handle)
    1150              : 
    1151           22 :    END SUBROUTINE fattebert_gygi
    1152              : 
    1153              : ! **************************************************************************************************
    1154              : !> \brief      Calculate the smoothed dielectric function of solvent aware algorithm
    1155              : !> \param rho_elec ...
    1156              : !> \param eps_elec ...
    1157              : !> \param deps_elec ...
    1158              : !> \param epsilon_solvent ...
    1159              : !> \param rho_max ...
    1160              : !> \param rho_min ...
    1161              : !> \param s ...
    1162              : !> \param d_s_rhoel ...
    1163              : !> \author     Ziwei Chai
    1164              : !> \version    1.0
    1165              : ! **************************************************************************************************
    1166            0 :    SUBROUTINE sa_andreussi(rho_elec, eps_elec, deps_elec, epsilon_solvent, rho_max, &
    1167              :                            rho_min, s, d_s_rhoel)
    1168              : 
    1169              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: rho_elec, eps_elec, deps_elec
    1170              :       REAL(KIND=dp), INTENT(IN)                          :: epsilon_solvent, rho_max, rho_min
    1171              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: s, d_s_rhoel
    1172              : 
    1173              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'sa_andreussi'
    1174              :       REAL(KIND=dp), PARAMETER                           :: rhotol = 1.0E-12_dp
    1175              : 
    1176              :       INTEGER                                            :: handle, i, j, k
    1177              :       INTEGER, DIMENSION(3)                              :: lb, ub
    1178              :       REAL(KIND=dp)                                      :: diff, dq, dt, f, ln_rho_max, ln_rho_min, &
    1179              :                                                             q, rho, t, x, y
    1180              : 
    1181            0 :       CALL timeset(routineN, handle)
    1182              : 
    1183            0 :       f = LOG(epsilon_solvent)/twopi
    1184            0 :       diff = rho_max - rho_min
    1185            0 :       IF (diff < SQRT(rhotol)) CPABORT("SCCS: Difference between rho(min) and rho(max) is too small")
    1186            0 :       IF (rho_min >= rhotol) THEN
    1187            0 :          ln_rho_max = LOG(rho_max)
    1188            0 :          ln_rho_min = LOG(rho_min)
    1189            0 :          q = twopi/(ln_rho_max - ln_rho_min)
    1190            0 :          dq = -f*q
    1191              :       END IF
    1192              : 
    1193            0 :       lb(1:3) = rho_elec%pw_grid%bounds_local(1, 1:3)
    1194            0 :       ub(1:3) = rho_elec%pw_grid%bounds_local(2, 1:3)
    1195              : 
    1196              :       ! Calculate the dielectric function and its derivative
    1197              : !$OMP PARALLEL DO DEFAULT(NONE) &
    1198              : !$OMP             PRIVATE(dt,i,j,k,rho,t,x,y) &
    1199              : !$OMP             SHARED(deps_elec,dq,eps_elec,epsilon_solvent,f,lb,ub) &
    1200            0 : !$OMP             SHARED(ln_rho_max,rho_elec,q,rho_max,rho_min, s, d_s_rhoel)
    1201              :       DO k = lb(3), ub(3)
    1202              :          DO j = lb(2), ub(2)
    1203              :             DO i = lb(1), ub(1)
    1204              :                rho = rho_elec%array(i, j, k)
    1205              :                IF (rho < rho_min) THEN
    1206              :                   eps_elec%array(i, j, k) = epsilon_solvent
    1207              :                   s%array(i, j, k) = 0.0_dp
    1208              :                   deps_elec%array(i, j, k) = 0.0_dp
    1209              :                   d_s_rhoel%array(i, j, k) = 0.0_dp
    1210              :                ELSE IF (rho <= rho_max) THEN
    1211              :                   x = LOG(rho)
    1212              :                   y = q*(ln_rho_max - x)
    1213              :                   t = f*(y - SIN(y))
    1214              :                   s%array(i, j, k) = 1 - t/(f*twopi)
    1215              :                   eps_elec%array(i, j, k) = EXP(t)
    1216              :                   dt = dq*(1.0_dp - COS(y))
    1217              :                   deps_elec%array(i, j, k) = eps_elec%array(i, j, k)*dt/rho
    1218              :                   d_s_rhoel%array(i, j, k) = deps_elec%array(i, j, k)/(-eps_elec%array(i, j, k)*LOG(epsilon_solvent))
    1219              :                ELSE
    1220              :                   eps_elec%array(i, j, k) = 1.0_dp
    1221              :                   deps_elec%array(i, j, k) = 0.0_dp
    1222              :                   s%array(i, j, k) = 1.0_dp
    1223              :                   d_s_rhoel%array(i, j, k) = 0.0_dp
    1224              :                END IF
    1225              :             END DO
    1226              :          END DO
    1227              :       END DO
    1228              : !$OMP END PARALLEL DO
    1229              : 
    1230            0 :       CALL timestop(handle)
    1231              : 
    1232            0 :    END SUBROUTINE sa_andreussi
    1233              : 
    1234              : ! **************************************************************************************************
    1235              : !> \brief      Build the numerical derivative of a function on realspace grid
    1236              : !> \param f ...
    1237              : !> \param df ...
    1238              : !> \param method ...
    1239              : !> \param pw_env ...
    1240              : !> \param input ...
    1241              : !> \par History:
    1242              : !>      - Creation (15.11.2013,MK)
    1243              : !> \author     Matthias Krack (MK)
    1244              : !> \version    1.0
    1245              : ! **************************************************************************************************
    1246          236 :    SUBROUTINE derive(f, df, method, pw_env, input)
    1247              : 
    1248              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: f
    1249              :       TYPE(pw_r3d_rs_type), DIMENSION(3), INTENT(INOUT)  :: df
    1250              :       INTEGER, INTENT(IN)                                :: method
    1251              :       TYPE(pw_env_type), POINTER                         :: pw_env
    1252              :       TYPE(section_vals_type), POINTER                   :: input
    1253              : 
    1254              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'derive'
    1255              : 
    1256              :       INTEGER                                            :: border_points, handle, i
    1257              :       INTEGER, DIMENSION(3)                              :: lb, n, ub
    1258          708 :       TYPE(pw_c1d_gs_type), DIMENSION(2)                 :: work_g1d
    1259              :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
    1260              :       TYPE(realspace_grid_desc_type), POINTER            :: rs_desc
    1261              :       TYPE(realspace_grid_input_type)                    :: input_settings
    1262              :       TYPE(realspace_grid_type), POINTER                 :: rs_grid
    1263              :       TYPE(section_vals_type), POINTER                   :: rs_grid_section
    1264              : 
    1265          236 :       CALL timeset(routineN, handle)
    1266              : 
    1267          236 :       CPASSERT(ASSOCIATED(pw_env))
    1268              : 
    1269              :       ! Perform method specific setup
    1270          314 :       SELECT CASE (method)
    1271              :       CASE (sccs_derivative_cd3, sccs_derivative_cd5, sccs_derivative_cd7)
    1272           78 :          NULLIFY (rs_desc)
    1273           78 :          rs_grid_section => section_vals_get_subs_vals(input, "DFT%MGRID%RS_GRID")
    1274            0 :          SELECT CASE (method)
    1275              :          CASE (sccs_derivative_cd3)
    1276            0 :             border_points = 1
    1277              :          CASE (sccs_derivative_cd5)
    1278           78 :             border_points = 2
    1279              :          CASE (sccs_derivative_cd7)
    1280           78 :             border_points = 3
    1281              :          END SELECT
    1282              :          CALL init_input_type(input_settings, 2*border_points + 1, rs_grid_section, &
    1283           78 :                               1, [-1, -1, -1])
    1284              :          CALL rs_grid_create_descriptor(rs_desc, f%pw_grid, input_settings, &
    1285           78 :                                         border_points=border_points)
    1286         1638 :          ALLOCATE (rs_grid)
    1287           78 :          CALL rs_grid_create(rs_grid, rs_desc)
    1288              : !MK      CALL rs_grid_print(rs_grid, 6)
    1289              :       CASE (sccs_derivative_fft)
    1290          632 :          lb(1:3) = f%pw_grid%bounds_local(1, 1:3)
    1291          632 :          ub(1:3) = f%pw_grid%bounds_local(2, 1:3)
    1292          158 :          NULLIFY (auxbas_pw_pool)
    1293          158 :          CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
    1294              :          ! Get work storage for the 1d grids in g-space (derivative calculation)
    1295          710 :          DO i = 1, SIZE(work_g1d)
    1296          474 :             CALL auxbas_pw_pool%create_pw(work_g1d(i))
    1297              :          END DO
    1298              :       END SELECT
    1299              : 
    1300              :       ! Calculate the derivatives
    1301            0 :       SELECT CASE (method)
    1302              :       CASE (sccs_derivative_cd3)
    1303            0 :          CALL derive_fdm_cd3(f, df, rs_grid)
    1304              :       CASE (sccs_derivative_cd5)
    1305           78 :          CALL derive_fdm_cd5(f, df, rs_grid)
    1306              :       CASE (sccs_derivative_cd7)
    1307            0 :          CALL derive_fdm_cd7(f, df, rs_grid)
    1308              :       CASE (sccs_derivative_fft)
    1309              :          ! FFT
    1310          158 :          CALL pw_transfer(f, work_g1d(1))
    1311          632 :          DO i = 1, 3
    1312          474 :             n(:) = 0
    1313          474 :             n(i) = 1
    1314          474 :             CALL pw_copy(work_g1d(1), work_g1d(2))
    1315          474 :             CALL pw_derive(work_g1d(2), n(:))
    1316          632 :             CALL pw_transfer(work_g1d(2), df(i))
    1317              :          END DO
    1318              :       CASE DEFAULT
    1319          236 :          CPABORT("Invalid derivative method for SCCS specified")
    1320              :       END SELECT
    1321              : 
    1322              :       ! Perform method specific cleanup
    1323           78 :       SELECT CASE (method)
    1324              :       CASE (sccs_derivative_cd3, sccs_derivative_cd5, sccs_derivative_cd7)
    1325           78 :          CALL rs_grid_release(rs_grid)
    1326           78 :          DEALLOCATE (rs_grid)
    1327           78 :          CALL rs_grid_release_descriptor(rs_desc)
    1328              :       CASE (sccs_derivative_fft)
    1329          710 :          DO i = 1, SIZE(work_g1d)
    1330          474 :             CALL auxbas_pw_pool%give_back_pw(work_g1d(i))
    1331              :          END DO
    1332              :       END SELECT
    1333              : 
    1334          236 :       CALL timestop(handle)
    1335              : 
    1336          944 :    END SUBROUTINE derive
    1337              : 
    1338              : ! **************************************************************************************************
    1339              : !> \brief      Calculate the finite difference between two isosurfaces of the
    1340              : !>             electronic density. The smoothed dielectric function of
    1341              : !>             Andreussi et al. is used as switching function eventually
    1342              : !>             defining the quantum volume and surface of the cavity.
    1343              : !> \param rho_elec ...
    1344              : !> \param norm_drho_elec ...
    1345              : !> \param dtheta ...
    1346              : !> \param epsilon_solvent ...
    1347              : !> \param rho_max ...
    1348              : !> \param rho_min ...
    1349              : !> \param delta_rho ...
    1350              : !> \par History:
    1351              : !>      - Creation (21.12.2013,MK)
    1352              : !> \author     Matthias Krack (MK)
    1353              : !> \version    1.0
    1354              : ! **************************************************************************************************
    1355           96 :    SUBROUTINE surface_andreussi(rho_elec, norm_drho_elec, dtheta, &
    1356              :                                 epsilon_solvent, rho_max, rho_min, delta_rho)
    1357              : 
    1358              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: rho_elec, norm_drho_elec, dtheta
    1359              :       REAL(KIND=dp), INTENT(IN)                          :: epsilon_solvent, rho_max, rho_min, &
    1360              :                                                             delta_rho
    1361              : 
    1362              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'surface_andreussi'
    1363              :       REAL(KIND=dp), PARAMETER                           :: rhotol = 1.0E-12_dp
    1364              : 
    1365              :       INTEGER                                            :: handle, i, j, k, l
    1366              :       INTEGER, DIMENSION(3)                              :: lb, ub
    1367              :       REAL(KIND=dp)                                      :: diff, e, eps_elec, f, ln_rho_max, &
    1368              :                                                             ln_rho_min, q, rho, t, x, y
    1369              :       REAL(KIND=dp), DIMENSION(2)                        :: theta
    1370              : 
    1371           96 :       CALL timeset(routineN, handle)
    1372              : 
    1373           96 :       e = epsilon_solvent - 1.0_dp
    1374           96 :       f = LOG(epsilon_solvent)/twopi
    1375           96 :       diff = rho_max - rho_min
    1376           96 :       IF (diff < SQRT(rhotol)) CPABORT("SCCS: Difference between rho(min) and rho(max) is too small")
    1377           96 :       IF (rho_min >= rhotol) THEN
    1378           96 :          ln_rho_max = LOG(rho_max)
    1379           96 :          ln_rho_min = LOG(rho_min)
    1380           96 :          q = twopi/(ln_rho_max - ln_rho_min)
    1381              :       END IF
    1382              : 
    1383          384 :       lb(1:3) = rho_elec%pw_grid%bounds_local(1, 1:3)
    1384          384 :       ub(1:3) = rho_elec%pw_grid%bounds_local(2, 1:3)
    1385              : 
    1386              :       ! Calculate finite difference between two isosurfaces
    1387              : !$OMP PARALLEL DO DEFAULT(NONE) &
    1388              : !$OMP             PRIVATE(eps_elec,i,j,k,l,rho,t,theta,x,y) &
    1389              : !$OMP             SHARED(delta_rho,dtheta,e,epsilon_solvent,f,lb) &
    1390           96 : !$OMP             SHARED(ln_rho_max,norm_drho_elec,rho_elec,q,rho_max,rho_min,ub)
    1391              :       DO k = lb(3), ub(3)
    1392              :          DO j = lb(2), ub(2)
    1393              :             DO i = lb(1), ub(1)
    1394              :                DO l = 1, 2
    1395              :                   rho = rho_elec%array(i, j, k) + (REAL(l, KIND=dp) - 1.5_dp)*delta_rho
    1396              :                   IF (rho < rho_min) THEN
    1397              :                      eps_elec = epsilon_solvent
    1398              :                   ELSE IF (rho <= rho_max) THEN
    1399              :                      x = LOG(rho)
    1400              :                      y = q*(ln_rho_max - x)
    1401              :                      t = f*(y - SIN(y))
    1402              :                      eps_elec = EXP(t)
    1403              :                   ELSE
    1404              :                      eps_elec = 1.0_dp
    1405              :                   END IF
    1406              :                   theta(l) = (epsilon_solvent - eps_elec)/e
    1407              :                END DO
    1408              :                dtheta%array(i, j, k) = (theta(2) - theta(1))*norm_drho_elec%array(i, j, k)/delta_rho
    1409              :             END DO
    1410              :          END DO
    1411              :       END DO
    1412              : !$OMP END PARALLEL DO
    1413              : 
    1414           96 :       CALL timestop(handle)
    1415              : 
    1416           96 :    END SUBROUTINE surface_andreussi
    1417              : 
    1418              : ! **************************************************************************************************
    1419              : !> \brief      Calculate the finite difference between two isosurfaces of the
    1420              : !>             the electronic density. The smoothed dielectric function of
    1421              : !>             Fattebert and Gygi is used as switching function eventually
    1422              : !>             defining the quantum volume and surface of the cavity.
    1423              : !> \param rho_elec ...
    1424              : !> \param norm_drho_elec ...
    1425              : !> \param dtheta ...
    1426              : !> \param epsilon_solvent ...
    1427              : !> \param beta ...
    1428              : !> \param rho_zero ...
    1429              : !> \param delta_rho ...
    1430              : !> \par History:
    1431              : !>      - Creation (21.12.2013,MK)
    1432              : !> \author     Matthias Krack (MK)
    1433              : !> \version    1.0
    1434              : ! **************************************************************************************************
    1435           22 :    SUBROUTINE surface_fattebert_gygi(rho_elec, norm_drho_elec, dtheta, &
    1436              :                                      epsilon_solvent, beta, rho_zero, delta_rho)
    1437              : 
    1438              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: rho_elec, norm_drho_elec, dtheta
    1439              :       REAL(KIND=dp), INTENT(IN)                          :: epsilon_solvent, beta, rho_zero, &
    1440              :                                                             delta_rho
    1441              : 
    1442              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'surface_fattebert_gygi'
    1443              :       REAL(KIND=dp), PARAMETER                           :: rhotol = 1.0E-12_dp
    1444              : 
    1445              :       INTEGER                                            :: handle, i, j, k, l
    1446              :       INTEGER, DIMENSION(3)                              :: lb, ub
    1447              :       REAL(KIND=dp)                                      :: e, eps_elec, f, p, q, rho, s, t, twobeta
    1448              :       REAL(KIND=dp), DIMENSION(2)                        :: theta
    1449              : 
    1450           22 :       CALL timeset(routineN, handle)
    1451              : 
    1452           22 :       e = epsilon_solvent - 1.0_dp
    1453           22 :       f = 0.5_dp*e
    1454           22 :       q = 1.0_dp/rho_zero
    1455           22 :       twobeta = 2.0_dp*beta
    1456              : 
    1457           88 :       lb(1:3) = rho_elec%pw_grid%bounds_local(1, 1:3)
    1458           88 :       ub(1:3) = rho_elec%pw_grid%bounds_local(2, 1:3)
    1459              : 
    1460              :       ! Calculate finite difference between two isosurfaces
    1461              : !$OMP PARALLEL DO DEFAULT(NONE) &
    1462              : !$OMP             PRIVATE(eps_elec,i,j,k,l,p,rho,s,t,theta) &
    1463              : !$OMP             SHARED(delta_rho,dtheta,e,epsilon_solvent,f,lb) &
    1464           22 : !$OMP             SHARED(norm_drho_elec,q,rho_elec,twobeta,ub)
    1465              :       DO k = lb(3), ub(3)
    1466              :          DO j = lb(2), ub(2)
    1467              :             DO i = lb(1), ub(1)
    1468              :                DO l = 1, 2
    1469              :                   rho = rho_elec%array(i, j, k) + (REAL(l, KIND=dp) - 1.5_dp)*delta_rho
    1470              :                   IF (rho < rhotol) THEN
    1471              :                      eps_elec = epsilon_solvent
    1472              :                   ELSE
    1473              :                      s = rho*q
    1474              :                      p = s**twobeta
    1475              :                      t = 1.0_dp/(1.0_dp + p)
    1476              :                      eps_elec = 1.0_dp + f*(1.0_dp + (1.0_dp - p)*t)
    1477              :                   END IF
    1478              :                   theta(l) = (epsilon_solvent - eps_elec)/e
    1479              :                END DO
    1480              :                dtheta%array(i, j, k) = (theta(2) - theta(1))*norm_drho_elec%array(i, j, k)/delta_rho
    1481              :             END DO
    1482              :          END DO
    1483              :       END DO
    1484              : !$OMP END PARALLEL DO
    1485              : 
    1486           22 :       CALL timestop(handle)
    1487              : 
    1488           22 :    END SUBROUTINE surface_fattebert_gygi
    1489              : 
    1490              : ! **************************************************************************************************
    1491              : !> \brief      Print SCCS results
    1492              : !> \param energy ...
    1493              : !> \param sccs_control ...
    1494              : !> \param output_unit ...
    1495              : !> \par History:
    1496              : !>      - Creation (11.11.2022,MK)
    1497              : !> \author     Matthias Krack (MK)
    1498              : !> \version    1.0
    1499              : ! **************************************************************************************************
    1500           53 :    SUBROUTINE print_sccs_results(energy, sccs_control, output_unit)
    1501              : 
    1502              :       TYPE(qs_energy_type), POINTER                      :: energy
    1503              :       TYPE(sccs_control_type), POINTER                   :: sccs_control
    1504              :       INTEGER, INTENT(IN)                                :: output_unit
    1505              : 
    1506           53 :       IF (output_unit > 0) THEN
    1507           53 :          CPASSERT(ASSOCIATED(energy))
    1508           53 :          CPASSERT(ASSOCIATED(sccs_control))
    1509              :          WRITE (UNIT=output_unit, FMT="(T3,A,T56,F25.14)") &
    1510           53 :             "SCCS| Hartree energy of solute and solvent [Hartree]", energy%sccs_hartree, &
    1511          106 :             "SCCS| Hartree energy of the solute only    [Hartree]", energy%hartree
    1512              :          WRITE (UNIT=output_unit, FMT="(T3,A,T56,F25.14,/,T3,A,T61,F20.3)") &
    1513           53 :             "SCCS| Polarisation energy                  [Hartree]", energy%sccs_pol, &
    1514           53 :             "SCCS|                                      [kcal/mol]", &
    1515           53 :             cp_unit_from_cp2k(energy%sccs_pol, "kcalmol"), &
    1516           53 :             "SCCS| Cavitation energy                    [Hartree]", energy%sccs_cav, &
    1517           53 :             "SCCS|                                      [kcal/mol]", &
    1518           53 :             cp_unit_from_cp2k(energy%sccs_cav, "kcalmol"), &
    1519           53 :             "SCCS| Dispersion free energy               [Hartree]", energy%sccs_dis, &
    1520           53 :             "SCCS|                                      [kcal/mol]", &
    1521           53 :             cp_unit_from_cp2k(energy%sccs_dis, "kcalmol"), &
    1522           53 :             "SCCS| Repulsion free energy                [Hartree]", energy%sccs_rep, &
    1523           53 :             "SCCS|                                      [kcal/mol]", &
    1524           53 :             cp_unit_from_cp2k(energy%sccs_rep, "kcalmol"), &
    1525           53 :             "SCCS| Solvation free energy                [Hartree]", energy%sccs_sol, &
    1526           53 :             "SCCS|                                      [kcal/mol]", &
    1527          106 :             cp_unit_from_cp2k(energy%sccs_sol, "kcalmol")
    1528              :       END IF
    1529              : 
    1530           53 :    END SUBROUTINE print_sccs_results
    1531              : 
    1532              : END MODULE qs_sccs
        

Generated by: LCOV version 2.0-1