LCOV - code coverage report
Current view: top level - src - qs_sccs.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:4dc10b3) Lines: 333 391 85.2 %
Date: 2024-11-21 06:45:46 Functions: 7 7 100.0 %

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

Generated by: LCOV version 1.15