LCOV - code coverage report
Current view: top level - src - qs_resp.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 92.2 % 812 749
Test Date: 2026-07-25 06:35:44 Functions: 88.9 % 18 16

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief provides a resp fit for gas phase systems
      10              : !> \par History
      11              : !>      created
      12              : !>      Dorothea Golze [06.2012] (1) extension to periodic systems
      13              : !>                               (2) re-structured the code
      14              : !> \author Joost VandeVondele (02.2007)
      15              : ! **************************************************************************************************
      16              : MODULE qs_resp
      17              :    USE atomic_charges,                  ONLY: print_atomic_charges
      18              :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      19              :                                               get_atomic_kind
      20              :    USE bibliography,                    ONLY: Campana2009,&
      21              :                                               Golze2015,&
      22              :                                               Rappe1992,&
      23              :                                               cite_reference
      24              :    USE cell_types,                      ONLY: cell_type,&
      25              :                                               get_cell,&
      26              :                                               pbc,&
      27              :                                               use_perd_none,&
      28              :                                               use_perd_xyz
      29              :    USE cp_control_types,                ONLY: dft_control_type
      30              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      31              :                                               cp_logger_type
      32              :    USE cp_output_handling,              ONLY: cp_p_file,&
      33              :                                               cp_print_key_finished_output,&
      34              :                                               cp_print_key_generate_filename,&
      35              :                                               cp_print_key_should_output,&
      36              :                                               cp_print_key_unit_nr
      37              :    USE cp_realspace_grid_cube,          ONLY: cp_pw_to_cube
      38              :    USE cp_units,                        ONLY: cp_unit_from_cp2k,&
      39              :                                               cp_unit_to_cp2k
      40              :    USE input_constants,                 ONLY: do_resp_minus_x_dir,&
      41              :                                               do_resp_minus_y_dir,&
      42              :                                               do_resp_minus_z_dir,&
      43              :                                               do_resp_x_dir,&
      44              :                                               do_resp_y_dir,&
      45              :                                               do_resp_z_dir,&
      46              :                                               use_cambridge_vdw_radii,&
      47              :                                               use_uff_vdw_radii
      48              :    USE input_section_types,             ONLY: section_get_ivals,&
      49              :                                               section_get_lval,&
      50              :                                               section_vals_get,&
      51              :                                               section_vals_get_subs_vals,&
      52              :                                               section_vals_type,&
      53              :                                               section_vals_val_get
      54              :    USE kahan_sum,                       ONLY: accurate_sum
      55              :    USE kinds,                           ONLY: default_path_length,&
      56              :                                               default_string_length,&
      57              :                                               dp
      58              :    USE machine,                         ONLY: m_flush
      59              :    USE mathconstants,                   ONLY: pi
      60              :    USE memory_utilities,                ONLY: reallocate
      61              :    USE message_passing,                 ONLY: mp_para_env_type,&
      62              :                                               mp_request_type
      63              :    USE particle_list_types,             ONLY: particle_list_type
      64              :    USE particle_types,                  ONLY: particle_type
      65              :    USE periodic_table,                  ONLY: get_ptable_info
      66              :    USE pw_env_types,                    ONLY: pw_env_get,&
      67              :                                               pw_env_type
      68              :    USE pw_methods,                      ONLY: pw_copy,&
      69              :                                               pw_scale,&
      70              :                                               pw_transfer,&
      71              :                                               pw_zero
      72              :    USE pw_poisson_methods,              ONLY: pw_poisson_solve
      73              :    USE pw_poisson_types,                ONLY: pw_poisson_type
      74              :    USE pw_pool_types,                   ONLY: pw_pool_type
      75              :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      76              :                                               pw_r3d_rs_type
      77              :    USE qs_collocate_density,            ONLY: calculate_rho_resp_all,&
      78              :                                               calculate_rho_resp_single
      79              :    USE qs_environment_types,            ONLY: get_qs_env,&
      80              :                                               qs_environment_type,&
      81              :                                               set_qs_env
      82              :    USE qs_kind_types,                   ONLY: qs_kind_type
      83              :    USE qs_subsys_types,                 ONLY: qs_subsys_get,&
      84              :                                               qs_subsys_type
      85              :    USE uff_vdw_radii_table,             ONLY: get_uff_vdw_radius
      86              : #include "./base/base_uses.f90"
      87              : 
      88              :    IMPLICIT NONE
      89              : 
      90              :    PRIVATE
      91              : 
      92              : ! *** Global parameters ***
      93              : 
      94              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_resp'
      95              : 
      96              :    PUBLIC :: resp_fit
      97              : 
      98              :    TYPE resp_type
      99              :       LOGICAL                                :: equal_charges = .FALSE., itc = .FALSE., &
     100              :                                                 molecular_sys = .FALSE., rheavies = .FALSE., &
     101              :                                                 use_repeat_method = .FALSE.
     102              :       INTEGER                                :: nres = -1, ncons = -1, &
     103              :                                                 nrest_sec = -1, ncons_sec = -1, &
     104              :                                                 npoints = -1, stride(3) = -1, my_fit = -1, &
     105              :                                                 npoints_proc = -1, &
     106              :                                                 auto_vdw_radii_table = -1
     107              :       INTEGER, DIMENSION(:), POINTER         :: atom_surf_list => NULL()
     108              :       INTEGER, DIMENSION(:, :), POINTER       :: fitpoints => NULL()
     109              :       REAL(KIND=dp)                          :: rheavies_strength = -1.0_dp, &
     110              :                                                 length = -1.0_dp, eta = -1.0_dp, &
     111              :                                                 sum_vhartree = -1.0_dp, offset = -1.0_dp
     112              :       REAL(KIND=dp), DIMENSION(3)            :: box_hi = -1.0_dp, box_low = -1.0_dp
     113              :       REAL(KIND=dp), DIMENSION(:), POINTER   :: rmin_kind => NULL(), &
     114              :                                                 rmax_kind => NULL()
     115              :       REAL(KIND=dp), DIMENSION(:), POINTER   :: range_surf => NULL()
     116              :       REAL(KIND=dp), DIMENSION(:), POINTER   :: rhs => NULL()
     117              :       REAL(KIND=dp), DIMENSION(:), POINTER   :: sum_vpot => NULL()
     118              :       REAL(KIND=dp), DIMENSION(:, :), POINTER :: matrix => NULL()
     119              :    END TYPE resp_type
     120              : 
     121              :    TYPE resp_p_type
     122              :       TYPE(resp_type), POINTER              ::  p_resp => NULL()
     123              :    END TYPE resp_p_type
     124              : 
     125              : CONTAINS
     126              : 
     127              : ! **************************************************************************************************
     128              : !> \brief performs resp fit and generates RESP charges
     129              : !> \param qs_env the qs environment
     130              : ! **************************************************************************************************
     131        11629 :    SUBROUTINE resp_fit(qs_env)
     132              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     133              : 
     134              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'resp_fit'
     135              : 
     136              :       INTEGER                                            :: handle, info, my_per, natom, nvar, &
     137              :                                                             output_unit
     138        11629 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ipiv
     139              :       LOGICAL                                            :: has_resp
     140        11629 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: rhs_to_save
     141        11629 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     142              :       TYPE(cell_type), POINTER                           :: cell
     143              :       TYPE(cp_logger_type), POINTER                      :: logger
     144              :       TYPE(dft_control_type), POINTER                    :: dft_control
     145              :       TYPE(particle_list_type), POINTER                  :: particles
     146        11629 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     147              :       TYPE(qs_subsys_type), POINTER                      :: subsys
     148        11629 :       TYPE(resp_p_type), DIMENSION(:), POINTER           :: rep_sys
     149              :       TYPE(resp_type), POINTER                           :: resp_env
     150              :       TYPE(section_vals_type), POINTER                   :: cons_section, input, poisson_section, &
     151              :                                                             resp_section, rest_section
     152              : 
     153        11629 :       CALL timeset(routineN, handle)
     154              : 
     155        11629 :       NULLIFY (logger, atomic_kind_set, cell, subsys, particles, particle_set, input, &
     156        11629 :                resp_section, cons_section, rest_section, poisson_section, resp_env, rep_sys)
     157              : 
     158        11629 :       CPASSERT(ASSOCIATED(qs_env))
     159              : 
     160              :       CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, input=input, &
     161        11629 :                       subsys=subsys, particle_set=particle_set, cell=cell)
     162        11629 :       resp_section => section_vals_get_subs_vals(input, "PROPERTIES%RESP")
     163        11629 :       CALL section_vals_get(resp_section, explicit=has_resp)
     164              : 
     165        11629 :       IF (has_resp) THEN
     166           14 :          logger => cp_get_default_logger()
     167           14 :          poisson_section => section_vals_get_subs_vals(input, "DFT%POISSON")
     168           14 :          CALL section_vals_val_get(poisson_section, "PERIODIC", i_val=my_per)
     169           14 :          CALL create_resp_type(resp_env, rep_sys)
     170              :          !initialize the RESP fitting, get all the keywords
     171              :          CALL init_resp(resp_env, rep_sys, subsys, atomic_kind_set, &
     172           14 :                         cell, resp_section, cons_section, rest_section)
     173              : 
     174              :          !print info
     175           14 :          CALL print_resp_parameter_info(qs_env, resp_env, rep_sys, my_per)
     176              : 
     177           14 :          CALL qs_subsys_get(subsys, particles=particles)
     178           14 :          natom = particles%n_els
     179           14 :          nvar = natom + resp_env%ncons
     180              : 
     181           14 :          CALL resp_allocate(resp_env, natom, nvar)
     182           42 :          ALLOCATE (ipiv(nvar))
     183           14 :          ipiv = 0
     184              : 
     185              :          ! calculate the matrix and the vector rhs
     186            4 :          SELECT CASE (my_per)
     187              :          CASE (use_perd_none)
     188              :             CALL calc_resp_matrix_nonper(qs_env, resp_env, atomic_kind_set, particles, cell, &
     189            4 :                                          resp_env%matrix, resp_env%rhs, natom)
     190              :          CASE (use_perd_xyz)
     191           10 :             CALL cite_reference(Golze2015)
     192           10 :             IF (resp_env%use_repeat_method) CALL cite_reference(Campana2009)
     193           10 :             CALL calc_resp_matrix_periodic(qs_env, resp_env, rep_sys, particles, cell, natom)
     194              :          CASE DEFAULT
     195              :             CALL cp_abort(__LOCATION__, &
     196              :                           "RESP charges only implemented for nonperiodic systems"// &
     197           14 :                           " or XYZ periodicity!")
     198              :          END SELECT
     199              : 
     200              :          output_unit = cp_print_key_unit_nr(logger, resp_section, "PRINT%PROGRAM_RUN_INFO", &
     201           14 :                                             extension=".resp")
     202           14 :          IF (output_unit > 0) THEN
     203              :             WRITE (output_unit, '(T3,A,T69,I12)') "Number of fitting points "// &
     204            7 :                "found: ", resp_env%npoints
     205            7 :             WRITE (output_unit, '()')
     206              :          END IF
     207              : 
     208              :          !adding restraints and constraints
     209              :          CALL add_restraints_and_constraints(qs_env, resp_env, rest_section, &
     210           14 :                                              subsys, natom, cons_section, particle_set)
     211              : 
     212              :          !solve system for the values of the charges and the lagrangian multipliers
     213           14 :          CALL DGETRF(nvar, nvar, resp_env%matrix, nvar, ipiv, info)
     214           14 :          CPASSERT(info == 0)
     215              : 
     216           14 :          CALL DGETRS('N', nvar, 1, resp_env%matrix, nvar, ipiv, resp_env%rhs, nvar, info)
     217           14 :          CPASSERT(info == 0)
     218              : 
     219           14 :          IF (resp_env%use_repeat_method) resp_env%offset = resp_env%rhs(natom + 1)
     220           14 :          CALL print_resp_charges(qs_env, resp_env, output_unit, natom)
     221           14 :          CALL print_fitting_points(qs_env, resp_env)
     222           14 :          CALL print_pot_from_resp_charges(qs_env, resp_env, particles, natom, output_unit)
     223              : 
     224              :          ! In case of density functional embedding we need to save  the charges to qs_env
     225           14 :          NULLIFY (dft_control)
     226           14 :          CALL get_qs_env(qs_env, dft_control=dft_control)
     227           14 :          IF (dft_control%qs_control%ref_embed_subsys) THEN
     228            6 :             ALLOCATE (rhs_to_save(SIZE(resp_env%rhs)))
     229           28 :             rhs_to_save = resp_env%rhs
     230            2 :             CALL set_qs_env(qs_env, rhs=rhs_to_save)
     231              :          END IF
     232              : 
     233           14 :          DEALLOCATE (ipiv)
     234           14 :          CALL resp_dealloc(resp_env, rep_sys)
     235              :          CALL cp_print_key_finished_output(output_unit, logger, resp_section, &
     236           28 :                                            "PRINT%PROGRAM_RUN_INFO")
     237              : 
     238              :       END IF
     239              : 
     240        11629 :       CALL timestop(handle)
     241              : 
     242        11629 :    END SUBROUTINE resp_fit
     243              : 
     244              : ! **************************************************************************************************
     245              : !> \brief creates the resp_type structure
     246              : !> \param resp_env the resp environment
     247              : !> \param rep_sys structure for repeating input sections defining fit points
     248              : ! **************************************************************************************************
     249           14 :    SUBROUTINE create_resp_type(resp_env, rep_sys)
     250              :       TYPE(resp_type), POINTER                           :: resp_env
     251              :       TYPE(resp_p_type), DIMENSION(:), POINTER           :: rep_sys
     252              : 
     253           14 :       IF (ASSOCIATED(resp_env)) CALL resp_dealloc(resp_env, rep_sys)
     254          182 :       ALLOCATE (resp_env)
     255              : 
     256              :       NULLIFY (resp_env%matrix, &
     257              :                resp_env%fitpoints, &
     258              :                resp_env%rmin_kind, &
     259              :                resp_env%rmax_kind, &
     260              :                resp_env%rhs, &
     261              :                resp_env%sum_vpot)
     262              : 
     263              :       resp_env%equal_charges = .FALSE.
     264              :       resp_env%itc = .FALSE.
     265              :       resp_env%molecular_sys = .FALSE.
     266              :       resp_env%rheavies = .FALSE.
     267              :       resp_env%use_repeat_method = .FALSE.
     268              : 
     269           56 :       resp_env%box_hi = 0.0_dp
     270           56 :       resp_env%box_low = 0.0_dp
     271              : 
     272           14 :       resp_env%ncons = 0
     273           14 :       resp_env%ncons_sec = 0
     274           14 :       resp_env%nres = 0
     275           14 :       resp_env%nrest_sec = 0
     276           14 :       resp_env%npoints = 0
     277           14 :       resp_env%npoints_proc = 0
     278           14 :       resp_env%auto_vdw_radii_table = use_cambridge_vdw_radii
     279              : 
     280           14 :    END SUBROUTINE create_resp_type
     281              : 
     282              : ! **************************************************************************************************
     283              : !> \brief allocates the resp
     284              : !> \param resp_env the resp environment
     285              : !> \param natom ...
     286              : !> \param nvar ...
     287              : ! **************************************************************************************************
     288           14 :    SUBROUTINE resp_allocate(resp_env, natom, nvar)
     289              :       TYPE(resp_type), POINTER                           :: resp_env
     290              :       INTEGER, INTENT(IN)                                :: natom, nvar
     291              : 
     292           14 :       IF (.NOT. ASSOCIATED(resp_env%matrix)) THEN
     293           56 :          ALLOCATE (resp_env%matrix(nvar, nvar))
     294              :       END IF
     295           14 :       IF (.NOT. ASSOCIATED(resp_env%rhs)) THEN
     296           42 :          ALLOCATE (resp_env%rhs(nvar))
     297              :       END IF
     298           14 :       IF (.NOT. ASSOCIATED(resp_env%sum_vpot)) THEN
     299           42 :          ALLOCATE (resp_env%sum_vpot(natom))
     300              :       END IF
     301         1258 :       resp_env%matrix = 0.0_dp
     302          138 :       resp_env%rhs = 0.0_dp
     303          104 :       resp_env%sum_vpot = 0.0_dp
     304              : 
     305           14 :    END SUBROUTINE resp_allocate
     306              : 
     307              : ! **************************************************************************************************
     308              : !> \brief deallocates the resp_type structure
     309              : !> \param resp_env the resp environment
     310              : !> \param rep_sys structure for repeating input sections defining fit points
     311              : ! **************************************************************************************************
     312           14 :    SUBROUTINE resp_dealloc(resp_env, rep_sys)
     313              :       TYPE(resp_type), POINTER                           :: resp_env
     314              :       TYPE(resp_p_type), DIMENSION(:), POINTER           :: rep_sys
     315              : 
     316              :       INTEGER                                            :: i
     317              : 
     318           14 :       IF (ASSOCIATED(resp_env)) THEN
     319           14 :          IF (ASSOCIATED(resp_env%matrix)) THEN
     320           14 :             DEALLOCATE (resp_env%matrix)
     321              :          END IF
     322           14 :          IF (ASSOCIATED(resp_env%rhs)) THEN
     323           14 :             DEALLOCATE (resp_env%rhs)
     324              :          END IF
     325           14 :          IF (ASSOCIATED(resp_env%sum_vpot)) THEN
     326           14 :             DEALLOCATE (resp_env%sum_vpot)
     327              :          END IF
     328           14 :          IF (ASSOCIATED(resp_env%fitpoints)) THEN
     329           14 :             DEALLOCATE (resp_env%fitpoints)
     330              :          END IF
     331           14 :          IF (ASSOCIATED(resp_env%rmin_kind)) THEN
     332           10 :             DEALLOCATE (resp_env%rmin_kind)
     333              :          END IF
     334           14 :          IF (ASSOCIATED(resp_env%rmax_kind)) THEN
     335           10 :             DEALLOCATE (resp_env%rmax_kind)
     336              :          END IF
     337           14 :          DEALLOCATE (resp_env)
     338              :       END IF
     339           14 :       IF (ASSOCIATED(rep_sys)) THEN
     340            8 :          DO i = 1, SIZE(rep_sys)
     341            4 :             DEALLOCATE (rep_sys(i)%p_resp%atom_surf_list)
     342            8 :             DEALLOCATE (rep_sys(i)%p_resp)
     343              :          END DO
     344            4 :          DEALLOCATE (rep_sys)
     345              :       END IF
     346              : 
     347           14 :    END SUBROUTINE resp_dealloc
     348              : 
     349              : ! **************************************************************************************************
     350              : !> \brief initializes the resp fit. Getting the parameters
     351              : !> \param resp_env the resp environment
     352              : !> \param rep_sys structure for repeating input sections defining fit points
     353              : !> \param subsys ...
     354              : !> \param atomic_kind_set ...
     355              : !> \param cell parameters related to the simulation cell
     356              : !> \param resp_section resp section
     357              : !> \param cons_section constraints section, part of resp section
     358              : !> \param rest_section restraints section, part of resp section
     359              : ! **************************************************************************************************
     360           14 :    SUBROUTINE init_resp(resp_env, rep_sys, subsys, atomic_kind_set, &
     361              :                         cell, resp_section, cons_section, rest_section)
     362              : 
     363              :       TYPE(resp_type), POINTER                           :: resp_env
     364              :       TYPE(resp_p_type), DIMENSION(:), POINTER           :: rep_sys
     365              :       TYPE(qs_subsys_type), POINTER                      :: subsys
     366              :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     367              :       TYPE(cell_type), POINTER                           :: cell
     368              :       TYPE(section_vals_type), POINTER                   :: resp_section, cons_section, rest_section
     369              : 
     370              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'init_resp'
     371              : 
     372              :       INTEGER                                            :: handle, i, nrep
     373           14 :       INTEGER, DIMENSION(:), POINTER                     :: atom_list_cons, my_stride
     374              :       LOGICAL                                            :: explicit
     375              :       TYPE(section_vals_type), POINTER                   :: slab_section, sphere_section
     376              : 
     377           14 :       CALL timeset(routineN, handle)
     378              : 
     379           14 :       NULLIFY (atom_list_cons, my_stride, sphere_section, slab_section)
     380              : 
     381              :       ! get the subsections
     382           14 :       sphere_section => section_vals_get_subs_vals(resp_section, "SPHERE_SAMPLING")
     383           14 :       slab_section => section_vals_get_subs_vals(resp_section, "SLAB_SAMPLING")
     384           14 :       cons_section => section_vals_get_subs_vals(resp_section, "CONSTRAINT")
     385           14 :       rest_section => section_vals_get_subs_vals(resp_section, "RESTRAINT")
     386              : 
     387              :       ! get the general keywords
     388              :       CALL section_vals_val_get(resp_section, "INTEGER_TOTAL_CHARGE", &
     389           14 :                                 l_val=resp_env%itc)
     390           14 :       IF (resp_env%itc) resp_env%ncons = resp_env%ncons + 1
     391              : 
     392              :       CALL section_vals_val_get(resp_section, "RESTRAIN_HEAVIES_TO_ZERO", &
     393           14 :                                 l_val=resp_env%rheavies)
     394           14 :       IF (resp_env%rheavies) THEN
     395              :          CALL section_vals_val_get(resp_section, "RESTRAIN_HEAVIES_STRENGTH", &
     396           14 :                                    r_val=resp_env%rheavies_strength)
     397              :       END IF
     398           14 :       CALL section_vals_val_get(resp_section, "STRIDE", i_vals=my_stride)
     399           14 :       IF (SIZE(my_stride) /= 1 .AND. SIZE(my_stride) /= 3) THEN
     400              :          CALL cp_abort(__LOCATION__, "STRIDE keyword can accept only 1 (the same for X,Y,Z) "// &
     401            0 :                        "or 3 values. Correct your input file.")
     402              :       END IF
     403           14 :       IF (SIZE(my_stride) == 1) THEN
     404           48 :          DO i = 1, 3
     405           48 :             resp_env%stride(i) = my_stride(1)
     406              :          END DO
     407              :       ELSE
     408           16 :          resp_env%stride = my_stride(1:3)
     409              :       END IF
     410           14 :       CALL section_vals_val_get(resp_section, "WIDTH", r_val=resp_env%eta)
     411              : 
     412              :       ! get if the user wants to use REPEAT method
     413              :       CALL section_vals_val_get(resp_section, "USE_REPEAT_METHOD", &
     414           14 :                                 l_val=resp_env%use_repeat_method)
     415           14 :       IF (resp_env%use_repeat_method) THEN
     416            4 :          resp_env%ncons = resp_env%ncons + 1
     417              :          ! restrain heavies should be off
     418            4 :          resp_env%rheavies = .FALSE.
     419              :       END IF
     420              : 
     421              :       ! get and set the parameters for molecular (non-surface) systems
     422              :       ! this must come after the repeat settings being set
     423              :       CALL get_parameter_molecular_sys(resp_env, sphere_section, cell, &
     424           14 :                                        atomic_kind_set)
     425              : 
     426              :       ! get the parameter for periodic/surface systems
     427           14 :       CALL section_vals_get(slab_section, explicit=explicit, n_repetition=nrep)
     428           14 :       IF (explicit) THEN
     429            4 :          IF (resp_env%molecular_sys) THEN
     430              :             CALL cp_abort(__LOCATION__, &
     431              :                           "You can only use either SPHERE_SAMPLING or SLAB_SAMPLING, but "// &
     432            0 :                           "not both.")
     433              :          END IF
     434           16 :          ALLOCATE (rep_sys(nrep))
     435            8 :          DO i = 1, nrep
     436           52 :             ALLOCATE (rep_sys(i)%p_resp)
     437            4 :             NULLIFY (rep_sys(i)%p_resp%range_surf, rep_sys(i)%p_resp%atom_surf_list)
     438              :             CALL section_vals_val_get(slab_section, "RANGE", r_vals=rep_sys(i)%p_resp%range_surf, &
     439            4 :                                       i_rep_section=i)
     440              :             CALL section_vals_val_get(slab_section, "LENGTH", r_val=rep_sys(i)%p_resp%length, &
     441            4 :                                       i_rep_section=i)
     442              :             CALL section_vals_val_get(slab_section, "SURF_DIRECTION", &
     443            4 :                                       i_rep_section=i, i_val=rep_sys(i)%p_resp%my_fit)
     444           12 :             IF (ANY(rep_sys(i)%p_resp%range_surf < 0.0_dp)) THEN
     445            0 :                CPABORT("Numbers in RANGE in SLAB_SAMPLING cannot be negative.")
     446              :             END IF
     447            4 :             IF (rep_sys(i)%p_resp%length <= EPSILON(0.0_dp)) THEN
     448            0 :                CPABORT("Parameter LENGTH in SLAB_SAMPLING has to be larger than zero.")
     449              :             END IF
     450              :             !list of atoms specifying the surface
     451            8 :             CALL build_atom_list(slab_section, subsys, rep_sys(i)%p_resp%atom_surf_list, rep=i)
     452              :          END DO
     453              :       END IF
     454              : 
     455              :       ! get the parameters for the constraint and restraint sections
     456           14 :       CALL section_vals_get(cons_section, explicit=explicit)
     457           14 :       IF (explicit) THEN
     458            8 :          CALL section_vals_get(cons_section, n_repetition=resp_env%ncons_sec)
     459           22 :          DO i = 1, resp_env%ncons_sec
     460              :             CALL section_vals_val_get(cons_section, "EQUAL_CHARGES", &
     461           14 :                                       l_val=resp_env%equal_charges, explicit=explicit)
     462           14 :             IF (.NOT. explicit) CYCLE
     463            2 :             CALL build_atom_list(cons_section, subsys, atom_list_cons, i)
     464              :             !instead of using EQUAL_CHARGES the constraint sections could be repeated
     465            2 :             resp_env%ncons = resp_env%ncons + SIZE(atom_list_cons) - 2
     466           24 :             DEALLOCATE (atom_list_cons)
     467              :          END DO
     468              :       END IF
     469           14 :       CALL section_vals_get(rest_section, explicit=explicit)
     470           14 :       IF (explicit) THEN
     471            6 :          CALL section_vals_get(rest_section, n_repetition=resp_env%nrest_sec)
     472              :       END IF
     473           14 :       resp_env%ncons = resp_env%ncons + resp_env%ncons_sec
     474           14 :       resp_env%nres = resp_env%nres + resp_env%nrest_sec
     475              : 
     476           14 :       CALL timestop(handle)
     477              : 
     478           56 :    END SUBROUTINE init_resp
     479              : 
     480              : ! **************************************************************************************************
     481              : !> \brief getting the parameters for nonperiodic/non-surface systems
     482              : !> \param resp_env the resp environment
     483              : !> \param sphere_section input section setting parameters for sampling
     484              : !>        fitting in spheres around the atom
     485              : !> \param cell parameters related to the simulation cell
     486              : !> \param atomic_kind_set ...
     487              : ! **************************************************************************************************
     488           14 :    SUBROUTINE get_parameter_molecular_sys(resp_env, sphere_section, cell, &
     489              :                                           atomic_kind_set)
     490              : 
     491              :       TYPE(resp_type), POINTER                           :: resp_env
     492              :       TYPE(section_vals_type), POINTER                   :: sphere_section
     493              :       TYPE(cell_type), POINTER                           :: cell
     494              :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     495              : 
     496              :       CHARACTER(LEN=2)                                   :: symbol
     497              :       CHARACTER(LEN=default_string_length)               :: missing_rmax, missing_rmin
     498              :       CHARACTER(LEN=default_string_length), &
     499           14 :          DIMENSION(:), POINTER                           :: tmpstringlist
     500              :       INTEGER                                            :: ikind, j, kind_number, n_rmax_missing, &
     501              :                                                             n_rmin_missing, nkind, nrep_rmax, &
     502              :                                                             nrep_rmin, z
     503              :       LOGICAL                                            :: explicit, has_rmax, has_rmin
     504           14 :       LOGICAL, ALLOCATABLE, DIMENSION(:)                 :: rmax_is_set, rmin_is_set
     505              :       REAL(KIND=dp)                                      :: auto_rmax_scale, auto_rmin_scale, rmax, &
     506              :                                                             rmin
     507              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: hmat
     508              :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
     509              : 
     510           14 :       nrep_rmin = 0
     511           14 :       nrep_rmax = 0
     512           14 :       nkind = SIZE(atomic_kind_set)
     513              : 
     514           14 :       has_rmin = .FALSE.
     515           14 :       has_rmax = .FALSE.
     516              : 
     517           14 :       CALL section_vals_get(sphere_section, explicit=explicit)
     518           14 :       IF (explicit) THEN
     519           10 :          resp_env%molecular_sys = .TRUE.
     520              :          CALL section_vals_val_get(sphere_section, "AUTO_VDW_RADII_TABLE", &
     521           10 :                                    i_val=resp_env%auto_vdw_radii_table)
     522           10 :          CALL section_vals_val_get(sphere_section, "AUTO_RMIN_SCALE", r_val=auto_rmin_scale)
     523           10 :          CALL section_vals_val_get(sphere_section, "AUTO_RMAX_SCALE", r_val=auto_rmax_scale)
     524           10 :          CALL section_vals_val_get(sphere_section, "RMIN", explicit=has_rmin, r_val=rmin)
     525           10 :          CALL section_vals_val_get(sphere_section, "RMAX", explicit=has_rmax, r_val=rmax)
     526           10 :          CALL section_vals_val_get(sphere_section, "RMIN_KIND", n_rep_val=nrep_rmin)
     527           10 :          CALL section_vals_val_get(sphere_section, "RMAX_KIND", n_rep_val=nrep_rmax)
     528           30 :          ALLOCATE (resp_env%rmin_kind(nkind))
     529           20 :          ALLOCATE (resp_env%rmax_kind(nkind))
     530           38 :          resp_env%rmin_kind = 0.0_dp
     531           38 :          resp_env%rmax_kind = 0.0_dp
     532           30 :          ALLOCATE (rmin_is_set(nkind))
     533           20 :          ALLOCATE (rmax_is_set(nkind))
     534           10 :          rmin_is_set = .FALSE.
     535           10 :          rmax_is_set = .FALSE.
     536              :          ! define rmin_kind and rmax_kind to predefined vdW radii
     537           38 :          DO ikind = 1, nkind
     538           28 :             atomic_kind => atomic_kind_set(ikind)
     539              :             CALL get_atomic_kind(atomic_kind, &
     540              :                                  element_symbol=symbol, &
     541              :                                  kind_number=kind_number, &
     542           28 :                                  z=z)
     543           50 :             SELECT CASE (resp_env%auto_vdw_radii_table)
     544              :             CASE (use_cambridge_vdw_radii)
     545           22 :                CALL get_ptable_info(symbol, vdw_radius=resp_env%rmin_kind(kind_number))
     546           22 :                rmin_is_set(kind_number) = .TRUE.
     547              :             CASE (use_uff_vdw_radii)
     548            6 :                CALL cite_reference(Rappe1992)
     549              :                CALL get_uff_vdw_radius(z, radius=resp_env%rmin_kind(kind_number), &
     550            6 :                                        found=rmin_is_set(kind_number))
     551              :             CASE DEFAULT
     552            0 :                CALL get_ptable_info(symbol, vdw_radius=resp_env%rmin_kind(kind_number))
     553           28 :                rmin_is_set(kind_number) = .TRUE.
     554              :             END SELECT
     555           66 :             IF (rmin_is_set(kind_number)) THEN
     556              :                resp_env%rmin_kind(kind_number) = cp_unit_to_cp2k(resp_env%rmin_kind(kind_number), &
     557           28 :                                                                  "angstrom")
     558           28 :                resp_env%rmin_kind(kind_number) = resp_env%rmin_kind(kind_number)*auto_rmin_scale
     559              :                ! set RMAX_KIND accourding by scaling RMIN_KIND
     560              :                resp_env%rmax_kind(kind_number) = &
     561              :                   MAX(resp_env%rmin_kind(kind_number), &
     562           28 :                       resp_env%rmin_kind(kind_number)*auto_rmax_scale)
     563           28 :                rmax_is_set(kind_number) = .TRUE.
     564              :             END IF
     565              :          END DO
     566              :          ! if RMIN or RMAX are present, overwrite the rmin_kind(:) and
     567              :          ! rmax_kind(:) to those values
     568           10 :          IF (has_rmin) THEN
     569           24 :             resp_env%rmin_kind = rmin
     570           24 :             rmin_is_set = .TRUE.
     571              :          END IF
     572           10 :          IF (has_rmax) THEN
     573           24 :             resp_env%rmax_kind = rmax
     574           24 :             rmax_is_set = .TRUE.
     575              :          END IF
     576              :          ! if RMIN_KIND's or RMAX_KIND's are present, overwrite the
     577              :          ! rmin_kinds(:) or rmax_kind(:) to those values
     578           10 :          DO j = 1, nrep_rmin
     579              :             CALL section_vals_val_get(sphere_section, "RMIN_KIND", i_rep_val=j, &
     580            0 :                                       c_vals=tmpstringlist)
     581           10 :             DO ikind = 1, nkind
     582            0 :                atomic_kind => atomic_kind_set(ikind)
     583            0 :                CALL get_atomic_kind(atomic_kind, element_symbol=symbol, kind_number=kind_number)
     584            0 :                IF (TRIM(tmpstringlist(2)) == TRIM(symbol)) THEN
     585            0 :                   READ (tmpstringlist(1), *) resp_env%rmin_kind(kind_number)
     586              :                   resp_env%rmin_kind(kind_number) = &
     587              :                      cp_unit_to_cp2k(resp_env%rmin_kind(kind_number), &
     588            0 :                                      "angstrom")
     589            0 :                   rmin_is_set(kind_number) = .TRUE.
     590              :                END IF
     591              :             END DO
     592              :          END DO
     593           10 :          DO j = 1, nrep_rmax
     594              :             CALL section_vals_val_get(sphere_section, "RMAX_KIND", i_rep_val=j, &
     595            0 :                                       c_vals=tmpstringlist)
     596           10 :             DO ikind = 1, nkind
     597            0 :                atomic_kind => atomic_kind_set(ikind)
     598            0 :                CALL get_atomic_kind(atomic_kind, element_symbol=symbol, kind_number=kind_number)
     599            0 :                IF (TRIM(tmpstringlist(2)) == TRIM(symbol)) THEN
     600            0 :                   READ (tmpstringlist(1), *) resp_env%rmax_kind(kind_number)
     601              :                   resp_env%rmax_kind(kind_number) = cp_unit_to_cp2k(resp_env%rmax_kind(kind_number), &
     602            0 :                                                                     "angstrom")
     603            0 :                   rmax_is_set(kind_number) = .TRUE.
     604              :                END IF
     605              :             END DO
     606              :          END DO
     607              :          ! check if rmin and rmax are set for each kind
     608           10 :          n_rmin_missing = 0
     609           10 :          n_rmax_missing = 0
     610           10 :          missing_rmin = ""
     611           10 :          missing_rmax = ""
     612           38 :          DO ikind = 1, nkind
     613           28 :             atomic_kind => atomic_kind_set(ikind)
     614              :             CALL get_atomic_kind(atomic_kind, &
     615              :                                  element_symbol=symbol, &
     616           28 :                                  kind_number=kind_number)
     617           28 :             IF (.NOT. rmin_is_set(kind_number)) THEN
     618            0 :                n_rmin_missing = n_rmin_missing + 1
     619            0 :                missing_rmin = TRIM(missing_rmin)//" "//TRIM(symbol)//","
     620              :             END IF
     621           66 :             IF (.NOT. rmax_is_set(kind_number)) THEN
     622            0 :                n_rmax_missing = n_rmax_missing + 1
     623            0 :                missing_rmax = TRIM(missing_rmax)//" "//TRIM(symbol)//","
     624              :             END IF
     625              :          END DO
     626           10 :          IF (n_rmin_missing > 0) THEN
     627              :             CALL cp_warn(__LOCATION__, &
     628              :                          "RMIN for the following elements are missing: "// &
     629              :                          TRIM(missing_rmin)// &
     630              :                          " please set these values manually using "// &
     631            0 :                          "RMIN_KIND in SPHERE_SAMPLING section")
     632              :          END IF
     633           10 :          IF (n_rmax_missing > 0) THEN
     634              :             CALL cp_warn(__LOCATION__, &
     635              :                          "RMAX for the following elements are missing: "// &
     636              :                          TRIM(missing_rmax)// &
     637              :                          " please set these values manually using "// &
     638            0 :                          "RMAX_KIND in SPHERE_SAMPLING section")
     639              :          END IF
     640           10 :          IF (n_rmin_missing > 0 .OR. &
     641              :              n_rmax_missing > 0) THEN
     642            0 :             CPABORT("Insufficient data for RMIN or RMAX")
     643              :          END IF
     644              : 
     645           10 :          CALL get_cell(cell=cell, h=hmat)
     646           40 :          resp_env%box_hi = [hmat(1, 1), hmat(2, 2), hmat(3, 3)]
     647           40 :          resp_env%box_low = 0.0_dp
     648           10 :          CALL section_vals_val_get(sphere_section, "X_HI", explicit=explicit)
     649           10 :          IF (explicit) CALL section_vals_val_get(sphere_section, "X_HI", &
     650            0 :                                                  r_val=resp_env%box_hi(1))
     651           10 :          CALL section_vals_val_get(sphere_section, "X_LOW", explicit=explicit)
     652           10 :          IF (explicit) CALL section_vals_val_get(sphere_section, "X_LOW", &
     653            0 :                                                  r_val=resp_env%box_low(1))
     654           10 :          CALL section_vals_val_get(sphere_section, "Y_HI", explicit=explicit)
     655           10 :          IF (explicit) CALL section_vals_val_get(sphere_section, "Y_HI", &
     656            0 :                                                  r_val=resp_env%box_hi(2))
     657           10 :          CALL section_vals_val_get(sphere_section, "Y_LOW", explicit=explicit)
     658           10 :          IF (explicit) CALL section_vals_val_get(sphere_section, "Y_LOW", &
     659            0 :                                                  r_val=resp_env%box_low(2))
     660           10 :          CALL section_vals_val_get(sphere_section, "Z_HI", explicit=explicit)
     661           10 :          IF (explicit) CALL section_vals_val_get(sphere_section, "Z_HI", &
     662            0 :                                                  r_val=resp_env%box_hi(3))
     663           10 :          CALL section_vals_val_get(sphere_section, "Z_LOW", explicit=explicit)
     664           10 :          IF (explicit) CALL section_vals_val_get(sphere_section, "Z_LOW", &
     665            0 :                                                  r_val=resp_env%box_low(3))
     666              : 
     667           10 :          DEALLOCATE (rmin_is_set)
     668           80 :          DEALLOCATE (rmax_is_set)
     669              :       END IF
     670              : 
     671           14 :    END SUBROUTINE get_parameter_molecular_sys
     672              : 
     673              : ! **************************************************************************************************
     674              : !> \brief building atom lists for different sections of RESP
     675              : !> \param section input section
     676              : !> \param subsys ...
     677              : !> \param atom_list list of atoms for restraints, constraints and fit point
     678              : !>        sampling for slab-like systems
     679              : !> \param rep input section can be repeated, this param defines for which
     680              : !>        repetition of the input section the atom_list is built
     681              : ! **************************************************************************************************
     682           26 :    SUBROUTINE build_atom_list(section, subsys, atom_list, rep)
     683              : 
     684              :       TYPE(section_vals_type), POINTER                   :: section
     685              :       TYPE(qs_subsys_type), POINTER                      :: subsys
     686              :       INTEGER, DIMENSION(:), POINTER                     :: atom_list
     687              :       INTEGER, INTENT(IN), OPTIONAL                      :: rep
     688              : 
     689              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'build_atom_list'
     690              : 
     691              :       INTEGER                                            :: atom_a, atom_b, handle, i, irep, j, &
     692              :                                                             max_index, n_var, num_atom
     693           26 :       INTEGER, DIMENSION(:), POINTER                     :: indexes
     694              :       LOGICAL                                            :: index_in_range
     695              : 
     696           26 :       CALL timeset(routineN, handle)
     697              : 
     698           26 :       NULLIFY (indexes)
     699           26 :       irep = 1
     700           26 :       IF (PRESENT(rep)) irep = rep
     701              : 
     702              :       CALL section_vals_val_get(section, "ATOM_LIST", i_rep_section=irep, &
     703           26 :                                 n_rep_val=n_var)
     704           26 :       num_atom = 0
     705           52 :       DO i = 1, n_var
     706              :          CALL section_vals_val_get(section, "ATOM_LIST", i_rep_section=irep, &
     707           26 :                                    i_rep_val=i, i_vals=indexes)
     708           52 :          num_atom = num_atom + SIZE(indexes)
     709              :       END DO
     710           78 :       ALLOCATE (atom_list(num_atom))
     711          100 :       atom_list = 0
     712           26 :       num_atom = 1
     713           52 :       DO i = 1, n_var
     714              :          CALL section_vals_val_get(section, "ATOM_LIST", i_rep_section=irep, &
     715           26 :                                    i_rep_val=i, i_vals=indexes)
     716          200 :          atom_list(num_atom:num_atom + SIZE(indexes) - 1) = indexes(:)
     717           52 :          num_atom = num_atom + SIZE(indexes)
     718              :       END DO
     719              :       !check atom list
     720           26 :       num_atom = num_atom - 1
     721           26 :       CALL qs_subsys_get(subsys, nparticle=max_index)
     722           26 :       CPASSERT(SIZE(atom_list) /= 0)
     723              :       index_in_range = (MAXVAL(atom_list) <= max_index) &
     724          200 :                        .AND. (MINVAL(atom_list) > 0)
     725            0 :       CPASSERT(index_in_range)
     726          100 :       DO i = 1, num_atom
     727          236 :          DO j = i + 1, num_atom
     728          136 :             atom_a = atom_list(i)
     729          136 :             atom_b = atom_list(j)
     730          210 :             IF (atom_a == atom_b) THEN
     731            0 :                CPABORT("There are atoms doubled in atom list for RESP.")
     732              :             END IF
     733              :          END DO
     734              :       END DO
     735              : 
     736           26 :       CALL timestop(handle)
     737              : 
     738           78 :    END SUBROUTINE build_atom_list
     739              : 
     740              : ! **************************************************************************************************
     741              : !> \brief build matrix and vector for nonperiodic RESP fitting
     742              : !> \param qs_env the qs environment
     743              : !> \param resp_env the resp environment
     744              : !> \param atomic_kind_set ...
     745              : !> \param particles ...
     746              : !> \param cell parameters related to the simulation cell
     747              : !> \param matrix coefficient matrix of the linear system of equations
     748              : !> \param rhs vector of the linear system of equations
     749              : !> \param natom number of atoms
     750              : ! **************************************************************************************************
     751            4 :    SUBROUTINE calc_resp_matrix_nonper(qs_env, resp_env, atomic_kind_set, particles, &
     752              :                                       cell, matrix, rhs, natom)
     753              : 
     754              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     755              :       TYPE(resp_type), POINTER                           :: resp_env
     756              :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     757              :       TYPE(particle_list_type), POINTER                  :: particles
     758              :       TYPE(cell_type), POINTER                           :: cell
     759              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: matrix
     760              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: rhs
     761              :       INTEGER, INTENT(IN)                                :: natom
     762              : 
     763              :       CHARACTER(len=*), PARAMETER :: routineN = 'calc_resp_matrix_nonper'
     764              : 
     765              :       INTEGER                                            :: bo(2, 3), gbo(2, 3), handle, i, ikind, &
     766              :                                                             jx, jy, jz, k, kind_number, l, m, &
     767              :                                                             nkind, now, np(3), p
     768            4 :       LOGICAL, ALLOCATABLE, DIMENSION(:, :)              :: not_in_range
     769              :       REAL(KIND=dp)                                      :: delta, dh(3, 3), dvol, r(3), rmax, rmin, &
     770              :                                                             vec(3), vec_pbc(3), vj
     771            4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: dist
     772              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: hmat, hmat_inv
     773            4 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     774              :       TYPE(pw_r3d_rs_type), POINTER                      :: v_hartree_pw
     775              : 
     776            4 :       CALL timeset(routineN, handle)
     777              : 
     778            4 :       NULLIFY (particle_set, v_hartree_pw)
     779            4 :       delta = 1.0E-13_dp
     780              : 
     781            4 :       CALL get_cell(cell=cell, h=hmat, h_inv=hmat_inv)
     782              : 
     783            4 :       IF (.NOT. cell%orthorhombic) THEN
     784              :          CALL cp_abort(__LOCATION__, &
     785              :                        "Nonperiodic solution for RESP charges only"// &
     786            0 :                        " implemented for orthorhombic cells!")
     787              :       END IF
     788            4 :       IF (.NOT. resp_env%molecular_sys) THEN
     789              :          CALL cp_abort(__LOCATION__, &
     790              :                        "Nonperiodic solution for RESP charges (i.e. nonperiodic"// &
     791            0 :                        " Poisson solver) can only be used with section SPHERE_SAMPLING")
     792              :       END IF
     793            4 :       IF (resp_env%use_repeat_method) THEN
     794              :          CALL cp_abort(__LOCATION__, &
     795            0 :                        "REPEAT method only reasonable for periodic RESP fitting")
     796              :       END IF
     797            4 :       CALL get_qs_env(qs_env, particle_set=particle_set, v_hartree_rspace=v_hartree_pw)
     798              : 
     799           40 :       bo = v_hartree_pw%pw_grid%bounds_local
     800           40 :       gbo = v_hartree_pw%pw_grid%bounds
     801           16 :       np = v_hartree_pw%pw_grid%npts
     802           52 :       dh = v_hartree_pw%pw_grid%dh
     803            4 :       dvol = v_hartree_pw%pw_grid%dvol
     804            4 :       nkind = SIZE(atomic_kind_set)
     805              : 
     806           12 :       ALLOCATE (dist(natom))
     807           12 :       ALLOCATE (not_in_range(natom, 2))
     808              : 
     809              :       ! store fitting points to calculate the RMS and RRMS later
     810            4 :       IF (.NOT. ASSOCIATED(resp_env%fitpoints)) THEN
     811            4 :          now = 1000
     812            4 :          ALLOCATE (resp_env%fitpoints(3, now))
     813              :       ELSE
     814            0 :          now = SIZE(resp_env%fitpoints, 2)
     815              :       END IF
     816              : 
     817          184 :       DO jz = bo(1, 3), bo(2, 3)
     818         8284 :       DO jy = bo(1, 2), bo(2, 2)
     819       190530 :       DO jx = bo(1, 1), bo(2, 1)
     820       182250 :          IF (.NOT. (MODULO(jz, resp_env%stride(3)) == 0)) CYCLE
     821        60750 :          IF (.NOT. (MODULO(jy, resp_env%stride(2)) == 0)) CYCLE
     822        20250 :          IF (.NOT. (MODULO(jx, resp_env%stride(1)) == 0)) CYCLE
     823              :          !bounds bo reach from -np/2 to np/2. shift of np/2 so that r(1,1,1)=(0,0,0)
     824         6750 :          l = jx - gbo(1, 1)
     825         6750 :          k = jy - gbo(1, 2)
     826         6750 :          p = jz - gbo(1, 3)
     827         6750 :          r(3) = p*dh(3, 3) + k*dh(3, 2) + l*dh(3, 1)
     828         6750 :          r(2) = p*dh(2, 3) + k*dh(2, 2) + l*dh(2, 1)
     829         6750 :          r(1) = p*dh(1, 3) + k*dh(1, 2) + l*dh(1, 1)
     830         6750 :          IF (r(3) < resp_env%box_low(3) .OR. r(3) > resp_env%box_hi(3)) CYCLE
     831         6750 :          IF (r(2) < resp_env%box_low(2) .OR. r(2) > resp_env%box_hi(2)) CYCLE
     832         6750 :          IF (r(1) < resp_env%box_low(1) .OR. r(1) > resp_env%box_hi(1)) CYCLE
     833              :          ! compute distance from the grid point to all atoms
     834         6750 :          not_in_range = .FALSE.
     835        47250 :          DO i = 1, natom
     836       162000 :             vec = r - particles%els(i)%r
     837        40500 :             vec_pbc(1) = vec(1) - hmat(1, 1)*ANINT(hmat_inv(1, 1)*vec(1))
     838        40500 :             vec_pbc(2) = vec(2) - hmat(2, 2)*ANINT(hmat_inv(2, 2)*vec(2))
     839        40500 :             vec_pbc(3) = vec(3) - hmat(3, 3)*ANINT(hmat_inv(3, 3)*vec(3))
     840       162000 :             dist(i) = SQRT(SUM(vec_pbc**2))
     841              :             CALL get_atomic_kind(atomic_kind=particle_set(i)%atomic_kind, &
     842        40500 :                                  kind_number=kind_number)
     843       101250 :             DO ikind = 1, nkind
     844       101250 :                IF (ikind == kind_number) THEN
     845        40500 :                   rmin = resp_env%rmin_kind(ikind)
     846        40500 :                   rmax = resp_env%rmax_kind(ikind)
     847        40500 :                   EXIT
     848              :                END IF
     849              :             END DO
     850        40500 :             IF (dist(i) < rmin + delta) not_in_range(i, 1) = .TRUE.
     851        87750 :             IF (dist(i) > rmax - delta) not_in_range(i, 2) = .TRUE.
     852              :          END DO
     853              :          ! check if the point is sufficiently close and  far. if OK, we can use
     854              :          ! the point for fitting, add/subtract 1.0E-13 to get rid of rounding errors when shifting atoms
     855        85830 :          IF (ANY(not_in_range(:, 1)) .OR. ALL(not_in_range(:, 2))) CYCLE
     856           72 :          resp_env%npoints_proc = resp_env%npoints_proc + 1
     857           72 :          IF (resp_env%npoints_proc > now) THEN
     858            0 :             now = 2*now
     859            0 :             CALL reallocate(resp_env%fitpoints, 1, 3, 1, now)
     860              :          END IF
     861           72 :          resp_env%fitpoints(1, resp_env%npoints_proc) = jx
     862           72 :          resp_env%fitpoints(2, resp_env%npoints_proc) = jy
     863           72 :          resp_env%fitpoints(3, resp_env%npoints_proc) = jz
     864              :          ! correct for the fact that v_hartree is scaled by dvol, and has the opposite sign
     865           72 :          IF (qs_env%qmmm) THEN
     866              :             ! If it's a QM/MM run let's remove the contribution of the MM potential out of the Hartree pot
     867            0 :             vj = -v_hartree_pw%array(jx, jy, jz)/dvol + qs_env%ks_qmmm_env%v_qmmm_rspace%array(jx, jy, jz)
     868              :          ELSE
     869           72 :             vj = -v_hartree_pw%array(jx, jy, jz)/dvol
     870              :          END IF
     871          504 :          dist(:) = 1.0_dp/dist(:)
     872              : 
     873         8604 :          DO i = 1, natom
     874         3024 :             DO m = 1, natom
     875         3024 :                matrix(m, i) = matrix(m, i) + 2.0_dp*dist(i)*dist(m)
     876              :             END DO
     877       182682 :             rhs(i) = rhs(i) + 2.0_dp*vj*dist(i)
     878              :          END DO
     879              :       END DO
     880              :       END DO
     881              :       END DO
     882              : 
     883            4 :       resp_env%npoints = resp_env%npoints_proc
     884            4 :       CALL v_hartree_pw%pw_grid%para%group%sum(resp_env%npoints)
     885          724 :       CALL v_hartree_pw%pw_grid%para%group%sum(matrix)
     886           76 :       CALL v_hartree_pw%pw_grid%para%group%sum(rhs)
     887              :       !weighted sum
     888          364 :       matrix = matrix/resp_env%npoints
     889           40 :       rhs = rhs/resp_env%npoints
     890              : 
     891            4 :       DEALLOCATE (dist)
     892            4 :       DEALLOCATE (not_in_range)
     893              : 
     894            4 :       CALL timestop(handle)
     895              : 
     896            4 :    END SUBROUTINE calc_resp_matrix_nonper
     897              : 
     898              : ! **************************************************************************************************
     899              : !> \brief build matrix and vector for periodic RESP fitting
     900              : !> \param qs_env the qs environment
     901              : !> \param resp_env the resp environment
     902              : !> \param rep_sys structure for repeating input sections defining fit points
     903              : !> \param particles ...
     904              : !> \param cell parameters related to the simulation cell
     905              : !> \param natom number of atoms
     906              : ! **************************************************************************************************
     907           10 :    SUBROUTINE calc_resp_matrix_periodic(qs_env, resp_env, rep_sys, particles, cell, &
     908              :                                         natom)
     909              : 
     910              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     911              :       TYPE(resp_type), POINTER                           :: resp_env
     912              :       TYPE(resp_p_type), DIMENSION(:), POINTER           :: rep_sys
     913              :       TYPE(particle_list_type), POINTER                  :: particles
     914              :       TYPE(cell_type), POINTER                           :: cell
     915              :       INTEGER, INTENT(IN)                                :: natom
     916              : 
     917              :       CHARACTER(len=*), PARAMETER :: routineN = 'calc_resp_matrix_periodic'
     918              : 
     919              :       INTEGER                                            :: handle, i, ip, j, jx, jy, jz
     920              :       INTEGER, DIMENSION(3)                              :: periodic
     921              :       REAL(KIND=dp)                                      :: normalize_factor
     922           10 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: vpot
     923              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     924              :       TYPE(pw_c1d_gs_type)                               :: rho_ga, va_gspace
     925              :       TYPE(pw_env_type), POINTER                         :: pw_env
     926              :       TYPE(pw_poisson_type), POINTER                     :: poisson_env
     927              :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
     928              :       TYPE(pw_r3d_rs_type)                               :: va_rspace
     929              : 
     930           10 :       CALL timeset(routineN, handle)
     931              : 
     932           10 :       NULLIFY (pw_env, para_env, auxbas_pw_pool, poisson_env)
     933              : 
     934           10 :       CALL get_cell(cell=cell, periodic=periodic)
     935              : 
     936           40 :       IF (.NOT. ALL(periodic /= 0)) THEN
     937              :          CALL cp_abort(__LOCATION__, &
     938              :                        "Periodic solution for RESP (with periodic Poisson solver)"// &
     939            0 :                        " can only be obtained with a cell that has XYZ periodicity")
     940              :       END IF
     941              : 
     942           10 :       CALL get_qs_env(qs_env, pw_env=pw_env, para_env=para_env)
     943              : 
     944              :       CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool, &
     945           10 :                       poisson_env=poisson_env)
     946           10 :       CALL auxbas_pw_pool%create_pw(rho_ga)
     947           10 :       CALL auxbas_pw_pool%create_pw(va_gspace)
     948           10 :       CALL auxbas_pw_pool%create_pw(va_rspace)
     949              : 
     950              :       !get fitting points and store them in resp_env%fitpoints
     951              :       CALL get_fitting_points(qs_env, resp_env, rep_sys, particles=particles, &
     952           10 :                               cell=cell)
     953           40 :       ALLOCATE (vpot(resp_env%npoints_proc, natom))
     954           10 :       normalize_factor = SQRT((resp_env%eta/pi)**3)
     955              : 
     956           76 :       DO i = 1, natom
     957              :          !collocate gaussian for each atom
     958           66 :          CALL pw_zero(rho_ga)
     959           66 :          CALL calculate_rho_resp_single(rho_ga, qs_env, resp_env%eta, i)
     960              :          !calculate potential va and store the part needed for fitting in vpot
     961           66 :          CALL pw_zero(va_gspace)
     962           66 :          CALL pw_poisson_solve(poisson_env, rho_ga, vhartree=va_gspace)
     963           66 :          CALL pw_zero(va_rspace)
     964           66 :          CALL pw_transfer(va_gspace, va_rspace)
     965           66 :          CALL pw_scale(va_rspace, normalize_factor)
     966        10659 :          DO ip = 1, resp_env%npoints_proc
     967        10583 :             jx = resp_env%fitpoints(1, ip)
     968        10583 :             jy = resp_env%fitpoints(2, ip)
     969        10583 :             jz = resp_env%fitpoints(3, ip)
     970        10649 :             vpot(ip, i) = va_rspace%array(jx, jy, jz)
     971              :          END DO
     972              :       END DO
     973              : 
     974           10 :       CALL va_gspace%release()
     975           10 :       CALL va_rspace%release()
     976           10 :       CALL rho_ga%release()
     977              : 
     978           76 :       DO i = 1, natom
     979          516 :          DO j = 1, natom
     980              :             ! calculate matrix
     981        55897 :             resp_env%matrix(i, j) = resp_env%matrix(i, j) + 2.0_dp*SUM(vpot(:, i)*vpot(:, j))
     982              :          END DO
     983              :          ! calculate vector resp_env%rhs
     984           76 :          CALL calculate_rhs(qs_env, resp_env, resp_env%rhs(i), vpot(:, i))
     985              :       END DO
     986              : 
     987         1778 :       CALL para_env%sum(resp_env%matrix)
     988          186 :       CALL para_env%sum(resp_env%rhs)
     989              :       !weighted sum
     990          894 :       resp_env%matrix = resp_env%matrix/resp_env%npoints
     991           98 :       resp_env%rhs = resp_env%rhs/resp_env%npoints
     992              : 
     993              :       ! REPEAT stuff
     994           10 :       IF (resp_env%use_repeat_method) THEN
     995              :          ! sum over selected points of single Gaussian potential vpot
     996           32 :          DO i = 1, natom
     997           32 :             resp_env%sum_vpot(i) = 2.0_dp*accurate_sum(vpot(:, i))/resp_env%npoints
     998              :          END DO
     999           60 :          CALL para_env%sum(resp_env%sum_vpot)
    1000            4 :          CALL para_env%sum(resp_env%sum_vhartree)
    1001            4 :          resp_env%sum_vhartree = 2.0_dp*resp_env%sum_vhartree/resp_env%npoints
    1002              :       END IF
    1003              : 
    1004           10 :       DEALLOCATE (vpot)
    1005           10 :       CALL timestop(handle)
    1006              : 
    1007           10 :    END SUBROUTINE calc_resp_matrix_periodic
    1008              : 
    1009              : ! **************************************************************************************************
    1010              : !> \brief get RESP fitting points for the periodic fitting
    1011              : !> \param qs_env the qs environment
    1012              : !> \param resp_env the resp environment
    1013              : !> \param rep_sys structure for repeating input sections defining fit points
    1014              : !> \param particles ...
    1015              : !> \param cell parameters related to the simulation cell
    1016              : ! **************************************************************************************************
    1017           10 :    SUBROUTINE get_fitting_points(qs_env, resp_env, rep_sys, particles, cell)
    1018              : 
    1019              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1020              :       TYPE(resp_type), POINTER                           :: resp_env
    1021              :       TYPE(resp_p_type), DIMENSION(:), POINTER           :: rep_sys
    1022              :       TYPE(particle_list_type), POINTER                  :: particles
    1023              :       TYPE(cell_type), POINTER                           :: cell
    1024              : 
    1025              :       CHARACTER(len=*), PARAMETER :: routineN = 'get_fitting_points'
    1026              : 
    1027              :       INTEGER                                            :: bo(2, 3), gbo(2, 3), handle, i, iatom, &
    1028              :                                                             ikind, in_x, in_y, in_z, jx, jy, jz, &
    1029              :                                                             k, kind_number, l, m, natom, nkind, &
    1030              :                                                             now, p
    1031           10 :       LOGICAL, ALLOCATABLE, DIMENSION(:, :)              :: not_in_range
    1032              :       REAL(KIND=dp)                                      :: delta, dh(3, 3), r(3), rmax, rmin, &
    1033              :                                                             vec_pbc(3)
    1034           10 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: dist
    1035           10 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    1036              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1037           10 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1038              :       TYPE(pw_r3d_rs_type), POINTER                      :: v_hartree_pw
    1039              : 
    1040           10 :       CALL timeset(routineN, handle)
    1041              : 
    1042           10 :       NULLIFY (atomic_kind_set, v_hartree_pw, para_env, particle_set)
    1043           10 :       delta = 1.0E-13_dp
    1044              : 
    1045              :       CALL get_qs_env(qs_env, &
    1046              :                       particle_set=particle_set, &
    1047              :                       atomic_kind_set=atomic_kind_set, &
    1048              :                       para_env=para_env, &
    1049           10 :                       v_hartree_rspace=v_hartree_pw)
    1050              : 
    1051          100 :       bo = v_hartree_pw%pw_grid%bounds_local
    1052          100 :       gbo = v_hartree_pw%pw_grid%bounds
    1053          130 :       dh = v_hartree_pw%pw_grid%dh
    1054           10 :       natom = SIZE(particles%els)
    1055           10 :       nkind = SIZE(atomic_kind_set)
    1056              : 
    1057           10 :       IF (.NOT. ASSOCIATED(resp_env%fitpoints)) THEN
    1058           10 :          now = 1000
    1059           10 :          ALLOCATE (resp_env%fitpoints(3, now))
    1060              :       ELSE
    1061            0 :          now = SIZE(resp_env%fitpoints, 2)
    1062              :       END IF
    1063              : 
    1064           30 :       ALLOCATE (dist(natom))
    1065           30 :       ALLOCATE (not_in_range(natom, 2))
    1066              : 
    1067              :       !every proc gets another bo, grid is distributed
    1068          350 :       DO jz = bo(1, 3), bo(2, 3)
    1069          340 :          IF (.NOT. (MODULO(jz, resp_env%stride(3)) == 0)) CYCLE
    1070         4338 :          DO jy = bo(1, 2), bo(2, 2)
    1071         4204 :             IF (.NOT. (MODULO(jy, resp_env%stride(2)) == 0)) CYCLE
    1072        31554 :             DO jx = bo(1, 1), bo(2, 1)
    1073        29642 :                IF (.NOT. (MODULO(jx, resp_env%stride(1)) == 0)) CYCLE
    1074              :                !bounds gbo reach from -np/2 to np/2. shift of np/2 so that r(1,1,1)=(0,0,0)
    1075        11246 :                l = jx - gbo(1, 1)
    1076        11246 :                k = jy - gbo(1, 2)
    1077        11246 :                p = jz - gbo(1, 3)
    1078        11246 :                r(3) = p*dh(3, 3) + k*dh(3, 2) + l*dh(3, 1)
    1079        11246 :                r(2) = p*dh(2, 3) + k*dh(2, 2) + l*dh(2, 1)
    1080        11246 :                r(1) = p*dh(1, 3) + k*dh(1, 2) + l*dh(1, 1)
    1081        11246 :                IF (resp_env%molecular_sys) THEN
    1082        10846 :                   not_in_range = .FALSE.
    1083        71826 :                   DO m = 1, natom
    1084        60980 :                      vec_pbc = pbc(r, particles%els(m)%r, cell)
    1085       243920 :                      dist(m) = SQRT(SUM(vec_pbc**2))
    1086              :                      CALL get_atomic_kind(atomic_kind=particle_set(m)%atomic_kind, &
    1087        60980 :                                           kind_number=kind_number)
    1088       138114 :                      DO ikind = 1, nkind
    1089       138114 :                         IF (ikind == kind_number) THEN
    1090        60980 :                            rmin = resp_env%rmin_kind(ikind)
    1091        60980 :                            rmax = resp_env%rmax_kind(ikind)
    1092        60980 :                            EXIT
    1093              :                         END IF
    1094              :                      END DO
    1095        60980 :                      IF (dist(m) < rmin + delta) not_in_range(m, 1) = .TRUE.
    1096       132806 :                      IF (dist(m) > rmax - delta) not_in_range(m, 2) = .TRUE.
    1097              :                   END DO
    1098       121136 :                   IF (ANY(not_in_range(:, 1)) .OR. ALL(not_in_range(:, 2))) CYCLE
    1099              :                ELSE
    1100          752 :                   DO i = 1, SIZE(rep_sys)
    1101         3348 :                      DO m = 1, SIZE(rep_sys(i)%p_resp%atom_surf_list)
    1102         2996 :                         in_z = 0
    1103         2996 :                         in_y = 0
    1104         2996 :                         in_x = 0
    1105         2996 :                         iatom = rep_sys(i)%p_resp%atom_surf_list(m)
    1106         5992 :                         SELECT CASE (rep_sys(i)%p_resp%my_fit)
    1107              :                         CASE (do_resp_x_dir, do_resp_y_dir, do_resp_z_dir)
    1108         2996 :                            vec_pbc = pbc(particles%els(iatom)%r, r, cell)
    1109              :                         CASE (do_resp_minus_x_dir, do_resp_minus_y_dir, do_resp_minus_z_dir)
    1110         2996 :                            vec_pbc = pbc(r, particles%els(iatom)%r, cell)
    1111              :                         END SELECT
    1112         2996 :                         SELECT CASE (rep_sys(i)%p_resp%my_fit)
    1113              :                            !subtract delta=1.0E-13 to get rid of rounding errors when shifting atoms
    1114              :                         CASE (do_resp_x_dir, do_resp_minus_x_dir)
    1115            0 :                            IF (ABS(vec_pbc(3)) < rep_sys(i)%p_resp%length - delta) in_z = 1
    1116            0 :                            IF (ABS(vec_pbc(2)) < rep_sys(i)%p_resp%length - delta) in_y = 1
    1117            0 :                            IF (vec_pbc(1) > rep_sys(i)%p_resp%range_surf(1) + delta .AND. &
    1118            0 :                                vec_pbc(1) < rep_sys(i)%p_resp%range_surf(2) - delta) in_x = 1
    1119              :                         CASE (do_resp_y_dir, do_resp_minus_y_dir)
    1120            0 :                            IF (ABS(vec_pbc(3)) < rep_sys(i)%p_resp%length - delta) in_z = 1
    1121            0 :                            IF (vec_pbc(2) > rep_sys(i)%p_resp%range_surf(1) + delta .AND. &
    1122            0 :                                vec_pbc(2) < rep_sys(i)%p_resp%range_surf(2) - delta) in_y = 1
    1123            0 :                            IF (ABS(vec_pbc(1)) < rep_sys(i)%p_resp%length - delta) in_x = 1
    1124              :                         CASE (do_resp_z_dir, do_resp_minus_z_dir)
    1125         2996 :                            IF (vec_pbc(3) > rep_sys(i)%p_resp%range_surf(1) + delta .AND. &
    1126          196 :                                vec_pbc(3) < rep_sys(i)%p_resp%range_surf(2) - delta) in_z = 1
    1127         2996 :                            IF (ABS(vec_pbc(2)) < rep_sys(i)%p_resp%length - delta) in_y = 1
    1128         5992 :                            IF (ABS(vec_pbc(1)) < rep_sys(i)%p_resp%length - delta) in_x = 1
    1129              :                         END SELECT
    1130         3348 :                         IF (in_z*in_y*in_x == 1) EXIT
    1131              :                      END DO
    1132          752 :                      IF (in_z*in_y*in_x == 1) EXIT
    1133              :                   END DO
    1134          400 :                   IF (in_z*in_y*in_x == 0) CYCLE
    1135              :                END IF
    1136         2044 :                resp_env%npoints_proc = resp_env%npoints_proc + 1
    1137         2044 :                IF (resp_env%npoints_proc > now) THEN
    1138            1 :                   now = 2*now
    1139            1 :                   CALL reallocate(resp_env%fitpoints, 1, 3, 1, now)
    1140              :                END IF
    1141         2044 :                resp_env%fitpoints(1, resp_env%npoints_proc) = jx
    1142         2044 :                resp_env%fitpoints(2, resp_env%npoints_proc) = jy
    1143        33846 :                resp_env%fitpoints(3, resp_env%npoints_proc) = jz
    1144              :             END DO
    1145              :          END DO
    1146              :       END DO
    1147              : 
    1148           10 :       resp_env%npoints = resp_env%npoints_proc
    1149           10 :       CALL para_env%sum(resp_env%npoints)
    1150              : 
    1151           10 :       DEALLOCATE (dist)
    1152           10 :       DEALLOCATE (not_in_range)
    1153              : 
    1154           10 :       CALL timestop(handle)
    1155              : 
    1156           10 :    END SUBROUTINE get_fitting_points
    1157              : 
    1158              : ! **************************************************************************************************
    1159              : !> \brief calculate vector rhs
    1160              : !> \param qs_env the qs environment
    1161              : !> \param resp_env the resp environment
    1162              : !> \param rhs vector
    1163              : !> \param vpot single gaussian potential
    1164              : ! **************************************************************************************************
    1165           66 :    SUBROUTINE calculate_rhs(qs_env, resp_env, rhs, vpot)
    1166              : 
    1167              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1168              :       TYPE(resp_type), POINTER                           :: resp_env
    1169              :       REAL(KIND=dp), INTENT(INOUT)                       :: rhs
    1170              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: vpot
    1171              : 
    1172              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'calculate_rhs'
    1173              : 
    1174              :       INTEGER                                            :: handle, ip, jx, jy, jz
    1175              :       REAL(KIND=dp)                                      :: dvol
    1176           66 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: vhartree
    1177              :       TYPE(pw_r3d_rs_type), POINTER                      :: v_hartree_pw
    1178              : 
    1179           66 :       CALL timeset(routineN, handle)
    1180              : 
    1181           66 :       NULLIFY (v_hartree_pw)
    1182           66 :       CALL get_qs_env(qs_env, v_hartree_rspace=v_hartree_pw)
    1183           66 :       dvol = v_hartree_pw%pw_grid%dvol
    1184          198 :       ALLOCATE (vhartree(resp_env%npoints_proc))
    1185           66 :       vhartree = 0.0_dp
    1186              : 
    1187              :       !multiply v_hartree and va_rspace and calculate the vector rhs
    1188              :       !taking into account that v_hartree has opposite site; remove v_qmmm
    1189        10649 :       DO ip = 1, resp_env%npoints_proc
    1190        10583 :          jx = resp_env%fitpoints(1, ip)
    1191        10583 :          jy = resp_env%fitpoints(2, ip)
    1192        10583 :          jz = resp_env%fitpoints(3, ip)
    1193        10583 :          vhartree(ip) = -v_hartree_pw%array(jx, jy, jz)/dvol
    1194        10583 :          IF (qs_env%qmmm) THEN
    1195              :             !taking into account that v_qmmm has also opposite sign
    1196            0 :             vhartree(ip) = vhartree(ip) + qs_env%ks_qmmm_env%v_qmmm_rspace%array(jx, jy, jz)
    1197              :          END IF
    1198        10649 :          rhs = rhs + 2.0_dp*vhartree(ip)*vpot(ip)
    1199              :       END DO
    1200              : 
    1201           66 :       IF (resp_env%use_repeat_method) THEN
    1202           28 :          resp_env%sum_vhartree = accurate_sum(vhartree)
    1203              :       END IF
    1204              : 
    1205           66 :       DEALLOCATE (vhartree)
    1206              : 
    1207           66 :       CALL timestop(handle)
    1208              : 
    1209          132 :    END SUBROUTINE calculate_rhs
    1210              : 
    1211              : ! **************************************************************************************************
    1212              : !> \brief print the atom coordinates and the coordinates of the fitting points
    1213              : !>        to an xyz file
    1214              : !> \param qs_env the qs environment
    1215              : !> \param resp_env the resp environment
    1216              : ! **************************************************************************************************
    1217           28 :    SUBROUTINE print_fitting_points(qs_env, resp_env)
    1218              : 
    1219              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1220              :       TYPE(resp_type), POINTER                           :: resp_env
    1221              : 
    1222              :       CHARACTER(len=*), PARAMETER :: routineN = 'print_fitting_points'
    1223              : 
    1224              :       CHARACTER(LEN=2)                                   :: element_symbol
    1225              :       CHARACTER(LEN=default_path_length)                 :: filename
    1226              :       INTEGER                                            :: gbo(2, 3), handle, i, iatom, ip, jx, jy, &
    1227              :                                                             jz, k, l, my_pos, nobjects, &
    1228              :                                                             output_unit, p
    1229           14 :       INTEGER, DIMENSION(:), POINTER                     :: tmp_npoints, tmp_size
    1230           14 :       INTEGER, DIMENSION(:, :), POINTER                  :: tmp_points
    1231              :       REAL(KIND=dp)                                      :: conv, dh(3, 3), r(3)
    1232              :       TYPE(cp_logger_type), POINTER                      :: logger
    1233              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1234           98 :       TYPE(mp_request_type), DIMENSION(6)                :: req
    1235           14 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1236              :       TYPE(pw_r3d_rs_type), POINTER                      :: v_hartree_pw
    1237              :       TYPE(section_vals_type), POINTER                   :: input, print_key, resp_section
    1238              : 
    1239           14 :       CALL timeset(routineN, handle)
    1240              : 
    1241           14 :       NULLIFY (para_env, input, logger, resp_section, print_key, particle_set, tmp_size, &
    1242           14 :                tmp_points, tmp_npoints, v_hartree_pw)
    1243              : 
    1244              :       CALL get_qs_env(qs_env, input=input, para_env=para_env, &
    1245           14 :                       particle_set=particle_set, v_hartree_rspace=v_hartree_pw)
    1246           14 :       conv = cp_unit_from_cp2k(1.0_dp, "angstrom")
    1247          140 :       gbo = v_hartree_pw%pw_grid%bounds
    1248          182 :       dh = v_hartree_pw%pw_grid%dh
    1249           14 :       nobjects = SIZE(particle_set) + resp_env%npoints
    1250              : 
    1251           14 :       resp_section => section_vals_get_subs_vals(input, "PROPERTIES%RESP")
    1252           14 :       print_key => section_vals_get_subs_vals(resp_section, "PRINT%COORD_FIT_POINTS")
    1253           14 :       logger => cp_get_default_logger()
    1254              :       output_unit = cp_print_key_unit_nr(logger, resp_section, &
    1255              :                                          "PRINT%COORD_FIT_POINTS", &
    1256              :                                          extension=".xyz", &
    1257              :                                          file_status="REPLACE", &
    1258              :                                          file_action="WRITE", &
    1259           14 :                                          file_form="FORMATTED")
    1260              : 
    1261           14 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, &
    1262              :                                            resp_section, "PRINT%COORD_FIT_POINTS"), &
    1263              :                 cp_p_file)) THEN
    1264            2 :          IF (output_unit > 0) THEN
    1265              :             filename = cp_print_key_generate_filename(logger, &
    1266              :                                                       print_key, extension=".xyz", &
    1267            1 :                                                       my_local=.FALSE.)
    1268            1 :             WRITE (unit=output_unit, FMT="(I12,/)") nobjects
    1269            7 :             DO iatom = 1, SIZE(particle_set)
    1270              :                CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
    1271            6 :                                     element_symbol=element_symbol)
    1272            6 :                WRITE (UNIT=output_unit, FMT="(A,1X,3F10.5)") element_symbol, &
    1273           31 :                   particle_set(iatom)%r(1:3)*conv
    1274              :             END DO
    1275              :             !printing points of proc which is doing the output (should be proc 0)
    1276          101 :             DO ip = 1, resp_env%npoints_proc
    1277          100 :                jx = resp_env%fitpoints(1, ip)
    1278          100 :                jy = resp_env%fitpoints(2, ip)
    1279          100 :                jz = resp_env%fitpoints(3, ip)
    1280          100 :                l = jx - gbo(1, 1)
    1281          100 :                k = jy - gbo(1, 2)
    1282          100 :                p = jz - gbo(1, 3)
    1283          100 :                r(3) = p*dh(3, 3) + k*dh(3, 2) + l*dh(3, 1)
    1284          100 :                r(2) = p*dh(2, 3) + k*dh(2, 2) + l*dh(2, 1)
    1285          100 :                r(1) = p*dh(1, 3) + k*dh(1, 2) + l*dh(1, 1)
    1286          400 :                r(:) = r(:)*conv
    1287          101 :                WRITE (UNIT=output_unit, FMT="(A,2X,3F10.5)") "X", r(1), r(2), r(3)
    1288              :             END DO
    1289              :          END IF
    1290              : 
    1291            2 :          ALLOCATE (tmp_size(1))
    1292            2 :          ALLOCATE (tmp_npoints(1))
    1293              : 
    1294              :          !sending data of all other procs to proc which makes the output (proc 0)
    1295            2 :          IF (output_unit > 0) THEN
    1296            1 :             my_pos = para_env%mepos
    1297            3 :             DO i = 1, para_env%num_pe
    1298            2 :                IF (my_pos == i - 1) CYCLE
    1299              :                CALL para_env%irecv(msgout=tmp_size, source=i - 1, &
    1300            1 :                                    request=req(1))
    1301            1 :                CALL req(1)%wait()
    1302            3 :                ALLOCATE (tmp_points(3, tmp_size(1)))
    1303              :                CALL para_env%irecv(msgout=tmp_points, source=i - 1, &
    1304            1 :                                    request=req(3))
    1305            1 :                CALL req(3)%wait()
    1306              :                CALL para_env%irecv(msgout=tmp_npoints, source=i - 1, &
    1307            1 :                                    request=req(5))
    1308            1 :                CALL req(5)%wait()
    1309           84 :                DO ip = 1, tmp_npoints(1)
    1310           83 :                   jx = tmp_points(1, ip)
    1311           83 :                   jy = tmp_points(2, ip)
    1312           83 :                   jz = tmp_points(3, ip)
    1313           83 :                   l = jx - gbo(1, 1)
    1314           83 :                   k = jy - gbo(1, 2)
    1315           83 :                   p = jz - gbo(1, 3)
    1316           83 :                   r(3) = p*dh(3, 3) + k*dh(3, 2) + l*dh(3, 1)
    1317           83 :                   r(2) = p*dh(2, 3) + k*dh(2, 2) + l*dh(2, 1)
    1318           83 :                   r(1) = p*dh(1, 3) + k*dh(1, 2) + l*dh(1, 1)
    1319          332 :                   r(:) = r(:)*conv
    1320           84 :                   WRITE (UNIT=output_unit, FMT="(A,2X,3F10.5)") "X", r(1), r(2), r(3)
    1321              :                END DO
    1322            3 :                DEALLOCATE (tmp_points)
    1323              :             END DO
    1324              :          ELSE
    1325            1 :             tmp_size(1) = SIZE(resp_env%fitpoints, 2)
    1326              :             !para_env%source should be 0
    1327              :             CALL para_env%isend(msgin=tmp_size, dest=para_env%source, &
    1328            1 :                                 request=req(2))
    1329            1 :             CALL req(2)%wait()
    1330              :             CALL para_env%isend(msgin=resp_env%fitpoints, dest=para_env%source, &
    1331            1 :                                 request=req(4))
    1332            1 :             CALL req(4)%wait()
    1333            1 :             tmp_npoints(1) = resp_env%npoints_proc
    1334              :             CALL para_env%isend(msgin=tmp_npoints, dest=para_env%source, &
    1335            1 :                                 request=req(6))
    1336            1 :             CALL req(6)%wait()
    1337              :          END IF
    1338              : 
    1339            2 :          DEALLOCATE (tmp_size)
    1340            2 :          DEALLOCATE (tmp_npoints)
    1341              :       END IF
    1342              : 
    1343              :       CALL cp_print_key_finished_output(output_unit, logger, resp_section, &
    1344           14 :                                         "PRINT%COORD_FIT_POINTS")
    1345              : 
    1346           14 :       CALL timestop(handle)
    1347              : 
    1348           14 :    END SUBROUTINE print_fitting_points
    1349              : 
    1350              : ! **************************************************************************************************
    1351              : !> \brief add restraints and constraints
    1352              : !> \param qs_env the qs environment
    1353              : !> \param resp_env the resp environment
    1354              : !> \param rest_section input section for restraints
    1355              : !> \param subsys ...
    1356              : !> \param natom number of atoms
    1357              : !> \param cons_section input section for constraints
    1358              : !> \param particle_set ...
    1359              : ! **************************************************************************************************
    1360           14 :    SUBROUTINE add_restraints_and_constraints(qs_env, resp_env, rest_section, &
    1361              :                                              subsys, natom, cons_section, particle_set)
    1362              : 
    1363              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1364              :       TYPE(resp_type), POINTER                           :: resp_env
    1365              :       TYPE(section_vals_type), POINTER                   :: rest_section
    1366              :       TYPE(qs_subsys_type), POINTER                      :: subsys
    1367              :       INTEGER, INTENT(IN)                                :: natom
    1368              :       TYPE(section_vals_type), POINTER                   :: cons_section
    1369              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1370              : 
    1371              :       CHARACTER(len=*), PARAMETER :: routineN = 'add_restraints_and_constraints'
    1372              : 
    1373              :       INTEGER                                            :: handle, i, k, m, ncons_v, z
    1374           14 :       INTEGER, DIMENSION(:), POINTER                     :: atom_list_cons, atom_list_res
    1375              :       LOGICAL                                            :: explicit_coeff
    1376              :       REAL(KIND=dp)                                      :: my_atom_coef(2), strength, TARGET
    1377           14 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: atom_coef
    1378              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1379              : 
    1380           14 :       CALL timeset(routineN, handle)
    1381              : 
    1382           14 :       NULLIFY (atom_coef, atom_list_res, atom_list_cons, dft_control)
    1383              : 
    1384           14 :       CALL get_qs_env(qs_env, dft_control=dft_control)
    1385              : 
    1386              :       !*** add the restraints
    1387           20 :       DO i = 1, resp_env%nrest_sec
    1388            6 :          CALL section_vals_val_get(rest_section, "TARGET", i_rep_section=i, r_val=TARGET)
    1389            6 :          CALL section_vals_val_get(rest_section, "STRENGTH", i_rep_section=i, r_val=strength)
    1390            6 :          CALL build_atom_list(rest_section, subsys, atom_list_res, i)
    1391            6 :          CALL section_vals_val_get(rest_section, "ATOM_COEF", i_rep_section=i, explicit=explicit_coeff)
    1392            6 :          IF (explicit_coeff) THEN
    1393            6 :             CALL section_vals_val_get(rest_section, "ATOM_COEF", i_rep_section=i, r_vals=atom_coef)
    1394            6 :             CPASSERT(SIZE(atom_list_res) == SIZE(atom_coef))
    1395              :          END IF
    1396           12 :          DO m = 1, SIZE(atom_list_res)
    1397           12 :             IF (explicit_coeff) THEN
    1398           12 :                DO k = 1, SIZE(atom_list_res)
    1399              :                   resp_env%matrix(atom_list_res(m), atom_list_res(k)) = &
    1400              :                      resp_env%matrix(atom_list_res(m), atom_list_res(k)) + &
    1401           12 :                      atom_coef(m)*atom_coef(k)*2.0_dp*strength
    1402              :                END DO
    1403              :                resp_env%rhs(atom_list_res(m)) = resp_env%rhs(atom_list_res(m)) + &
    1404            6 :                                                 2.0_dp*TARGET*strength*atom_coef(m)
    1405              :             ELSE
    1406              :                resp_env%matrix(atom_list_res(m), atom_list_res(m)) = &
    1407              :                   resp_env%matrix(atom_list_res(m), atom_list_res(m)) + &
    1408            0 :                   2.0_dp*strength
    1409              :                resp_env%rhs(atom_list_res(m)) = resp_env%rhs(atom_list_res(m)) + &
    1410            0 :                                                 2.0_dp*TARGET*strength
    1411              :             END IF
    1412              :          END DO
    1413           32 :          DEALLOCATE (atom_list_res)
    1414              :       END DO
    1415              : 
    1416              :       ! if heavies are restrained to zero, add these as well
    1417           14 :       IF (resp_env%rheavies) THEN
    1418           72 :          DO i = 1, natom
    1419           62 :             CALL get_atomic_kind(atomic_kind=particle_set(i)%atomic_kind, z=z)
    1420           72 :             IF (z /= 1) THEN
    1421           30 :                resp_env%matrix(i, i) = resp_env%matrix(i, i) + 2.0_dp*resp_env%rheavies_strength
    1422              :             END IF
    1423              :          END DO
    1424              :       END IF
    1425              : 
    1426              :       !*** add the constraints
    1427           14 :       ncons_v = 0
    1428           14 :       ncons_v = ncons_v + natom
    1429              : 
    1430              :       ! REPEAT charges: treat the offset like a constraint
    1431           14 :       IF (resp_env%use_repeat_method) THEN
    1432            4 :          ncons_v = ncons_v + 1
    1433           32 :          resp_env%matrix(1:natom, ncons_v) = resp_env%sum_vpot(1:natom)
    1434           32 :          resp_env%matrix(ncons_v, 1:natom) = resp_env%sum_vpot(1:natom)
    1435            4 :          resp_env%matrix(ncons_v, ncons_v) = 2.0_dp
    1436            4 :          resp_env%rhs(ncons_v) = resp_env%sum_vhartree
    1437              :       END IF
    1438              : 
    1439              :       ! total charge constraint
    1440           14 :       IF (resp_env%itc) THEN
    1441           14 :          ncons_v = ncons_v + 1
    1442          104 :          resp_env%matrix(1:natom, ncons_v) = 1.0_dp
    1443          104 :          resp_env%matrix(ncons_v, 1:natom) = 1.0_dp
    1444           14 :          resp_env%rhs(ncons_v) = dft_control%charge
    1445              :       END IF
    1446              : 
    1447              :       ! explicit constraints
    1448           28 :       DO i = 1, resp_env%ncons_sec
    1449           14 :          CALL build_atom_list(cons_section, subsys, atom_list_cons, i)
    1450           14 :          IF (.NOT. resp_env%equal_charges) THEN
    1451           12 :             ncons_v = ncons_v + 1
    1452           12 :             CALL section_vals_val_get(cons_section, "ATOM_COEF", i_rep_section=i, r_vals=atom_coef)
    1453           12 :             CALL section_vals_val_get(cons_section, "TARGET", i_rep_section=i, r_val=TARGET)
    1454           12 :             CPASSERT(SIZE(atom_list_cons) == SIZE(atom_coef))
    1455           36 :             DO m = 1, SIZE(atom_list_cons)
    1456           24 :                resp_env%matrix(atom_list_cons(m), ncons_v) = atom_coef(m)
    1457           36 :                resp_env%matrix(ncons_v, atom_list_cons(m)) = atom_coef(m)
    1458              :             END DO
    1459           12 :             resp_env%rhs(ncons_v) = TARGET
    1460              :          ELSE
    1461            2 :             my_atom_coef(1) = 1.0_dp
    1462            2 :             my_atom_coef(2) = -1.0_dp
    1463            6 :             DO k = 2, SIZE(atom_list_cons)
    1464            4 :                ncons_v = ncons_v + 1
    1465            4 :                resp_env%matrix(atom_list_cons(1), ncons_v) = my_atom_coef(1)
    1466            4 :                resp_env%matrix(ncons_v, atom_list_cons(1)) = my_atom_coef(1)
    1467            4 :                resp_env%matrix(atom_list_cons(k), ncons_v) = my_atom_coef(2)
    1468            4 :                resp_env%matrix(ncons_v, atom_list_cons(k)) = my_atom_coef(2)
    1469            6 :                resp_env%rhs(ncons_v) = 0.0_dp
    1470              :             END DO
    1471              :          END IF
    1472           28 :          DEALLOCATE (atom_list_cons)
    1473              :       END DO
    1474           14 :       CALL timestop(handle)
    1475              : 
    1476           14 :    END SUBROUTINE add_restraints_and_constraints
    1477              : 
    1478              : ! **************************************************************************************************
    1479              : !> \brief print input information
    1480              : !> \param qs_env the qs environment
    1481              : !> \param resp_env the resp environment
    1482              : !> \param rep_sys structure for repeating input sections defining fit points
    1483              : !> \param my_per ...
    1484              : ! **************************************************************************************************
    1485           14 :    SUBROUTINE print_resp_parameter_info(qs_env, resp_env, rep_sys, my_per)
    1486              : 
    1487              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1488              :       TYPE(resp_type), POINTER                           :: resp_env
    1489              :       TYPE(resp_p_type), DIMENSION(:), POINTER           :: rep_sys
    1490              :       INTEGER, INTENT(IN)                                :: my_per
    1491              : 
    1492              :       CHARACTER(len=*), PARAMETER :: routineN = 'print_resp_parameter_info'
    1493              : 
    1494              :       CHARACTER(len=2)                                   :: symbol
    1495              :       INTEGER                                            :: handle, i, ikind, kind_number, nkinds, &
    1496              :                                                             output_unit
    1497              :       REAL(KIND=dp)                                      :: conv, eta_conv
    1498           14 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    1499              :       TYPE(cp_logger_type), POINTER                      :: logger
    1500              :       TYPE(section_vals_type), POINTER                   :: input, resp_section
    1501              : 
    1502           14 :       CALL timeset(routineN, handle)
    1503           14 :       NULLIFY (logger, input, resp_section)
    1504              : 
    1505              :       CALL get_qs_env(qs_env, &
    1506              :                       input=input, &
    1507           14 :                       atomic_kind_set=atomic_kind_set)
    1508           14 :       resp_section => section_vals_get_subs_vals(input, "PROPERTIES%RESP")
    1509           14 :       logger => cp_get_default_logger()
    1510              :       output_unit = cp_print_key_unit_nr(logger, resp_section, "PRINT%PROGRAM_RUN_INFO", &
    1511           14 :                                          extension=".resp")
    1512           14 :       nkinds = SIZE(atomic_kind_set)
    1513              : 
    1514           14 :       conv = cp_unit_from_cp2k(1.0_dp, "angstrom")
    1515           14 :       IF (.NOT. my_per == use_perd_none) THEN
    1516           10 :          eta_conv = cp_unit_from_cp2k(resp_env%eta, "angstrom", power=-2)
    1517              :       END IF
    1518              : 
    1519           14 :       IF (output_unit > 0) THEN
    1520            7 :          WRITE (output_unit, '(/,1X,A,/)') "STARTING RESP FIT"
    1521            7 :          IF (resp_env%use_repeat_method) THEN
    1522              :             WRITE (output_unit, '(T3,A)') &
    1523            2 :                "Fit the variance of the potential (REPEAT method)."
    1524              :          END IF
    1525            7 :          IF (.NOT. resp_env%equal_charges) THEN
    1526            6 :             WRITE (output_unit, '(T3,A,T75,I6)') "Number of explicit constraints: ", resp_env%ncons_sec
    1527              :          ELSE
    1528            1 :             IF (resp_env%itc) THEN
    1529            1 :                WRITE (output_unit, '(T3,A,T75,I6)') "Number of explicit constraints: ", resp_env%ncons - 1
    1530              :             ELSE
    1531            0 :                WRITE (output_unit, '(T3,A,T75,I6)') "Number of explicit constraints: ", resp_env%ncons
    1532              :             END IF
    1533              :          END IF
    1534            7 :          WRITE (output_unit, '(T3,A,T75,I6)') "Number of explicit restraints: ", resp_env%nrest_sec
    1535            7 :          WRITE (output_unit, '(T3,A,T80,A)') "Constrain total charge ", MERGE("T", "F", resp_env%itc)
    1536            9 :          WRITE (output_unit, '(T3,A,T80,A)') "Restrain heavy atoms ", MERGE("T", "F", resp_env%rheavies)
    1537            7 :          IF (resp_env%rheavies) THEN
    1538            5 :             WRITE (output_unit, '(T3,A,T71,F10.6)') "Heavy atom restraint strength: ", &
    1539           10 :                resp_env%rheavies_strength
    1540              :          END IF
    1541           28 :          WRITE (output_unit, '(T3,A,T66,3I5)') "Stride: ", resp_env%stride
    1542            7 :          IF (resp_env%molecular_sys) THEN
    1543              :             WRITE (output_unit, '(T3,A)') &
    1544            5 :                "------------------------------------------------------------------------------"
    1545            5 :             WRITE (output_unit, '(T3,A)') "Using sphere sampling"
    1546              :             WRITE (output_unit, '(T3,A,T46,A,T66,A)') &
    1547            5 :                "Element", "RMIN [angstrom]", "RMAX [angstrom]"
    1548           19 :             DO ikind = 1, nkinds
    1549              :                CALL get_atomic_kind(atomic_kind=atomic_kind_set(ikind), &
    1550              :                                     kind_number=kind_number, &
    1551           14 :                                     element_symbol=symbol)
    1552              :                WRITE (output_unit, '(T3,A,T51,F10.5,T71,F10.5)') &
    1553           14 :                   symbol, &
    1554           14 :                   resp_env%rmin_kind(kind_number)*conv, &
    1555           33 :                   resp_env%rmax_kind(kind_number)*conv
    1556              :             END DO
    1557            5 :             IF (my_per == use_perd_none) THEN
    1558            8 :                WRITE (output_unit, '(T3,A,T51,3F10.5)') "Box min [angstrom]: ", resp_env%box_low(1:3)*conv
    1559            8 :                WRITE (output_unit, '(T3,A,T51,3F10.5)') "Box max [angstrom]: ", resp_env%box_hi(1:3)*conv
    1560              :             END IF
    1561              :             WRITE (output_unit, '(T3,A)') &
    1562            5 :                "------------------------------------------------------------------------------"
    1563              :          ELSE
    1564              :             WRITE (output_unit, '(T3,A)') &
    1565            2 :                "------------------------------------------------------------------------------"
    1566            2 :             WRITE (output_unit, '(T3,A)') "Using slab sampling"
    1567            2 :             WRITE (output_unit, '(2X,A,F10.5)') "Index of atoms defining the surface: "
    1568            4 :             DO i = 1, SIZE(rep_sys)
    1569           18 :                IF (i > 1 .AND. ALL(rep_sys(i)%p_resp%atom_surf_list == rep_sys(1)%p_resp%atom_surf_list)) EXIT
    1570           20 :                WRITE (output_unit, '(7X,10I6)') rep_sys(i)%p_resp%atom_surf_list
    1571              :             END DO
    1572            4 :             DO i = 1, SIZE(rep_sys)
    1573            6 :                IF (i > 1 .AND. ALL(rep_sys(i)%p_resp%range_surf == rep_sys(1)%p_resp%range_surf)) EXIT
    1574              :                WRITE (output_unit, '(T3,A,T61,2F10.5)') &
    1575            2 :                   "Range for sampling above the surface [angstrom]:", &
    1576           10 :                   rep_sys(i)%p_resp%range_surf(1:2)*conv
    1577              :             END DO
    1578            4 :             DO i = 1, SIZE(rep_sys)
    1579            2 :                IF (i > 1 .AND. rep_sys(i)%p_resp%length == rep_sys(1)%p_resp%length) EXIT
    1580              :                WRITE (output_unit, '(T3,A,T71,F10.5)') "Length of sampling box above each"// &
    1581            4 :                   " surface atom [angstrom]: ", rep_sys(i)%p_resp%length*conv
    1582              :             END DO
    1583              :             WRITE (output_unit, '(T3,A)') &
    1584            2 :                "------------------------------------------------------------------------------"
    1585              :          END IF
    1586            7 :          IF (.NOT. my_per == use_perd_none) THEN
    1587              :             WRITE (output_unit, '(T3,A,T71,F10.5)') "Width of Gaussian charge"// &
    1588            5 :                " distribution [angstrom^-2]: ", eta_conv
    1589              :          END IF
    1590            7 :          CALL m_flush(output_unit)
    1591              :       END IF
    1592              :       CALL cp_print_key_finished_output(output_unit, logger, resp_section, &
    1593           14 :                                         "PRINT%PROGRAM_RUN_INFO")
    1594              : 
    1595           14 :       CALL timestop(handle)
    1596              : 
    1597           14 :    END SUBROUTINE print_resp_parameter_info
    1598              : 
    1599              : ! **************************************************************************************************
    1600              : !> \brief print RESP charges to an extra file or to the normal output file
    1601              : !> \param qs_env the qs environment
    1602              : !> \param resp_env the resp environment
    1603              : !> \param output_runinfo ...
    1604              : !> \param natom number of atoms
    1605              : ! **************************************************************************************************
    1606           14 :    SUBROUTINE print_resp_charges(qs_env, resp_env, output_runinfo, natom)
    1607              : 
    1608              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1609              :       TYPE(resp_type), POINTER                           :: resp_env
    1610              :       INTEGER, INTENT(IN)                                :: output_runinfo, natom
    1611              : 
    1612              :       CHARACTER(len=*), PARAMETER :: routineN = 'print_resp_charges'
    1613              : 
    1614              :       CHARACTER(LEN=default_path_length)                 :: filename
    1615              :       INTEGER                                            :: handle, output_file
    1616              :       TYPE(cp_logger_type), POINTER                      :: logger
    1617           14 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1618           14 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1619              :       TYPE(section_vals_type), POINTER                   :: input, print_key, resp_section
    1620              : 
    1621           14 :       CALL timeset(routineN, handle)
    1622              : 
    1623           14 :       NULLIFY (particle_set, qs_kind_set, input, logger, resp_section, print_key)
    1624              : 
    1625              :       CALL get_qs_env(qs_env, input=input, particle_set=particle_set, &
    1626           14 :                       qs_kind_set=qs_kind_set)
    1627              : 
    1628           14 :       resp_section => section_vals_get_subs_vals(input, "PROPERTIES%RESP")
    1629              :       print_key => section_vals_get_subs_vals(resp_section, &
    1630           14 :                                               "PRINT%RESP_CHARGES_TO_FILE")
    1631           14 :       logger => cp_get_default_logger()
    1632              : 
    1633           14 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, &
    1634              :                                            resp_section, "PRINT%RESP_CHARGES_TO_FILE"), &
    1635              :                 cp_p_file)) THEN
    1636              :          output_file = cp_print_key_unit_nr(logger, resp_section, &
    1637              :                                             "PRINT%RESP_CHARGES_TO_FILE", &
    1638              :                                             extension=".resp", &
    1639              :                                             file_status="REPLACE", &
    1640              :                                             file_action="WRITE", &
    1641            0 :                                             file_form="FORMATTED")
    1642            0 :          IF (output_file > 0) THEN
    1643              :             filename = cp_print_key_generate_filename(logger, &
    1644              :                                                       print_key, extension=".resp", &
    1645            0 :                                                       my_local=.FALSE.)
    1646              :             CALL print_atomic_charges(particle_set, qs_kind_set, output_file, title="RESP charges:", &
    1647            0 :                                       atomic_charges=resp_env%rhs(1:natom))
    1648            0 :             IF (output_runinfo > 0) WRITE (output_runinfo, '(2X,A,/)') "PRINTED RESP CHARGES TO FILE"
    1649              :          END IF
    1650              : 
    1651              :          CALL cp_print_key_finished_output(output_file, logger, resp_section, &
    1652            0 :                                            "PRINT%RESP_CHARGES_TO_FILE")
    1653              :       ELSE
    1654              :          CALL print_atomic_charges(particle_set, qs_kind_set, output_runinfo, title="RESP charges:", &
    1655           14 :                                    atomic_charges=resp_env%rhs(1:natom))
    1656              :       END IF
    1657              : 
    1658           14 :       CALL timestop(handle)
    1659              : 
    1660           14 :    END SUBROUTINE print_resp_charges
    1661              : 
    1662              : ! **************************************************************************************************
    1663              : !> \brief print potential generated by RESP charges to file
    1664              : !> \param qs_env the qs environment
    1665              : !> \param resp_env the resp environment
    1666              : !> \param particles ...
    1667              : !> \param natom number of atoms
    1668              : !> \param output_runinfo ...
    1669              : ! **************************************************************************************************
    1670           14 :    SUBROUTINE print_pot_from_resp_charges(qs_env, resp_env, particles, natom, output_runinfo)
    1671              : 
    1672              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1673              :       TYPE(resp_type), POINTER                           :: resp_env
    1674              :       TYPE(particle_list_type), POINTER                  :: particles
    1675              :       INTEGER, INTENT(IN)                                :: natom, output_runinfo
    1676              : 
    1677              :       CHARACTER(len=*), PARAMETER :: routineN = 'print_pot_from_resp_charges'
    1678              : 
    1679              :       CHARACTER(LEN=default_path_length)                 :: my_pos_cube
    1680              :       INTEGER                                            :: handle, ip, jx, jy, jz, unit_nr
    1681              :       LOGICAL                                            :: append_cube, mpi_io
    1682              :       REAL(KIND=dp)                                      :: dvol, normalize_factor, rms, rrms, &
    1683              :                                                             sum_diff, sum_hartree, udvol
    1684              :       TYPE(cp_logger_type), POINTER                      :: logger
    1685              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1686              :       TYPE(pw_c1d_gs_type)                               :: rho_resp, v_resp_gspace
    1687              :       TYPE(pw_env_type), POINTER                         :: pw_env
    1688              :       TYPE(pw_poisson_type), POINTER                     :: poisson_env
    1689              :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
    1690              :       TYPE(pw_r3d_rs_type)                               :: aux_r, v_resp_rspace
    1691              :       TYPE(pw_r3d_rs_type), POINTER                      :: v_hartree_rspace
    1692              :       TYPE(section_vals_type), POINTER                   :: input, print_key, resp_section
    1693              : 
    1694           14 :       CALL timeset(routineN, handle)
    1695              : 
    1696           14 :       NULLIFY (auxbas_pw_pool, logger, pw_env, poisson_env, input, print_key, &
    1697           14 :                para_env, resp_section, v_hartree_rspace)
    1698              :       CALL get_qs_env(qs_env, &
    1699              :                       input=input, &
    1700              :                       para_env=para_env, &
    1701              :                       pw_env=pw_env, &
    1702           14 :                       v_hartree_rspace=v_hartree_rspace)
    1703           14 :       normalize_factor = SQRT((resp_env%eta/pi)**3)
    1704           14 :       resp_section => section_vals_get_subs_vals(input, "PROPERTIES%RESP")
    1705              :       print_key => section_vals_get_subs_vals(resp_section, &
    1706           14 :                                               "PRINT%V_RESP_CUBE")
    1707           14 :       logger => cp_get_default_logger()
    1708              : 
    1709              :       !*** calculate potential generated from RESP charges
    1710              :       CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool, &
    1711           14 :                       poisson_env=poisson_env)
    1712              : 
    1713           14 :       CALL auxbas_pw_pool%create_pw(rho_resp)
    1714           14 :       CALL auxbas_pw_pool%create_pw(v_resp_gspace)
    1715           14 :       CALL auxbas_pw_pool%create_pw(v_resp_rspace)
    1716              : 
    1717           14 :       CALL pw_zero(rho_resp)
    1718              :       CALL calculate_rho_resp_all(rho_resp, resp_env%rhs, natom, &
    1719           14 :                                   resp_env%eta, qs_env)
    1720           14 :       CALL pw_zero(v_resp_gspace)
    1721              :       CALL pw_poisson_solve(poisson_env, rho_resp, &
    1722           14 :                             vhartree=v_resp_gspace)
    1723           14 :       CALL pw_zero(v_resp_rspace)
    1724           14 :       CALL pw_transfer(v_resp_gspace, v_resp_rspace)
    1725           14 :       dvol = v_resp_rspace%pw_grid%dvol
    1726           14 :       CALL pw_scale(v_resp_rspace, dvol)
    1727           14 :       CALL pw_scale(v_resp_rspace, -normalize_factor)
    1728              :       ! REPEAT: correct for offset, take into account that potentials have reverse sign
    1729              :       ! and are scaled by dvol
    1730           14 :       IF (resp_env%use_repeat_method) THEN
    1731       101437 :          v_resp_rspace%array(:, :, :) = v_resp_rspace%array(:, :, :) - resp_env%offset*dvol
    1732              :       END IF
    1733           14 :       CALL v_resp_gspace%release()
    1734           14 :       CALL rho_resp%release()
    1735              : 
    1736              :       !***now print the v_resp_rspace%pw to a cube file if requested
    1737           14 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, resp_section, &
    1738              :                                            "PRINT%V_RESP_CUBE"), cp_p_file)) THEN
    1739            2 :          CALL auxbas_pw_pool%create_pw(aux_r)
    1740            2 :          append_cube = section_get_lval(resp_section, "PRINT%V_RESP_CUBE%APPEND")
    1741            2 :          my_pos_cube = "REWIND"
    1742            2 :          IF (append_cube) THEN
    1743            0 :             my_pos_cube = "APPEND"
    1744              :          END IF
    1745            2 :          mpi_io = .TRUE.
    1746              :          unit_nr = cp_print_key_unit_nr(logger, resp_section, &
    1747              :                                         "PRINT%V_RESP_CUBE", &
    1748              :                                         extension=".cube", &
    1749              :                                         file_position=my_pos_cube, &
    1750            2 :                                         mpi_io=mpi_io)
    1751            2 :          udvol = 1.0_dp/dvol
    1752            2 :          CALL pw_copy(v_resp_rspace, aux_r)
    1753            2 :          CALL pw_scale(aux_r, udvol)
    1754              :          CALL cp_pw_to_cube(aux_r, unit_nr, "RESP POTENTIAL", particles=particles, &
    1755              :                             stride=section_get_ivals(resp_section, &
    1756              :                                                      "PRINT%V_RESP_CUBE%STRIDE"), &
    1757            2 :                             mpi_io=mpi_io)
    1758              :          CALL cp_print_key_finished_output(unit_nr, logger, resp_section, &
    1759            2 :                                            "PRINT%V_RESP_CUBE", mpi_io=mpi_io)
    1760            2 :          CALL auxbas_pw_pool%give_back_pw(aux_r)
    1761              :       END IF
    1762              : 
    1763              :       !*** RMS and RRMS
    1764           14 :       sum_diff = 0.0_dp
    1765           14 :       sum_hartree = 0.0_dp
    1766              :       rms = 0.0_dp
    1767              :       rrms = 0.0_dp
    1768         2130 :       DO ip = 1, resp_env%npoints_proc
    1769         2116 :          jx = resp_env%fitpoints(1, ip)
    1770         2116 :          jy = resp_env%fitpoints(2, ip)
    1771         2116 :          jz = resp_env%fitpoints(3, ip)
    1772              :          sum_diff = sum_diff + (v_hartree_rspace%array(jx, jy, jz) - &
    1773         2116 :                                 v_resp_rspace%array(jx, jy, jz))**2
    1774         2130 :          sum_hartree = sum_hartree + v_hartree_rspace%array(jx, jy, jz)**2
    1775              :       END DO
    1776           14 :       CALL para_env%sum(sum_diff)
    1777           14 :       CALL para_env%sum(sum_hartree)
    1778           14 :       rms = SQRT(sum_diff/resp_env%npoints)
    1779           14 :       rrms = SQRT(sum_diff/sum_hartree)
    1780           14 :       IF (output_runinfo > 0) THEN
    1781              :          WRITE (output_runinfo, '(2X,A,T69,ES12.5)') "Root-mean-square (RMS) "// &
    1782            7 :             "error of RESP fit:", rms
    1783              :          WRITE (output_runinfo, '(2X,A,T69,ES12.5,/)') "Relative root-mean-square "// &
    1784            7 :             "(RRMS) error of RESP fit:", rrms
    1785              :       END IF
    1786              : 
    1787           14 :       CALL v_resp_rspace%release()
    1788              : 
    1789           14 :       CALL timestop(handle)
    1790              : 
    1791           14 :    END SUBROUTINE print_pot_from_resp_charges
    1792              : 
    1793            0 : END MODULE qs_resp
        

Generated by: LCOV version 2.0-1