LCOV - code coverage report
Current view: top level - src - qs_dcdr_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 90.2 % 478 431
Test Date: 2025-12-04 06:27:48 Functions: 100.0 % 8 8

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Calculate the derivatives of the MO coefficients wrt nuclear coordinates
      10              : !> \author Sandra Luber, Edward Ditler
      11              : ! **************************************************************************************************
      12              : 
      13              : MODULE qs_dcdr_utils
      14              : !#include "./common/cp_common_uses.f90"
      15              :    USE cell_types,                      ONLY: cell_type,&
      16              :                                               get_cell
      17              :    USE cp_control_types,                ONLY: dft_control_type
      18              :    USE cp_dbcsr_api,                    ONLY: dbcsr_copy,&
      19              :                                               dbcsr_create,&
      20              :                                               dbcsr_init_p,&
      21              :                                               dbcsr_p_type,&
      22              :                                               dbcsr_set,&
      23              :                                               dbcsr_type,&
      24              :                                               dbcsr_type_no_symmetry,&
      25              :                                               dbcsr_type_symmetric
      26              :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_alloc_block_from_nbl
      27              :    USE cp_dbcsr_operations,             ONLY: cp_dbcsr_sm_fm_multiply,&
      28              :                                               dbcsr_allocate_matrix_set,&
      29              :                                               dbcsr_deallocate_matrix_set
      30              :    USE cp_files,                        ONLY: close_file,&
      31              :                                               open_file
      32              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      33              :                                               cp_fm_struct_release
      34              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      35              :                                               cp_fm_get_info,&
      36              :                                               cp_fm_get_submatrix,&
      37              :                                               cp_fm_release,&
      38              :                                               cp_fm_set_all,&
      39              :                                               cp_fm_set_submatrix,&
      40              :                                               cp_fm_to_fm,&
      41              :                                               cp_fm_type
      42              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      43              :                                               cp_logger_get_default_io_unit,&
      44              :                                               cp_logger_type,&
      45              :                                               cp_to_string
      46              :    USE cp_output_handling,              ONLY: cp_p_file,&
      47              :                                               cp_print_key_finished_output,&
      48              :                                               cp_print_key_generate_filename,&
      49              :                                               cp_print_key_should_output,&
      50              :                                               cp_print_key_unit_nr
      51              :    USE cp_result_methods,               ONLY: get_results
      52              :    USE cp_result_types,                 ONLY: cp_result_type
      53              :    USE input_constants,                 ONLY: current_orb_center_wannier,&
      54              :                                               use_mom_ref_user
      55              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      56              :                                               section_vals_type,&
      57              :                                               section_vals_val_get
      58              :    USE kinds,                           ONLY: default_path_length,&
      59              :                                               default_string_length,&
      60              :                                               dp
      61              :    USE memory_utilities,                ONLY: reallocate
      62              :    USE message_passing,                 ONLY: mp_para_env_type
      63              :    USE molecule_types,                  ONLY: molecule_type
      64              :    USE moments_utils,                   ONLY: get_reference_point
      65              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      66              :    USE particle_types,                  ONLY: particle_type
      67              :    USE qs_core_matrices,                ONLY: kinetic_energy_matrix
      68              :    USE qs_environment_types,            ONLY: get_qs_env,&
      69              :                                               qs_environment_type
      70              :    USE qs_ks_types,                     ONLY: qs_ks_env_type
      71              :    USE qs_linres_types,                 ONLY: dcdr_env_type,&
      72              :                                               linres_control_type
      73              :    USE qs_loc_types,                    ONLY: get_qs_loc_env,&
      74              :                                               localized_wfn_control_type,&
      75              :                                               qs_loc_env_type
      76              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      77              :                                               mo_set_type
      78              :    USE qs_moments,                      ONLY: build_local_moment_matrix
      79              :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type
      80              :    USE qs_overlap,                      ONLY: build_overlap_matrix
      81              :    USE string_utilities,                ONLY: xstring
      82              : #include "./base/base_uses.f90"
      83              : 
      84              :    IMPLICIT NONE
      85              : 
      86              :    PRIVATE
      87              :    PUBLIC :: dcdr_env_cleanup, dcdr_env_init, dcdr_print, &
      88              :              get_loc_setting, shift_wannier_into_cell, &
      89              :              dcdr_write_restart, dcdr_read_restart, &
      90              :              multiply_localization
      91              : 
      92              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_dcdr_utils'
      93              : 
      94              :    REAL(dp), DIMENSION(3, 3, 3), PARAMETER  :: Levi_Civita = RESHAPE([ &
      95              :                                                           0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, -1.0_dp, 0.0_dp, 1.0_dp, 0.0_dp, &
      96              :                                                           0.0_dp, 0.0_dp, 1.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, -1.0_dp, 0.0_dp, 0.0_dp, &
      97              :                                                          0.0_dp, -1.0_dp, 0.0_dp, 1.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp], &
      98              :                                                                      [3, 3, 3])
      99              : 
     100              : CONTAINS
     101              : 
     102              : ! **************************************************************************************************
     103              : !> \brief Multiply (ao_matrix @ mo_coeff) and store the column icenter in res
     104              : !> \param ao_matrix ...
     105              : !> \param mo_coeff ...
     106              : !> \param work Working space
     107              : !> \param nmo ...
     108              : !> \param icenter ...
     109              : !> \param res ...
     110              : !> \author Edward Ditler
     111              : ! **************************************************************************************************
     112          864 :    SUBROUTINE multiply_localization(ao_matrix, mo_coeff, work, nmo, icenter, res)
     113              :       TYPE(dbcsr_type), INTENT(IN), POINTER              :: ao_matrix
     114              :       TYPE(cp_fm_type), INTENT(IN)                       :: mo_coeff
     115              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: work
     116              :       INTEGER, INTENT(IN)                                :: nmo, icenter
     117              :       TYPE(cp_fm_type), INTENT(IN)                       :: res
     118              : 
     119              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'multiply_localization'
     120              : 
     121              :       INTEGER                                            :: handle
     122              : 
     123          864 :       CALL timeset(routineN, handle)
     124              : 
     125              :       ! Multiply by the MO coefficients
     126          864 :       CALL cp_dbcsr_sm_fm_multiply(ao_matrix, mo_coeff, work, ncol=nmo)
     127              : 
     128              :       ! Only keep the icenter-th column
     129          864 :       CALL cp_fm_to_fm(work, res, 1, icenter, icenter)
     130              : 
     131              :       ! Reset the matrices
     132          864 :       CALL cp_fm_set_all(work, 0.0_dp)
     133              : 
     134          864 :       CALL timestop(handle)
     135          864 :    END SUBROUTINE multiply_localization
     136              : 
     137              : ! **************************************************************************************************
     138              : !> \brief Copied from linres_read_restart
     139              : !> \param qs_env ...
     140              : !> \param linres_section ...
     141              : !> \param vec ...
     142              : !> \param lambda ...
     143              : !> \param beta ...
     144              : !> \param tag ...
     145              : !> \note Adapted from linres_read_restart (ED)
     146              : !>       Would be nice not to crash but to start from zero if the present file doesn't match.
     147              : ! **************************************************************************************************
     148           18 :    SUBROUTINE dcdr_read_restart(qs_env, linres_section, vec, lambda, beta, tag)
     149              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     150              :       TYPE(section_vals_type), POINTER                   :: linres_section
     151              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: vec
     152              :       INTEGER, INTENT(IN)                                :: lambda, beta
     153              :       CHARACTER(LEN=*)                                   :: tag
     154              : 
     155              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'dcdr_read_restart'
     156              : 
     157              :       CHARACTER(LEN=default_path_length)                 :: filename
     158              :       CHARACTER(LEN=default_string_length)               :: my_middle
     159              :       INTEGER :: beta_tmp, handle, i, i_block, ia, ie, iostat, iounit, ispin, j, lambda_tmp, &
     160              :          max_block, n_rep_val, nao, nao_tmp, nmo, nmo_tmp, nspins, nspins_tmp, rst_unit
     161              :       LOGICAL                                            :: file_exists
     162           18 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: vecbuffer
     163              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     164              :       TYPE(cp_logger_type), POINTER                      :: logger
     165           18 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     166              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     167              :       TYPE(section_vals_type), POINTER                   :: print_key
     168              : 
     169           18 :       file_exists = .FALSE.
     170              : 
     171           18 :       CALL timeset(routineN, handle)
     172              : 
     173           18 :       NULLIFY (mos, para_env, logger, print_key, vecbuffer)
     174           18 :       logger => cp_get_default_logger()
     175              : 
     176              :       iounit = cp_print_key_unit_nr(logger, linres_section, &
     177           18 :                                     "PRINT%PROGRAM_RUN_INFO", extension=".Log")
     178              : 
     179              :       CALL get_qs_env(qs_env=qs_env, &
     180              :                       para_env=para_env, &
     181           18 :                       mos=mos)
     182              : 
     183           18 :       nspins = SIZE(mos)
     184              : 
     185           18 :       rst_unit = -1
     186           18 :       IF (para_env%is_source()) THEN
     187              :          CALL section_vals_val_get(linres_section, "WFN_RESTART_FILE_NAME", &
     188            9 :                                    n_rep_val=n_rep_val)
     189              : 
     190            9 :          CALL XSTRING(tag, ia, ie)
     191              :          my_middle = "RESTART-"//tag(ia:ie)//TRIM("-")//TRIM(ADJUSTL(cp_to_string(beta))) &
     192            9 :                      //TRIM("-")//TRIM(ADJUSTL(cp_to_string(lambda)))
     193              : 
     194            9 :          IF (n_rep_val > 0) THEN
     195            0 :             CALL section_vals_val_get(linres_section, "WFN_RESTART_FILE_NAME", c_val=filename)
     196            0 :             CALL xstring(filename, ia, ie)
     197            0 :             filename = filename(ia:ie)//TRIM(my_middle)//".lr"
     198              :          ELSE
     199              :             ! try to read from the filename that is generated automatically from the printkey
     200            9 :             print_key => section_vals_get_subs_vals(linres_section, "PRINT%RESTART")
     201              :             filename = cp_print_key_generate_filename(logger, print_key, &
     202            9 :                                                       extension=".lr", middle_name=TRIM(my_middle), my_local=.FALSE.)
     203              :          END IF
     204            9 :          INQUIRE (FILE=filename, exist=file_exists)
     205              :          !
     206              :          ! open file
     207            9 :          IF (file_exists) THEN
     208              :             CALL open_file(file_name=TRIM(filename), &
     209              :                            file_action="READ", &
     210              :                            file_form="UNFORMATTED", &
     211              :                            file_position="REWIND", &
     212              :                            file_status="OLD", &
     213            0 :                            unit_number=rst_unit)
     214              : 
     215            0 :             IF (iounit > 0) WRITE (iounit, "(T2,A)") &
     216            0 :                "LINRES| Reading response wavefunctions from the restart file <"//TRIM(ADJUSTL(filename))//">"
     217              :          ELSE
     218            9 :             IF (iounit > 0) WRITE (iounit, "(T2,A)") &
     219            9 :                "LINRES| Restart file  <"//TRIM(ADJUSTL(filename))//"> not found"
     220              :          END IF
     221              :       END IF
     222              : 
     223           18 :       CALL para_env%bcast(file_exists)
     224              : 
     225           18 :       IF (file_exists) THEN
     226              : 
     227            0 :          CALL get_mo_set(mos(1), mo_coeff=mo_coeff)
     228            0 :          CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_block=max_block)
     229              : 
     230            0 :          ALLOCATE (vecbuffer(nao, max_block))
     231            0 :          vecbuffer = 0.0_dp
     232              :          !
     233              :          ! read headers
     234            0 :          IF (rst_unit > 0) READ (rst_unit, IOSTAT=iostat) lambda_tmp, beta_tmp, nspins_tmp, nao_tmp
     235            0 :          CALL para_env%bcast(iostat)
     236            0 :          CALL para_env%bcast(beta_tmp)
     237            0 :          CALL para_env%bcast(lambda_tmp)
     238            0 :          CALL para_env%bcast(nspins_tmp)
     239            0 :          CALL para_env%bcast(nao_tmp)
     240              : 
     241              :          ! check that the number nao, nmo and nspins are
     242              :          ! the same as in the current mos
     243            0 :          IF (nspins_tmp /= nspins) THEN
     244            0 :             CPABORT("nspins not consistent")
     245              :          END IF
     246            0 :          IF (nao_tmp /= nao) CPABORT("nao not consistent")
     247              :          ! check that it's the right file
     248              :          ! the same as in the current mos
     249            0 :          IF (lambda_tmp /= lambda) CPABORT("lambda not consistent")
     250            0 :          IF (beta_tmp /= beta) CPABORT("beta not consistent")
     251              :          !
     252            0 :          DO ispin = 1, nspins
     253            0 :             CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff)
     254            0 :             CALL cp_fm_get_info(mo_coeff, ncol_global=nmo)
     255              :             !
     256            0 :             IF (rst_unit > 0) READ (rst_unit) nmo_tmp
     257            0 :             CALL para_env%bcast(nmo_tmp)
     258            0 :             IF (nmo_tmp /= nmo) CPABORT("nmo not consistent")
     259              :             !
     260              :             ! read the response
     261            0 :             DO i = 1, nmo, MAX(max_block, 1)
     262            0 :                i_block = MIN(max_block, nmo - i + 1)
     263            0 :                DO j = 1, i_block
     264            0 :                   IF (rst_unit > 0) READ (rst_unit) vecbuffer(1:nao, j)
     265              :                END DO
     266            0 :                CALL para_env%bcast(vecbuffer)
     267            0 :                CALL cp_fm_set_submatrix(vec(ispin), vecbuffer, 1, i, nao, i_block)
     268              :             END DO
     269              :          END DO
     270              : 
     271            0 :          IF (iostat /= 0) THEN
     272            0 :             IF (iounit > 0) WRITE (iounit, "(T2,A)") &
     273            0 :                "LINRES| Restart file <"//TRIM(ADJUSTL(filename))//"> not found"
     274              :          END IF
     275              : 
     276            0 :          DEALLOCATE (vecbuffer)
     277              : 
     278              :       END IF
     279              : 
     280           18 :       IF (para_env%is_source()) THEN
     281            9 :          IF (file_exists) CALL close_file(unit_number=rst_unit)
     282              :       END IF
     283              : 
     284           18 :       CALL timestop(handle)
     285              : 
     286           18 :    END SUBROUTINE dcdr_read_restart
     287              : 
     288              : ! **************************************************************************************************
     289              : !> \brief Copied from linres_write_restart
     290              : !> \param qs_env ...
     291              : !> \param linres_section ...
     292              : !> \param vec ...
     293              : !> \param lambda ...
     294              : !> \param beta ...
     295              : !> \param tag ...
     296              : !> \note Adapted from linres_read_restart (ED)
     297              : !>       Would be nice not to crash but to start from zero if the present file doesn't match.
     298              : ! **************************************************************************************************
     299           18 :    SUBROUTINE dcdr_write_restart(qs_env, linres_section, vec, lambda, beta, tag)
     300              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     301              :       TYPE(section_vals_type), POINTER                   :: linres_section
     302              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: vec
     303              :       INTEGER, INTENT(IN)                                :: lambda, beta
     304              :       CHARACTER(LEN=*)                                   :: tag
     305              : 
     306              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dcdr_write_restart'
     307              : 
     308              :       CHARACTER(LEN=default_path_length)                 :: filename
     309              :       CHARACTER(LEN=default_string_length)               :: my_middle, my_pos, my_status
     310              :       INTEGER                                            :: handle, i, i_block, ia, ie, iounit, &
     311              :                                                             ispin, j, max_block, nao, nmo, nspins, &
     312              :                                                             rst_unit
     313           18 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: vecbuffer
     314              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     315              :       TYPE(cp_logger_type), POINTER                      :: logger
     316           18 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     317              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     318              :       TYPE(section_vals_type), POINTER                   :: print_key
     319              : 
     320           18 :       NULLIFY (logger, mo_coeff, mos, para_env, print_key, vecbuffer)
     321              : 
     322           18 :       CALL timeset(routineN, handle)
     323              : 
     324           18 :       logger => cp_get_default_logger()
     325              : 
     326           18 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, linres_section, "PRINT%RESTART", &
     327              :                                            used_print_key=print_key), &
     328              :                 cp_p_file)) THEN
     329              : 
     330              :          iounit = cp_print_key_unit_nr(logger, linres_section, &
     331           18 :                                        "PRINT%PROGRAM_RUN_INFO", extension=".Log")
     332              : 
     333              :          CALL get_qs_env(qs_env=qs_env, &
     334              :                          mos=mos, &
     335           18 :                          para_env=para_env)
     336              : 
     337           18 :          nspins = SIZE(mos)
     338              : 
     339           18 :          my_status = "REPLACE"
     340           18 :          my_pos = "REWIND"
     341           18 :          CALL XSTRING(tag, ia, ie)
     342              :          my_middle = "RESTART-"//tag(ia:ie)//TRIM("-")//TRIM(ADJUSTL(cp_to_string(beta))) &
     343           18 :                      //TRIM("-")//TRIM(ADJUSTL(cp_to_string(lambda)))
     344              :          rst_unit = cp_print_key_unit_nr(logger, linres_section, "PRINT%RESTART", &
     345              :                                          extension=".lr", middle_name=TRIM(my_middle), file_status=TRIM(my_status), &
     346           18 :                                          file_position=TRIM(my_pos), file_action="WRITE", file_form="UNFORMATTED")
     347              : 
     348              :          filename = cp_print_key_generate_filename(logger, print_key, &
     349           18 :                                                    extension=".lr", middle_name=TRIM(my_middle), my_local=.FALSE.)
     350              : 
     351           18 :          IF (iounit > 0) THEN
     352              :             WRITE (UNIT=iounit, FMT="(T2,A)") &
     353            9 :                "LINRES| Writing response functions to the restart file <"//TRIM(ADJUSTL(filename))//">"
     354              :          END IF
     355              : 
     356              :          !
     357              :          ! write data to file
     358              :          ! use the scalapack block size as a default for buffering columns
     359           18 :          CALL get_mo_set(mos(1), mo_coeff=mo_coeff)
     360           18 :          CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_block=max_block)
     361           72 :          ALLOCATE (vecbuffer(nao, max_block))
     362              : 
     363           18 :          IF (rst_unit > 0) WRITE (rst_unit) lambda, beta, nspins, nao
     364              : 
     365           36 :          DO ispin = 1, nspins
     366           18 :             CALL cp_fm_get_info(vec(ispin), ncol_global=nmo)
     367              : 
     368           18 :             IF (rst_unit > 0) WRITE (rst_unit) nmo
     369              : 
     370           72 :             DO i = 1, nmo, MAX(max_block, 1)
     371           18 :                i_block = MIN(max_block, nmo - i + 1)
     372           18 :                CALL cp_fm_get_submatrix(vec(ispin), vecbuffer, 1, i, nao, i_block)
     373              :                ! doing this in one write would increase efficiency, but breaks RESTART compatibility.
     374              :                ! to old ones, and in cases where max_block is different between runs, as might happen during
     375              :                ! restarts with a different number of CPUs
     376          108 :                DO j = 1, i_block
     377           90 :                   IF (rst_unit > 0) WRITE (rst_unit) vecbuffer(1:nao, j)
     378              :                END DO
     379              :             END DO
     380              :          END DO
     381              : 
     382           18 :          DEALLOCATE (vecbuffer)
     383              : 
     384              :          CALL cp_print_key_finished_output(rst_unit, logger, linres_section, &
     385           36 :                                            "PRINT%RESTART")
     386              :       END IF
     387              : 
     388           18 :       CALL timestop(handle)
     389              : 
     390           18 :    END SUBROUTINE dcdr_write_restart
     391              : 
     392              : ! **************************************************************************************************
     393              : !> \brief Print the APT and sum rules
     394              : !> \param dcdr_env ...
     395              : !> \param qs_env ...
     396              : !> \author Edward Ditler
     397              : ! **************************************************************************************************
     398           22 :    SUBROUTINE dcdr_print(dcdr_env, qs_env)
     399              :       TYPE(dcdr_env_type)                                :: dcdr_env
     400              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     401              : 
     402              :       CHARACTER(LEN=default_string_length)               :: description
     403              :       INTEGER                                            :: alpha, beta, delta, gamma, i, k, l, &
     404              :                                                             lambda, natom, nsubset, output_unit
     405           22 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: apt_el_dcdr, apt_nuc_dcdr, apt_total_dcdr
     406           22 :       REAL(dp), DIMENSION(:, :, :, :), POINTER           :: apt_center_dcdr, apt_subset_dcdr
     407              :       REAL(kind=dp), DIMENSION(3, 3)                     :: sum_rule_0, sum_rule_1, sum_rule_2
     408              :       TYPE(cp_logger_type), POINTER                      :: logger
     409              :       TYPE(cp_result_type), POINTER                      :: results
     410           22 :       TYPE(molecule_type), DIMENSION(:), POINTER         :: molecule_set
     411           22 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     412              :       TYPE(section_vals_type), POINTER                   :: dcdr_section
     413              : 
     414           22 :       NULLIFY (logger)
     415              : 
     416           44 :       logger => cp_get_default_logger()
     417           22 :       output_unit = cp_logger_get_default_io_unit(logger)
     418              : 
     419           22 :       dcdr_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%LINRES%DCDR")
     420              : 
     421           22 :       NULLIFY (particle_set)
     422           22 :       CALL get_qs_env(qs_env=qs_env, particle_set=particle_set, molecule_set=molecule_set)
     423           22 :       natom = SIZE(particle_set)
     424           22 :       nsubset = SIZE(molecule_set)
     425              : 
     426           22 :       apt_el_dcdr => dcdr_env%apt_el_dcdr
     427           22 :       apt_nuc_dcdr => dcdr_env%apt_nuc_dcdr
     428           22 :       apt_total_dcdr => dcdr_env%apt_total_dcdr
     429           22 :       apt_subset_dcdr => dcdr_env%apt_el_dcdr_per_subset
     430           22 :       apt_center_dcdr => dcdr_env%apt_el_dcdr_per_center
     431              : 
     432           22 :       IF (dcdr_env%localized_psi0) THEN
     433            4 :          IF (dcdr_env%output_unit > 0) WRITE (dcdr_env%output_unit, "(A)") 'APT | Write the final apt matrix per atom per subset'
     434           16 :          DO k = 1, natom
     435           52 :             DO l = 1, nsubset
     436           36 :                IF (dcdr_env%output_unit > 0) WRITE (dcdr_env%output_unit, *) 'APT | Subset', l
     437          156 :                DO i = 1, 3
     438          108 :                   IF (dcdr_env%output_unit > 0) WRITE (dcdr_env%output_unit, "(A,I3,F15.6,F15.6,F15.6)") &
     439           90 :                      'APT | apt_subset ', i, apt_subset_dcdr(i, :, k, l)
     440              :                END DO
     441              :             END DO
     442              :          END DO
     443              :       END IF
     444              : 
     445           22 :       IF (dcdr_env%output_unit > 0) WRITE (dcdr_env%output_unit, "(A)") &
     446           11 :          'APT | Write the final apt matrix per atom (Position perturbation)'
     447           88 :       DO l = 1, natom
     448           66 :          IF (dcdr_env%output_unit > 0) WRITE (dcdr_env%output_unit, "(A,I3,A,F15.6)") &
     449           33 :             'APT | Atom', l, ' - GAPT ', &
     450              :             (apt_total_dcdr(1, 1, l) &
     451              :              + apt_total_dcdr(2, 2, l) &
     452           66 :              + apt_total_dcdr(3, 3, l))/3._dp
     453          286 :          DO i = 1, 3
     454          264 :             IF (dcdr_env%output_unit > 0) WRITE (dcdr_env%output_unit, "(A,F15.6,F15.6,F15.6)") "APT | ", apt_total_dcdr(i, :, l)
     455              :          END DO
     456              :       END DO
     457              : 
     458           22 :       IF (dcdr_env%output_unit > 0) WRITE (dcdr_env%output_unit, "(A)") 'APT | Write the total apt matrix'
     459           88 :       DO i = 1, 3
     460           66 :          IF (dcdr_env%output_unit > 0) WRITE (dcdr_env%output_unit, &
     461          451 :                                               "(A,F15.6,F15.6,F15.6)") "APT | ", SUM(apt_total_dcdr(i, :, :), dim=2)
     462              :       END DO
     463           22 :       IF (dcdr_env%output_unit > 0) WRITE (dcdr_env%output_unit, "(A)") 'APT | End Write the final apt matrix'
     464              : 
     465              :       ! Get the dipole
     466           22 :       CALL get_qs_env(qs_env, results=results)
     467           22 :       description = "[DIPOLE]"
     468           22 :       CALL get_results(results=results, description=description, values=dcdr_env%dipole_pos(1:3))
     469              : 
     470              :       ! Sum rules [for all alpha, beta]
     471           22 :       sum_rule_0 = 0._dp
     472           22 :       sum_rule_1 = 0._dp
     473           22 :       sum_rule_2 = 0._dp
     474              : 
     475           88 :       DO alpha = 1, 3
     476          286 :          DO beta = 1, 3
     477              :             ! 0: sum_lambda apt(alpha, beta, lambda)
     478          792 :             DO lambda = 1, natom
     479              :                sum_rule_0(alpha, beta) = sum_rule_0(alpha, beta) &
     480          792 :                                          + apt_total_dcdr(alpha, beta, lambda)
     481              :             END DO
     482              : 
     483              :             ! 1: sum_gamma epsilon_(alpha beta gamma) mu_gamma
     484          792 :             DO gamma = 1, 3
     485              :                sum_rule_1(alpha, beta) = sum_rule_1(alpha, beta) &
     486          792 :                                          + Levi_Civita(alpha, beta, gamma)*dcdr_env%dipole_pos(gamma)
     487              :             END DO
     488              : 
     489              :             ! 2: sum_(lambda gamma delta) R^lambda_gamma apt(delta, alpha, lambda)
     490          858 :             DO lambda = 1, natom
     491         2574 :                DO gamma = 1, 3
     492         7722 :                   DO delta = 1, 3
     493              :                      sum_rule_2(alpha, beta) = sum_rule_2(alpha, beta) &
     494              :                                                + Levi_Civita(beta, gamma, delta) &
     495              :                                                *particle_set(lambda)%r(gamma) &
     496         7128 :                                                *apt_total_dcdr(delta, alpha, lambda)
     497              :                   END DO
     498              :                END DO
     499              :             END DO
     500              : 
     501              :          END DO ! beta
     502              :       END DO   ! alpha
     503              : 
     504           22 :       IF (dcdr_env%output_unit > 0) WRITE (dcdr_env%output_unit, "(A)") "APT | Position perturbation sum rules"
     505           22 :       IF (dcdr_env%output_unit > 0) WRITE (dcdr_env%output_unit, "(A,T18,A,T34,A,T49,A)") &
     506           11 :          "APT |", "Total APT", "Dipole", "R * APT"
     507           88 :       DO alpha = 1, 3
     508          286 :          DO beta = 1, 3
     509          198 :             IF (dcdr_env%output_unit > 0) WRITE (dcdr_env%output_unit, &
     510              :                                                  "(A,I3,I3,F15.6,F15.6,F15.6)") &
     511           99 :                "APT | ", &
     512           99 :                alpha, beta, &
     513           99 :                sum_rule_0(alpha, beta), &
     514           99 :                sum_rule_1(alpha, beta), &
     515          264 :                sum_rule_2(alpha, beta)
     516              :          END DO
     517              :       END DO
     518              : 
     519           22 :    END SUBROUTINE dcdr_print
     520              : 
     521              : ! **************************************************************************************************
     522              : !> \brief ...
     523              : !> \param r ...
     524              : !> \param cell ...
     525              : !> \param r_shifted ...
     526              : ! **************************************************************************************************
     527          144 :    SUBROUTINE shift_wannier_into_cell(r, cell, r_shifted)
     528              :       REAL(dp), DIMENSION(3), INTENT(in)                 :: r
     529              :       TYPE(cell_type), INTENT(in), POINTER               :: cell
     530              :       REAL(dp), DIMENSION(3), INTENT(out)                :: r_shifted
     531              : 
     532              :       INTEGER                                            :: i
     533              :       REAL(kind=dp), DIMENSION(3)                        :: abc
     534              : 
     535              :       ! Only orthorombic cell for now
     536          144 :       CALL get_cell(cell, abc=abc)
     537              : 
     538          576 :       DO i = 1, 3
     539          576 :          IF (r(i) < 0._dp) THEN
     540          234 :             r_shifted(i) = r(i) + abc(i)
     541          198 :          ELSE IF (r(i) > abc(i)) THEN
     542            0 :             r_shifted(i) = r(i) - abc(i)
     543              :          ELSE
     544          198 :             r_shifted(i) = r(i)
     545              :          END IF
     546              :       END DO
     547          144 :    END SUBROUTINE shift_wannier_into_cell
     548              : 
     549              : ! **************************************************************************************************
     550              : !> \brief ...
     551              : !> \param dcdr_env ...
     552              : !> \param qs_env ...
     553              : ! **************************************************************************************************
     554            4 :    SUBROUTINE get_loc_setting(dcdr_env, qs_env)
     555              :       TYPE(dcdr_env_type)                                :: dcdr_env
     556              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     557              : 
     558              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'get_loc_setting'
     559              : 
     560              :       INTEGER                                            :: handle, is, ispin, istate, max_states, &
     561              :                                                             nmo, nmoloc, nstate, nstate_list(2)
     562            4 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: state_list
     563            4 :       REAL(dp), DIMENSION(:, :), POINTER                 :: center_array
     564              :       TYPE(linres_control_type), POINTER                 :: linres_control
     565              :       TYPE(localized_wfn_control_type), POINTER          :: localized_wfn_control
     566            4 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     567              :       TYPE(qs_loc_env_type), POINTER                     :: qs_loc_env
     568              :       TYPE(section_vals_type), POINTER                   :: dcdr_section
     569              : 
     570            4 :       CALL timeset(routineN, handle)
     571              : 
     572              :       CALL get_qs_env(qs_env=qs_env, &
     573              :                       linres_control=linres_control, &
     574            4 :                       mos=mos)
     575              : 
     576              :       ! Some checks
     577            4 :       max_states = 0
     578            4 :       CALL get_mo_set(mo_set=mos(1), nmo=nmo)
     579            4 :       max_states = MAX(max_states, nmo)
     580              : 
     581              :       ! check that the number of localized states is equal to the number of states
     582            4 :       nmoloc = SIZE(linres_control%qs_loc_env%localized_wfn_control%centers_set(1)%array, 2)
     583            4 :       IF (nmoloc /= nmo) THEN
     584            0 :          CPABORT("The number of localized functions is not equal to the number of states.")
     585              :       END IF
     586              : 
     587              :       ! which center for the orbitals shall we use
     588            4 :       dcdr_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%LINRES%DCDR")
     589            4 :       CALL section_vals_val_get(dcdr_section, "ORBITAL_CENTER", i_val=dcdr_env%orb_center)
     590            8 :       SELECT CASE (dcdr_env%orb_center)
     591              :       CASE (current_orb_center_wannier)
     592            4 :          dcdr_env%orb_center_name = "WANNIER"
     593              :       CASE DEFAULT
     594            4 :          CPABORT(" ")
     595              :       END SELECT
     596              : 
     597            4 :       qs_loc_env => linres_control%qs_loc_env
     598            4 :       CALL get_qs_loc_env(qs_loc_env, localized_wfn_control=localized_wfn_control)
     599              : 
     600           16 :       ALLOCATE (dcdr_env%centers_set(dcdr_env%nspins))
     601           12 :       ALLOCATE (dcdr_env%center_list(dcdr_env%nspins))
     602           16 :       ALLOCATE (state_list(max_states, dcdr_env%nspins))
     603           24 :       state_list(:, :) = HUGE(0)
     604           12 :       nstate_list(:) = HUGE(0)
     605              : 
     606              :       ! Build the state_list
     607            8 :       DO ispin = 1, dcdr_env%nspins
     608            4 :          center_array => localized_wfn_control%centers_set(ispin)%array
     609            4 :          nstate = 0
     610           20 :          DO istate = 1, SIZE(center_array, 2)
     611           16 :             nstate = nstate + 1
     612           20 :             state_list(nstate, ispin) = istate
     613              :          END DO
     614              :          nstate_list(ispin) = nstate
     615              : 
     616              :          ! clustering the states
     617            4 :          nstate = nstate_list(ispin)
     618            4 :          dcdr_env%nstates(ispin) = nstate
     619              : 
     620           12 :          ALLOCATE (dcdr_env%center_list(ispin)%array(2, nstate + 1))
     621           12 :          ALLOCATE (dcdr_env%centers_set(ispin)%array(3, nstate))
     622           64 :          dcdr_env%center_list(ispin)%array(:, :) = HUGE(0)
     623           68 :          dcdr_env%centers_set(ispin)%array(:, :) = HUGE(0.0_dp)
     624              : 
     625            4 :          center_array => localized_wfn_control%centers_set(ispin)%array
     626              : 
     627              :          ! point to the psi0 centers
     628            4 :          SELECT CASE (dcdr_env%orb_center)
     629              :          CASE (current_orb_center_wannier)
     630              :             ! use the wannier center as -center-
     631            4 :             dcdr_env%nbr_center(ispin) = nstate
     632           20 :             DO is = 1, nstate
     633           16 :                istate = state_list(is, 1)
     634           64 :                dcdr_env%centers_set(ispin)%array(1:3, is) = center_array(1:3, istate)
     635           16 :                dcdr_env%center_list(ispin)%array(1, is) = is
     636           20 :                dcdr_env%center_list(ispin)%array(2, is) = istate
     637              :             END DO
     638            4 :             dcdr_env%center_list(ispin)%array(1, nstate + 1) = nstate + 1
     639              : 
     640              :          CASE DEFAULT
     641            4 :             CPABORT("Unknown orbital center...")
     642              :          END SELECT
     643              :       END DO
     644              : 
     645            4 :       CALL timestop(handle)
     646           12 :    END SUBROUTINE get_loc_setting
     647              : 
     648              : ! **************************************************************************************************
     649              : !> \brief Initialize the dcdr environment
     650              : !> \param dcdr_env ...
     651              : !> \param qs_env ...
     652              : ! **************************************************************************************************
     653           24 :    SUBROUTINE dcdr_env_init(dcdr_env, qs_env)
     654              :       TYPE(dcdr_env_type)                                :: dcdr_env
     655              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     656              : 
     657              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'dcdr_env_init'
     658              : 
     659              :       INTEGER                                            :: handle, homo, i, isize, ispin, j, jg, &
     660              :                                                             n_rep, nao, natom, nmo, nspins, &
     661              :                                                             nsubset, output_unit, reference, &
     662              :                                                             unit_number
     663           24 :       INTEGER, DIMENSION(:), POINTER                     :: tmplist
     664              :       LOGICAL                                            :: explicit
     665           24 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: ref_point
     666              :       TYPE(cp_fm_type)                                   :: buf
     667              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     668              :       TYPE(cp_logger_type), POINTER                      :: logger
     669           24 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s
     670           24 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_p
     671              :       TYPE(dft_control_type), POINTER                    :: dft_control
     672           24 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     673           24 :       TYPE(molecule_type), DIMENSION(:), POINTER         :: molecule_set
     674              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     675              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     676           24 :          POINTER                                         :: sab_all, sab_orb
     677           24 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     678              :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
     679              :       TYPE(section_vals_type), POINTER                   :: dcdr_section, loc_section, lr_section
     680              : 
     681           24 :       CALL timeset(routineN, handle)
     682              : 
     683              :       ! Set up the logger
     684           24 :       NULLIFY (logger, loc_section, dcdr_section, lr_section)
     685           24 :       logger => cp_get_default_logger()
     686           24 :       loc_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%LINRES%LOCALIZE")
     687           24 :       dcdr_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%LINRES%DCDR")
     688              :       dcdr_env%output_unit = cp_print_key_unit_nr(logger, dcdr_section, "PRINT%APT", &
     689              :                                                   extension=".data", middle_name="dcdr", log_filename=.FALSE., &
     690           24 :                                                   file_position="REWIND", file_status="REPLACE")
     691              : 
     692           24 :       lr_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%LINRES")
     693              :       output_unit = cp_print_key_unit_nr(logger, lr_section, "PRINT%PROGRAM_RUN_INFO", &
     694           24 :                                          extension=".linresLog")
     695           24 :       unit_number = cp_print_key_unit_nr(logger, lr_section, "PRINT%PROGRAM_RUN_INFO", extension=".linresLog")
     696              : 
     697           24 :       IF (output_unit > 0) THEN
     698           12 :          WRITE (output_unit, "(/,T20,A,/)") "*** Start DCDR calculation ***"
     699              :       END IF
     700              : 
     701           24 :       NULLIFY (ks_env, dft_control, sab_orb, sab_all, particle_set, molecule_set, matrix_s, matrix_ks, mos, para_env)
     702              :       CALL get_qs_env(qs_env=qs_env, &
     703              :                       ks_env=ks_env, &
     704              :                       dft_control=dft_control, &
     705              :                       sab_orb=sab_orb, &
     706              :                       sab_all=sab_all, &
     707              :                       particle_set=particle_set, &
     708              :                       molecule_set=molecule_set, &
     709              :                       matrix_s=matrix_s, &
     710              :                       matrix_ks=matrix_ks, &
     711              :                       mos=mos, &
     712           24 :                       para_env=para_env)
     713              : 
     714           24 :       natom = SIZE(particle_set)
     715           24 :       nsubset = SIZE(molecule_set)
     716           24 :       nspins = dft_control%nspins
     717           24 :       dcdr_env%nspins = dft_control%nspins
     718              : 
     719           24 :       NULLIFY (dcdr_env%matrix_s)
     720              :       CALL build_overlap_matrix(ks_env, matrix_s=dcdr_env%matrix_s, &
     721              :                                 matrix_name="OVERLAP MATRIX", &
     722              :                                 nderivative=1, &
     723              :                                 basis_type_a="ORB", &
     724              :                                 basis_type_b="ORB", &
     725           24 :                                 sab_nl=sab_orb)
     726              : 
     727           24 :       NULLIFY (dcdr_env%matrix_t)
     728           24 :       NULLIFY (matrix_p)
     729              :       CALL kinetic_energy_matrix(qs_env, matrix_t=dcdr_env%matrix_t, matrix_p=matrix_p, &
     730              :                                  matrix_name="KINETIC ENERGY MATRIX", &
     731              :                                  calculate_forces=.FALSE., &
     732              :                                  basis_type="ORB", &
     733              :                                  sab_orb=sab_orb, &
     734              :                                  nderivative=1, &
     735           24 :                                  eps_filter=dft_control%qs_control%eps_filter_matrix)
     736              : 
     737              : !     CALL build_kinetic_matrix(ks_env, matrix_t=dcdr_env%matrix_t, &
     738              : !                               matrix_name="KINETIC ENERGY MATRIX", &
     739              : !                               basis_type="ORB", &
     740              : !                               sab_nl=sab_orb, nderivative=1, &
     741              : !                               eps_filter=dft_control%qs_control%eps_filter_matrix)
     742              : 
     743              :       ! Get inputs
     744           24 :       CALL section_vals_val_get(dcdr_section, "DISTRIBUTED_ORIGIN", l_val=dcdr_env%distributed_origin)
     745           24 :       CALL section_vals_val_get(loc_section, "_SECTION_PARAMETERS_", l_val=dcdr_env%localized_psi0)
     746           24 :       CALL section_vals_val_get(lr_section, "RESTART", l_val=qs_env%linres_control%linres_restart)
     747           24 :       CALL section_vals_val_get(dcdr_section, "Z_MATRIX_METHOD", l_val=dcdr_env%z_matrix_method)
     748              : 
     749           96 :       dcdr_env%ref_point = 0._dp
     750              : 
     751              :       ! List of atoms
     752           24 :       NULLIFY (tmplist)
     753           24 :       isize = 0
     754           24 :       CALL section_vals_val_get(dcdr_section, "LIST_OF_ATOMS", n_rep_val=n_rep)
     755           24 :       IF (n_rep == 0) THEN
     756           72 :          ALLOCATE (dcdr_env%list_of_atoms(natom))
     757           96 :          DO jg = 1, natom
     758           96 :             dcdr_env%list_of_atoms(jg) = jg
     759              :          END DO
     760              :       ELSE
     761            0 :          DO jg = 1, n_rep
     762            0 :             ALLOCATE (dcdr_env%list_of_atoms(isize))
     763            0 :             CALL section_vals_val_get(dcdr_section, "LIST_OF_ATOMS", i_rep_val=jg, i_vals=tmplist)
     764            0 :             CALL reallocate(dcdr_env%list_of_atoms, 1, isize + SIZE(tmplist))
     765            0 :             dcdr_env%list_of_atoms(isize + 1:isize + SIZE(tmplist)) = tmplist
     766            0 :             isize = SIZE(dcdr_env%list_of_atoms)
     767              :          END DO
     768              :       END IF
     769              : 
     770              :       ! Reference point
     771           24 :       IF (dcdr_env%localized_psi0) THEN
     772              :          ! Get the Wannier localized wave functions and centers
     773            4 :          CALL get_loc_setting(dcdr_env, qs_env)
     774              :       ELSE
     775              :          ! Get the reference point from the input
     776           20 :          CALL section_vals_val_get(dcdr_section, "REFERENCE", i_val=reference)
     777           20 :          CALL section_vals_val_get(dcdr_section, "REFERENCE_POINT", explicit=explicit)
     778           20 :          IF (explicit) THEN
     779            0 :             CALL section_vals_val_get(dcdr_section, "REFERENCE_POINT", r_vals=ref_point)
     780              :          ELSE
     781           20 :             IF (reference == use_mom_ref_user) &
     782            0 :                CPABORT("User-defined reference point should be given explicitly")
     783              :          END IF
     784              : 
     785              :          CALL get_reference_point(rpoint=dcdr_env%ref_point, qs_env=qs_env, &
     786              :                                   reference=reference, &
     787           20 :                                   ref_point=ref_point)
     788              :       END IF
     789              : 
     790              :       ! Helper matrix structs
     791              :       NULLIFY (dcdr_env%aoao_fm_struct, &
     792           24 :                dcdr_env%momo_fm_struct, &
     793           24 :                dcdr_env%likemos_fm_struct, &
     794           24 :                dcdr_env%homohomo_fm_struct)
     795              :       CALL get_mo_set(mo_set=mos(1), mo_coeff=mo_coeff, &
     796           24 :                       nao=nao, nmo=nmo, homo=homo)
     797              :       CALL cp_fm_struct_create(dcdr_env%aoao_fm_struct, nrow_global=nao, &
     798              :                                ncol_global=nao, para_env=para_env, &
     799           24 :                                context=mo_coeff%matrix_struct%context)
     800              :       CALL cp_fm_struct_create(dcdr_env%homohomo_fm_struct, nrow_global=homo, &
     801              :                                ncol_global=homo, para_env=para_env, &
     802           24 :                                context=mo_coeff%matrix_struct%context)
     803           24 :       dcdr_env%nao = nao
     804              : 
     805           72 :       ALLOCATE (dcdr_env%nmo(nspins))
     806          100 :       ALLOCATE (dcdr_env%momo_fm_struct(nspins))
     807           76 :       ALLOCATE (dcdr_env%likemos_fm_struct(nspins))
     808           52 :       DO ispin = 1, nspins
     809              :          CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff, &
     810           28 :                          nao=nao, nmo=nmo, homo=homo)
     811              :          CALL cp_fm_struct_create(dcdr_env%momo_fm_struct(ispin)%struct, nrow_global=nmo, &
     812              :                                   ncol_global=nmo, para_env=para_env, &
     813           28 :                                   context=mo_coeff%matrix_struct%context)
     814              :          CALL cp_fm_struct_create(dcdr_env%likemos_fm_struct(ispin)%struct, &
     815           28 :                                   template_fmstruct=mo_coeff%matrix_struct)
     816           80 :          dcdr_env%nmo(ispin) = nmo
     817              :       END DO
     818              : 
     819              :       ! Fields of reals
     820           72 :       ALLOCATE (dcdr_env%deltaR(3, natom))
     821           48 :       ALLOCATE (dcdr_env%delta_basis_function(3, natom))
     822           72 :       ALLOCATE (dcdr_env%apt_el_dcdr(3, 3, natom))
     823           48 :       ALLOCATE (dcdr_env%apt_nuc_dcdr(3, 3, natom))
     824           48 :       ALLOCATE (dcdr_env%apt_total_dcdr(3, 3, natom))
     825              : 
     826          960 :       dcdr_env%apt_el_dcdr = 0._dp
     827          960 :       dcdr_env%apt_nuc_dcdr = 0._dp
     828          960 :       dcdr_env%apt_total_dcdr = 0._dp
     829              : 
     830          312 :       dcdr_env%deltaR = 0.0_dp
     831          312 :       dcdr_env%delta_basis_function = 0._dp
     832              : 
     833              :       ! Localization
     834           24 :       IF (dcdr_env%localized_psi0) THEN
     835           16 :          ALLOCATE (dcdr_env%apt_el_dcdr_per_center(3, 3, natom, dcdr_env%nbr_center(1)))
     836           16 :          ALLOCATE (dcdr_env%apt_el_dcdr_per_subset(3, 3, natom, nsubset))
     837           12 :          ALLOCATE (dcdr_env%apt_subset(3, 3, natom, nsubset))
     838          644 :          dcdr_env%apt_el_dcdr_per_center = 0._dp
     839          484 :          dcdr_env%apt_el_dcdr_per_subset = 0._dp
     840          484 :          dcdr_env%apt_subset = 0.0_dp
     841              :       END IF
     842              : 
     843              :       ! Full matrices
     844          100 :       ALLOCATE (dcdr_env%mo_coeff(nspins))
     845           76 :       ALLOCATE (dcdr_env%dCR(nspins))
     846           76 :       ALLOCATE (dcdr_env%dCR_prime(nspins))
     847           76 :       ALLOCATE (dcdr_env%chc(nspins))
     848           76 :       ALLOCATE (dcdr_env%op_dR(nspins))
     849              : 
     850           52 :       DO ispin = 1, nspins
     851           28 :          CALL cp_fm_create(dcdr_env%dCR(ispin), dcdr_env%likemos_fm_struct(ispin)%struct, set_zero=.TRUE.)
     852           28 :          CALL cp_fm_create(dcdr_env%dCR_prime(ispin), dcdr_env%likemos_fm_struct(ispin)%struct, set_zero=.TRUE.)
     853           28 :          CALL cp_fm_create(dcdr_env%mo_coeff(ispin), dcdr_env%likemos_fm_struct(ispin)%struct, set_zero=.TRUE.)
     854           28 :          CALL cp_fm_create(dcdr_env%chc(ispin), dcdr_env%momo_fm_struct(ispin)%struct, set_zero=.TRUE.)
     855           28 :          CALL cp_fm_create(dcdr_env%op_dR(ispin), dcdr_env%likemos_fm_struct(ispin)%struct, set_zero=.TRUE.)
     856              : 
     857           28 :          CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
     858           52 :          CALL cp_fm_to_fm(mo_coeff, dcdr_env%mo_coeff(ispin))
     859              :       END DO
     860              : 
     861           24 :       IF (dcdr_env%z_matrix_method) THEN
     862           36 :          ALLOCATE (dcdr_env%matrix_m_alpha(3, nspins))
     863           16 :          DO i = 1, 3
     864           34 :             DO ispin = 1, nspins
     865           18 :                CALL cp_fm_create(dcdr_env%matrix_m_alpha(i, ispin), dcdr_env%likemos_fm_struct(1)%struct)
     866           30 :                CALL cp_fm_set_all(dcdr_env%matrix_m_alpha(i, ispin), 0.0_dp)
     867              :             END DO
     868              :          END DO
     869              :       END IF
     870              : 
     871              :       ! DBCSR matrices
     872           24 :       NULLIFY (dcdr_env%hamiltonian1)
     873           24 :       NULLIFY (dcdr_env%moments)
     874           24 :       NULLIFY (dcdr_env%matrix_difdip)
     875           24 :       NULLIFY (dcdr_env%matrix_core_charge_1)
     876           24 :       NULLIFY (dcdr_env%matrix_s1)
     877           24 :       NULLIFY (dcdr_env%matrix_t1)
     878           24 :       NULLIFY (dcdr_env%matrix_apply_op_constant)
     879           24 :       NULLIFY (dcdr_env%matrix_d_vhxc_dR)
     880           24 :       NULLIFY (dcdr_env%matrix_vhxc_perturbed_basis)
     881           24 :       NULLIFY (dcdr_env%matrix_hc)
     882           24 :       NULLIFY (dcdr_env%matrix_ppnl_1)
     883           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%perturbed_dm_correction, nspins)
     884           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%hamiltonian1, nspins)
     885           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%moments, 3)
     886           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%matrix_difdip, 3, 3)
     887           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%matrix_core_charge_1, 3)
     888           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%matrix_nosym_temp, 3)
     889           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%matrix_nosym_temp2, 3)
     890           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%matrix_s1, 4)
     891           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%matrix_t1, 4)
     892           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%matrix_apply_op_constant, nspins)
     893           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%matrix_d_vhxc_dR, 3, nspins)
     894           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%matrix_vhxc_perturbed_basis, nspins, 6)
     895           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%matrix_hc, 3)
     896           24 :       CALL dbcsr_allocate_matrix_set(dcdr_env%matrix_ppnl_1, 3)
     897              : 
     898              :       ! temporary no_symmetry matrix:
     899           96 :       DO i = 1, 3
     900           72 :          CALL dbcsr_init_p(dcdr_env%matrix_nosym_temp(i)%matrix)
     901              :          CALL dbcsr_create(dcdr_env%matrix_nosym_temp(i)%matrix, template=matrix_ks(1)%matrix, &
     902           72 :                            matrix_type=dbcsr_type_no_symmetry)
     903           72 :          CALL cp_dbcsr_alloc_block_from_nbl(dcdr_env%matrix_nosym_temp(i)%matrix, sab_all)
     904           72 :          CALL dbcsr_set(dcdr_env%matrix_nosym_temp(i)%matrix, 0._dp)
     905              : 
     906           72 :          CALL dbcsr_init_p(dcdr_env%matrix_nosym_temp2(i)%matrix)
     907              :          CALL dbcsr_create(dcdr_env%matrix_nosym_temp2(i)%matrix, template=matrix_ks(1)%matrix, &
     908           72 :                            matrix_type=dbcsr_type_no_symmetry)
     909           72 :          CALL cp_dbcsr_alloc_block_from_nbl(dcdr_env%matrix_nosym_temp2(i)%matrix, sab_all)
     910           96 :          CALL dbcsr_set(dcdr_env%matrix_nosym_temp2(i)%matrix, 0._dp)
     911              :       END DO
     912              : 
     913              :       ! moments carry the result of build_local_moment_matrix
     914           96 :       DO i = 1, 3
     915           72 :          CALL dbcsr_init_p(dcdr_env%moments(i)%matrix)
     916           72 :          CALL dbcsr_copy(dcdr_env%moments(i)%matrix, matrix_ks(1)%matrix, "dcdr_env%moments")
     917           96 :          CALL dbcsr_set(dcdr_env%moments(i)%matrix, 0.0_dp)
     918              :       END DO
     919           24 :       CALL build_local_moment_matrix(qs_env, dcdr_env%moments, 1, ref_point=[0._dp, 0._dp, 0._dp])
     920              : 
     921           96 :       DO i = 1, 3
     922          312 :          DO j = 1, 3
     923          216 :             CALL dbcsr_init_p(dcdr_env%matrix_difdip(i, j)%matrix)
     924          216 :             CALL dbcsr_copy(dcdr_env%matrix_difdip(i, j)%matrix, dcdr_env%matrix_nosym_temp(1)%matrix)
     925          288 :             CALL dbcsr_set(dcdr_env%matrix_difdip(i, j)%matrix, 0.0_dp)
     926              :          END DO
     927              :       END DO
     928              : 
     929           52 :       DO ispin = 1, nspins
     930           28 :          CALL dbcsr_init_p(dcdr_env%hamiltonian1(ispin)%matrix)
     931           28 :          CALL dbcsr_init_p(dcdr_env%perturbed_dm_correction(ispin)%matrix)
     932           28 :          CALL dbcsr_init_p(dcdr_env%matrix_apply_op_constant(ispin)%matrix)
     933           28 :          CALL dbcsr_copy(dcdr_env%matrix_apply_op_constant(ispin)%matrix, matrix_ks(1)%matrix)
     934           52 :          CALL dbcsr_copy(dcdr_env%perturbed_dm_correction(ispin)%matrix, matrix_ks(1)%matrix)
     935              :       END DO
     936              : 
     937              :       ! overlap/kinetic matrix: s(1)    normal overlap matrix;
     938              :       !                         s(2:4)  derivatives wrt. nuclear coordinates
     939           24 :       CALL dbcsr_init_p(dcdr_env%matrix_s1(1)%matrix)
     940           24 :       CALL dbcsr_init_p(dcdr_env%matrix_t1(1)%matrix)
     941              : 
     942           24 :       CALL dbcsr_copy(dcdr_env%matrix_s1(1)%matrix, matrix_s(1)%matrix)
     943           24 :       CALL dbcsr_copy(dcdr_env%matrix_t1(1)%matrix, dcdr_env%matrix_t(1)%matrix)
     944              : 
     945           96 :       DO i = 2, 4
     946           72 :          CALL dbcsr_init_p(dcdr_env%matrix_s1(i)%matrix)
     947           72 :          CALL dbcsr_copy(dcdr_env%matrix_s1(i)%matrix, dcdr_env%matrix_nosym_temp(1)%matrix)
     948              : 
     949           72 :          CALL dbcsr_init_p(dcdr_env%matrix_t1(i)%matrix)
     950           96 :          CALL dbcsr_copy(dcdr_env%matrix_t1(i)%matrix, dcdr_env%matrix_nosym_temp(1)%matrix)
     951              :       END DO
     952              : 
     953              :       ! j=1...3: derivative wrt nucleus A, 4...6: wrt nucleus B
     954           52 :       DO ispin = 1, nspins
     955          220 :          DO j = 1, 6
     956          168 :             CALL dbcsr_init_p(dcdr_env%matrix_vhxc_perturbed_basis(ispin, j)%matrix)
     957          196 :             CALL dbcsr_copy(dcdr_env%matrix_vhxc_perturbed_basis(ispin, j)%matrix, dcdr_env%matrix_s1(1)%matrix)
     958              :          END DO
     959              :       END DO
     960              : 
     961           96 :       DO i = 1, 3
     962           72 :          CALL dbcsr_init_p(dcdr_env%matrix_hc(i)%matrix)
     963              :          CALL dbcsr_create(dcdr_env%matrix_hc(i)%matrix, template=matrix_ks(1)%matrix, &
     964           72 :                            matrix_type=dbcsr_type_symmetric)
     965           72 :          CALL cp_dbcsr_alloc_block_from_nbl(dcdr_env%matrix_hc(i)%matrix, sab_orb)
     966           96 :          CALL dbcsr_set(dcdr_env%matrix_hc(i)%matrix, 0.0_dp)
     967              :       END DO
     968              : 
     969           96 :       DO i = 1, 3
     970           72 :          CALL dbcsr_init_p(dcdr_env%matrix_ppnl_1(i)%matrix)
     971              :          CALL dbcsr_create(dcdr_env%matrix_ppnl_1(i)%matrix, template=matrix_ks(1)%matrix, &
     972           72 :                            matrix_type=dbcsr_type_symmetric)
     973           72 :          CALL cp_dbcsr_alloc_block_from_nbl(dcdr_env%matrix_ppnl_1(i)%matrix, sab_orb)
     974           96 :          CALL dbcsr_set(dcdr_env%matrix_ppnl_1(i)%matrix, 0.0_dp)
     975              :       END DO
     976              : 
     977           96 :       DO i = 1, 3
     978          156 :          DO ispin = 1, nspins
     979           84 :             CALL dbcsr_init_p(dcdr_env%matrix_d_vhxc_dR(i, ispin)%matrix)
     980          156 :             CALL dbcsr_copy(dcdr_env%matrix_d_vhxc_dR(i, ispin)%matrix, dcdr_env%matrix_s1(1)%matrix)
     981              :          END DO
     982              : 
     983           72 :          CALL dbcsr_init_p(dcdr_env%matrix_core_charge_1(i)%matrix)
     984           72 :          CALL dbcsr_copy(dcdr_env%matrix_core_charge_1(i)%matrix, dcdr_env%matrix_s1(1)%matrix)
     985           96 :          CALL dbcsr_set(dcdr_env%matrix_core_charge_1(i)%matrix, 0.0_dp)
     986              :       END DO
     987              : 
     988              :       ! CHC
     989           52 :       DO ispin = 1, nspins
     990           28 :          CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff, nao=nao, nmo=nmo)
     991           28 :          CALL cp_fm_create(buf, dcdr_env%likemos_fm_struct(ispin)%struct)
     992              : 
     993           28 :          CALL cp_dbcsr_sm_fm_multiply(matrix_ks(ispin)%matrix, mo_coeff, buf, nmo)
     994              :          ! chc = mo * matrix_ks * mo
     995              :          CALL parallel_gemm('T', 'N', nmo, nmo, nao, &
     996              :                             1.0_dp, mo_coeff, buf, &
     997           28 :                             0.0_dp, dcdr_env%chc(ispin))
     998              : 
     999           80 :          CALL cp_fm_release(buf)
    1000              :       END DO
    1001              : 
    1002              :       CALL cp_print_key_finished_output(output_unit, logger, lr_section, &
    1003           24 :                                         "PRINT%PROGRAM_RUN_INFO")
    1004              : 
    1005           24 :       CALL timestop(handle)
    1006           72 :    END SUBROUTINE dcdr_env_init
    1007              : 
    1008              : ! **************************************************************************************************
    1009              : !> \brief Deallocate the dcdr environment
    1010              : !> \param qs_env ...
    1011              : !> \param dcdr_env ...
    1012              : ! **************************************************************************************************
    1013           24 :    SUBROUTINE dcdr_env_cleanup(qs_env, dcdr_env)
    1014              : 
    1015              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1016              :       TYPE(dcdr_env_type)                                :: dcdr_env
    1017              : 
    1018              :       INTEGER                                            :: ispin
    1019              :       TYPE(cp_logger_type), POINTER                      :: logger
    1020              :       TYPE(section_vals_type), POINTER                   :: dcdr_section
    1021              : 
    1022              :       ! Destroy the logger
    1023           24 :       logger => cp_get_default_logger()
    1024           24 :       dcdr_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%LINRES%DCDR")
    1025           24 :       CALL cp_print_key_finished_output(dcdr_env%output_unit, logger, dcdr_section, "PRINT%APT")
    1026              : 
    1027           24 :       DEALLOCATE (dcdr_env%list_of_atoms)
    1028              : 
    1029           24 :       CALL cp_fm_struct_release(dcdr_env%aoao_fm_struct)
    1030           24 :       CALL cp_fm_struct_release(dcdr_env%homohomo_fm_struct)
    1031           52 :       DO ispin = 1, dcdr_env%nspins
    1032           28 :          CALL cp_fm_struct_release(dcdr_env%momo_fm_struct(ispin)%struct)
    1033           52 :          CALL cp_fm_struct_release(dcdr_env%likemos_fm_struct(ispin)%struct)
    1034              :       END DO
    1035           24 :       DEALLOCATE (dcdr_env%momo_fm_struct)
    1036           24 :       DEALLOCATE (dcdr_env%likemos_fm_struct)
    1037              : 
    1038           24 :       DEALLOCATE (dcdr_env%deltar)
    1039           24 :       DEALLOCATE (dcdr_env%delta_basis_function)
    1040              : 
    1041           24 :       IF (dcdr_env%localized_psi0) THEN
    1042              :          ! DEALLOCATE (dcdr_env%psi0_order)
    1043            4 :          DEALLOCATE (dcdr_env%centers_set(1)%array)
    1044            4 :          DEALLOCATE (dcdr_env%center_list(1)%array)
    1045            4 :          DEALLOCATE (dcdr_env%centers_set)
    1046            4 :          DEALLOCATE (dcdr_env%center_list)
    1047            4 :          DEALLOCATE (dcdr_env%apt_subset)
    1048              :       END IF
    1049              : 
    1050           24 :       DEALLOCATE (dcdr_env%apt_el_dcdr)
    1051           24 :       DEALLOCATE (dcdr_env%apt_nuc_dcdr)
    1052           24 :       DEALLOCATE (dcdr_env%apt_total_dcdr)
    1053           24 :       IF (dcdr_env%localized_psi0) THEN
    1054            4 :          DEALLOCATE (dcdr_env%apt_el_dcdr_per_center)
    1055            4 :          DEALLOCATE (dcdr_env%apt_el_dcdr_per_subset)
    1056              :       END IF
    1057              : 
    1058              :       ! Full matrices
    1059           24 :       CALL cp_fm_release(dcdr_env%dCR)
    1060           24 :       CALL cp_fm_release(dcdr_env%dCR_prime)
    1061           24 :       CALL cp_fm_release(dcdr_env%mo_coeff)
    1062           24 :       CALL cp_fm_release(dcdr_env%chc)
    1063           24 :       CALL cp_fm_release(dcdr_env%op_dR)
    1064              : 
    1065           24 :       IF (dcdr_env%z_matrix_method) THEN
    1066            4 :          CALL cp_fm_release(dcdr_env%matrix_m_alpha)
    1067              :       END IF
    1068              : 
    1069              :       ! DBCSR matrices
    1070           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%perturbed_dm_correction)
    1071           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%hamiltonian1)
    1072           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%moments)
    1073           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%matrix_difdip)
    1074           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%matrix_core_charge_1)
    1075           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%matrix_nosym_temp)
    1076           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%matrix_nosym_temp2)
    1077           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%matrix_s)
    1078           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%matrix_t)
    1079           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%matrix_s1)
    1080           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%matrix_t1)
    1081           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%matrix_apply_op_constant)
    1082           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%matrix_d_vhxc_dR)
    1083           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%matrix_vhxc_perturbed_basis)
    1084           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%matrix_hc)
    1085           24 :       CALL dbcsr_deallocate_matrix_set(dcdr_env%matrix_ppnl_1)
    1086              : 
    1087           24 :    END SUBROUTINE dcdr_env_cleanup
    1088              : 
    1089              : END MODULE qs_dcdr_utils
        

Generated by: LCOV version 2.0-1