LCOV - code coverage report
Current view: top level - src - qs_sccs.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 85.4 % 391 334
Test Date: 2025-12-04 06:27:48 Functions: 100.0 % 7 7

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

Generated by: LCOV version 2.0-1