LCOV - code coverage report
Current view: top level - src - qs_moments.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:ca6acae) Lines: 87.6 % 1722 1509
Test Date: 2026-01-02 06:29:53 Functions: 94.7 % 19 18

            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 Calculates the moment integrals <a|r^m|b> and <a|r x d/dr|b>
      10              : !> \par History
      11              : !>      added angular moments (JGH 11.2012)
      12              : !> \author JGH (20.07.2006)
      13              : ! **************************************************************************************************
      14              : MODULE qs_moments
      15              :    USE ai_angmom, ONLY: angmom
      16              :    USE ai_moments, ONLY: contract_cossin, &
      17              :                          cossin, &
      18              :                          diff_momop, &
      19              :                          diff_momop2, &
      20              :                          diff_momop_velocity, &
      21              :                          moment
      22              :    USE atomic_kind_types, ONLY: atomic_kind_type, &
      23              :                                 get_atomic_kind
      24              :    USE basis_set_types, ONLY: gto_basis_set_p_type, &
      25              :                               gto_basis_set_type
      26              :    USE bibliography, ONLY: Mattiat2019, &
      27              :                            cite_reference
      28              :    USE block_p_types, ONLY: block_p_type
      29              :    USE cell_types, ONLY: cell_type, &
      30              :                          pbc, &
      31              :                          get_cell
      32              :    USE commutator_rpnl, ONLY: build_com_mom_nl
      33              :    USE cp_cfm_basic_linalg, ONLY: cp_cfm_det
      34              :    USE cp_cfm_types, ONLY: cp_cfm_create, &
      35              :                            cp_cfm_get_info, &
      36              :                            cp_cfm_release, &
      37              :                            cp_cfm_type
      38              :    USE cp_control_types, ONLY: dft_control_type
      39              :    USE cp_dbcsr_api, ONLY: &
      40              :       dbcsr_copy, dbcsr_create, dbcsr_deallocate_matrix, dbcsr_distribution_type, &
      41              :       dbcsr_get_block_p, dbcsr_init_p, dbcsr_multiply, dbcsr_p_type, dbcsr_set, dbcsr_type, &
      42              :       dbcsr_type_antisymmetric, dbcsr_type_no_symmetry, dbcsr_type_symmetric
      43              :    USE cp_dbcsr_contrib, ONLY: dbcsr_dot, &
      44              :                                dbcsr_trace
      45              :    USE cp_dbcsr_cp2k_link, ONLY: cp_dbcsr_alloc_block_from_nbl
      46              :    USE cp_dbcsr_operations, ONLY: cp_dbcsr_sm_fm_multiply, &
      47              :                                   dbcsr_allocate_matrix_set, &
      48              :                                   dbcsr_deallocate_matrix_set
      49              :    USE cp_fm_struct, ONLY: cp_fm_struct_create, &
      50              :                            cp_fm_struct_double, &
      51              :                            cp_fm_struct_release, &
      52              :                            cp_fm_struct_type
      53              :    USE cp_fm_types, ONLY: cp_fm_create, &
      54              :                           cp_fm_get_info, &
      55              :                           cp_fm_release, &
      56              :                           cp_fm_set_all, &
      57              :                           cp_fm_type
      58              :    USE cp_result_methods, ONLY: cp_results_erase, &
      59              :                                 put_results
      60              :    USE cp_result_types, ONLY: cp_result_type
      61              :    USE distribution_1d_types, ONLY: distribution_1d_type
      62              :    USE kinds, ONLY: default_string_length, &
      63              :                     dp, &
      64              :                     max_line_length
      65              :    USE kpoint_k_r_trafo_simple, ONLY: replicate_rs_matrices, &
      66              :                                       rs_to_kp
      67              :    USE kpoint_methods, ONLY: kpoint_init_cell_index, &
      68              :                              kpoint_initialize
      69              :    USE kpoint_types, ONLY: get_kpoint_info, &
      70              :                            kpoint_type, &
      71              :                            kpoint_create, &
      72              :                            kpoint_release, &
      73              :                            read_kpoint_section
      74              :    USE mathconstants, ONLY: pi, &
      75              :                             twopi, &
      76              :                             gaussi, &
      77              :                             z_zero
      78              :    USE message_passing, ONLY: mp_para_env_type
      79              :    USE moments_utils, ONLY: get_reference_point
      80              :    USE orbital_pointers, ONLY: current_maxl, &
      81              :                                indco, &
      82              :                                ncoset
      83              :    USE parallel_gemm_api, ONLY: parallel_gemm
      84              :    USE particle_methods, ONLY: get_particle_set
      85              :    USE particle_types, ONLY: particle_type
      86              :    USE physcon, ONLY: bohr, &
      87              :                       debye, &
      88              :                       angstrom
      89              :    USE qs_environment_types, ONLY: get_qs_env, &
      90              :                                    qs_environment_type
      91              :    USE qs_kind_types, ONLY: get_qs_kind, &
      92              :                             get_qs_kind_set, &
      93              :                             qs_kind_type
      94              :    USE qs_ks_types, ONLY: get_ks_env, &
      95              :                           qs_ks_env_type
      96              :    USE qs_mo_types, ONLY: get_mo_set, &
      97              :                           mo_set_type
      98              :    USE qs_neighbor_list_types, ONLY: get_iterator_info, &
      99              :                                      neighbor_list_iterate, &
     100              :                                      neighbor_list_iterator_create, &
     101              :                                      neighbor_list_iterator_p_type, &
     102              :                                      neighbor_list_iterator_release, &
     103              :                                      neighbor_list_set_p_type
     104              :    USE qs_operators_ao, ONLY: build_lin_mom_matrix
     105              :    USE qs_rho_types, ONLY: qs_rho_get, &
     106              :                            qs_rho_type
     107              :    USE rt_propagation_types, ONLY: get_rtp, &
     108              :                                    rt_prop_type
     109              :    USE cp_parser_methods, ONLY: read_float_object
     110              :    USE input_section_types, ONLY: section_vals_get, &
     111              :                                   section_vals_get_subs_vals, &
     112              :                                   section_vals_type, &
     113              :                                   section_vals_val_get
     114              :    USE mathlib, ONLY: geeig_right, &
     115              :                       gemm_square
     116              :    USE string_utilities, ONLY: uppercase
     117              : 
     118              : #include "./base/base_uses.f90"
     119              : 
     120              :    IMPLICIT NONE
     121              : 
     122              :    PRIVATE
     123              : 
     124              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_moments'
     125              : 
     126              :    ! Public subroutines
     127              :    PUBLIC :: build_berry_moment_matrix, build_local_moment_matrix
     128              :    PUBLIC :: build_berry_kpoint_matrix, build_local_magmom_matrix
     129              :    PUBLIC :: qs_moment_berry_phase, qs_moment_locop
     130              :    PUBLIC :: qs_moment_kpoints, build_local_moment_matrix_rs_img
     131              :    PUBLIC :: dipole_deriv_ao
     132              :    PUBLIC :: build_local_moments_der_matrix
     133              :    PUBLIC :: build_dsdv_moments
     134              :    PUBLIC :: dipole_velocity_deriv
     135              : 
     136              : CONTAINS
     137              : 
     138              : ! *****************************************************************************
     139              : !> \brief This returns the derivative of the moment integrals [a|\mu|b], with respect
     140              : !>        to the basis function on the right
     141              : !>        difdip(beta, alpha) = < mu | r_beta | ∂_alpha nu >  * (mu - nu)
     142              : !> \param qs_env ...
     143              : !> \param difdip ...
     144              : !> \param order The order of the derivative (1 for dipole moment)
     145              : !> \param lambda The atom on which we take the derivative
     146              : !> \param rc ...
     147              : !> \author Edward Ditler
     148              : ! **************************************************************************************************
     149            6 :    SUBROUTINE dipole_velocity_deriv(qs_env, difdip, order, lambda, rc)
     150              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     151              :       TYPE(dbcsr_p_type), DIMENSION(:, :), INTENT(INOUT) :: difdip
     152              :       INTEGER, INTENT(IN)                                :: order, lambda
     153              :       REAL(KIND=dp), DIMENSION(3)                        :: rc
     154              : 
     155              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dipole_velocity_deriv'
     156              : 
     157              :       INTEGER :: handle, i, iatom, icol, idir, ikind, inode, irow, iset, j, jatom, jkind, jset, &
     158              :                  last_jatom, lda, ldab, ldb, M_dim, maxsgf, natom, ncoa, ncob, nkind, nseta, nsetb, sgfa, &
     159              :                  sgfb
     160              :       LOGICAL                                            :: found
     161              :       REAL(dp)                                           :: dab
     162              :       REAL(dp), DIMENSION(3)                             :: ra, rab, rac, rb, rbc
     163            6 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: work
     164            6 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: mab
     165            6 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :, :)  :: difmab, difmab2
     166            6 :       TYPE(block_p_type), ALLOCATABLE, DIMENSION(:, :)   :: mint, mint2
     167              :       TYPE(cell_type), POINTER                           :: cell
     168            6 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
     169              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set_a, basis_set_b
     170              :       TYPE(neighbor_list_iterator_p_type), &
     171            6 :          DIMENSION(:), POINTER                           :: nl_iterator
     172              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     173            6 :          POINTER                                         :: sab_all
     174            6 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     175            6 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     176              :       TYPE(qs_kind_type), POINTER                        :: qs_kind
     177              : 
     178            6 :       CALL timeset(routineN, handle)
     179              : 
     180            6 :       NULLIFY (cell, particle_set, qs_kind_set, sab_all)
     181              :       CALL get_qs_env(qs_env, cell=cell, particle_set=particle_set, &
     182            6 :                       qs_kind_set=qs_kind_set, sab_all=sab_all)
     183              :       CALL get_qs_kind_set(qs_kind_set=qs_kind_set, &
     184            6 :                            maxco=ldab, maxsgf=maxsgf)
     185              : 
     186            6 :       nkind = SIZE(qs_kind_set)
     187            6 :       natom = SIZE(particle_set)
     188              : 
     189            6 :       M_dim = ncoset(order) - 1
     190              : 
     191           30 :       ALLOCATE (basis_set_list(nkind))
     192              : 
     193           30 :       ALLOCATE (mab(ldab, ldab, M_dim))
     194           36 :       ALLOCATE (difmab2(ldab, ldab, M_dim, 3))
     195           24 :       ALLOCATE (work(ldab, maxsgf))
     196           78 :       ALLOCATE (mint(3, 3))
     197           78 :       ALLOCATE (mint2(3, 3))
     198              : 
     199         4920 :       mab(1:ldab, 1:ldab, 1:M_dim) = 0.0_dp
     200        14766 :       difmab2(1:ldab, 1:ldab, 1:M_dim, 1:3) = 0.0_dp
     201          414 :       work(1:ldab, 1:maxsgf) = 0.0_dp
     202              : 
     203           24 :       DO i = 1, 3
     204           78 :       DO j = 1, 3
     205           54 :          NULLIFY (mint(i, j)%block)
     206           72 :          NULLIFY (mint2(i, j)%block)
     207              :       END DO
     208              :       END DO
     209              : 
     210              :       ! Set the basis_set_list(nkind) to point to the corresponding basis sets
     211           18 :       DO ikind = 1, nkind
     212           12 :          qs_kind => qs_kind_set(ikind)
     213           12 :          CALL get_qs_kind(qs_kind=qs_kind, basis_set=basis_set_a)
     214           18 :          IF (ASSOCIATED(basis_set_a)) THEN
     215           12 :             basis_set_list(ikind)%gto_basis_set => basis_set_a
     216              :          ELSE
     217            0 :             NULLIFY (basis_set_list(ikind)%gto_basis_set)
     218              :          END IF
     219              :       END DO
     220              : 
     221            6 :       CALL neighbor_list_iterator_create(nl_iterator, sab_all)
     222           33 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
     223              :          CALL get_iterator_info(nl_iterator, ikind=ikind, jkind=jkind, inode=inode, &
     224           27 :                                 iatom=iatom, jatom=jatom, r=rab)
     225              : 
     226           27 :          basis_set_a => basis_set_list(ikind)%gto_basis_set
     227           27 :          basis_set_b => basis_set_list(jkind)%gto_basis_set
     228           27 :          IF (.NOT. ASSOCIATED(basis_set_a)) CYCLE
     229           27 :          IF (.NOT. ASSOCIATED(basis_set_b)) CYCLE
     230              : 
     231              :          ASSOCIATE ( &
     232              :             ! basis ikind
     233              :             first_sgfa => basis_set_a%first_sgf, &
     234              :             la_max => basis_set_a%lmax, &
     235              :             la_min => basis_set_a%lmin, &
     236              :             npgfa => basis_set_a%npgf, &
     237              :             nsgfa => basis_set_a%nsgf_set, &
     238              :             rpgfa => basis_set_a%pgf_radius, &
     239              :             set_radius_a => basis_set_a%set_radius, &
     240              :             sphi_a => basis_set_a%sphi, &
     241              :             zeta => basis_set_a%zet, &
     242              :             ! basis jkind, &
     243              :             first_sgfb => basis_set_b%first_sgf, &
     244              :             lb_max => basis_set_b%lmax, &
     245              :             lb_min => basis_set_b%lmin, &
     246              :             npgfb => basis_set_b%npgf, &
     247              :             nsgfb => basis_set_b%nsgf_set, &
     248              :             rpgfb => basis_set_b%pgf_radius, &
     249              :             set_radius_b => basis_set_b%set_radius, &
     250              :             sphi_b => basis_set_b%sphi, &
     251              :             zetb => basis_set_b%zet)
     252              : 
     253           27 :             nseta = basis_set_a%nset
     254           27 :             nsetb = basis_set_b%nset
     255              : 
     256           18 :             IF (inode == 1) last_jatom = 0
     257              : 
     258              :             ! this guarantees minimum image convention
     259              :             ! anything else would not make sense
     260           27 :             IF (jatom == last_jatom) THEN
     261              :                CYCLE
     262              :             END IF
     263              : 
     264           27 :             last_jatom = jatom
     265              : 
     266           27 :             irow = iatom
     267           27 :             icol = jatom
     268              : 
     269          108 :             DO i = 1, 3
     270          351 :             DO j = 1, 3
     271          243 :                NULLIFY (mint(i, j)%block)
     272              :                CALL dbcsr_get_block_p(matrix=difdip(i, j)%matrix, &
     273              :                                       row=irow, col=icol, BLOCK=mint(i, j)%block, &
     274          243 :                                       found=found)
     275          243 :                CPASSERT(found)
     276         2025 :                mint(i, j)%block = 0._dp
     277              :             END DO
     278              :             END DO
     279              : 
     280              :             ! With and without MIC, rab(:) is the vector giving us the coordinates of rb.
     281           27 :             ra = pbc(particle_set(iatom)%r(:), cell)
     282          108 :             rb(:) = ra(:) + rab(:)
     283           27 :             rac = pbc(rc, ra, cell)
     284          108 :             rbc = rac + rab
     285          108 :             dab = norm2(rab)
     286              : 
     287           81 :             DO iset = 1, nseta
     288           27 :                ncoa = npgfa(iset)*ncoset(la_max(iset))
     289           27 :                sgfa = first_sgfa(1, iset)
     290           81 :                DO jset = 1, nsetb
     291           27 :                   IF (set_radius_a(iset) + set_radius_b(jset) < dab) CYCLE
     292           27 :                   ncob = npgfb(jset)*ncoset(lb_max(jset))
     293           27 :                   sgfb = first_sgfb(1, jset)
     294           27 :                   ldab = MAX(ncoa, ncob)
     295           27 :                   lda = ncoset(la_max(iset))*npgfa(iset)
     296           27 :                   ldb = ncoset(lb_max(jset))*npgfb(jset)
     297          162 :                   ALLOCATE (difmab(lda, ldb, M_dim, 3))
     298              : 
     299              :                   ! Calculate integral difmab(beta, alpha) = (a|r_beta|db_alpha)
     300              :                   ! difmab(beta, alpha) = < a | r_beta | ∂_alpha b >
     301              :                   ! difmab(j, idir) = < a | r_j | ∂_idir b >
     302              :                   CALL diff_momop_velocity(la_max(iset), npgfa(iset), zeta(:, iset), &
     303              :                                            rpgfa(:, iset), la_min(iset), lb_max(jset), npgfb(jset), &
     304              :                                            zetb(:, jset), rpgfb(:, jset), lb_min(jset), order, rac, rbc, &
     305           27 :                                            difmab, lambda=lambda, iatom=iatom, jatom=jatom)
     306              : 
     307              :                   !                  *** Contraction step ***
     308              : 
     309          108 :                   DO idir = 1, 3 ! derivative of AO function
     310          351 :                   DO j = 1, 3     ! position operator r_j
     311              :                      CALL dgemm("N", "N", ncoa, nsgfb(jset), ncob, &
     312              :                                 1.0_dp, difmab(1, 1, j, idir), SIZE(difmab, 1), &
     313              :                                 sphi_b(1, sgfb), SIZE(sphi_b, 1), &
     314          243 :                                 0.0_dp, work(1, 1), SIZE(work, 1))
     315              : 
     316              :                      CALL dgemm("T", "N", nsgfa(iset), nsgfb(jset), ncoa, &
     317              :                                 1.0_dp, sphi_a(1, sgfa), SIZE(sphi_a, 1), &
     318              :                                 work(1, 1), SIZE(work, 1), &
     319              :                                 1.0_dp, mint(j, idir)%block(sgfa, sgfb), &
     320          324 :                                 SIZE(mint(j, idir)%block, 1))
     321              :                   END DO !j
     322              :                   END DO !idir
     323           54 :                   DEALLOCATE (difmab)
     324              :                END DO !jset
     325              :             END DO !iset
     326              :          END ASSOCIATE
     327              :       END DO!iterator
     328              : 
     329            6 :       CALL neighbor_list_iterator_release(nl_iterator)
     330              : 
     331           24 :       DO i = 1, 3
     332           78 :       DO j = 1, 3
     333           72 :          NULLIFY (mint(i, j)%block)
     334              :       END DO
     335              :       END DO
     336              : 
     337            6 :       DEALLOCATE (mab, difmab2, basis_set_list, work, mint, mint2)
     338              : 
     339            6 :       CALL timestop(handle)
     340           18 :    END SUBROUTINE dipole_velocity_deriv
     341              : 
     342              : ! **************************************************************************************************
     343              : !> \brief Builds the moments for the derivative of the overlap with respect to nuclear velocities
     344              : !> \param qs_env ...
     345              : !> \param moments ...
     346              : !> \param nmoments ...
     347              : !> \param ref_point ...
     348              : !> \param ref_points ...
     349              : !> \param basis_type ...
     350              : !> \author Edward Ditler
     351              : ! **************************************************************************************************
     352            6 :    SUBROUTINE build_dsdv_moments(qs_env, moments, nmoments, ref_point, ref_points, basis_type)
     353              : 
     354              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     355              :       TYPE(dbcsr_p_type), DIMENSION(:)                   :: moments
     356              :       INTEGER, INTENT(IN)                                :: nmoments
     357              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: ref_point
     358              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
     359              :          OPTIONAL                                        :: ref_points
     360              :       CHARACTER(len=*), OPTIONAL                         :: basis_type
     361              : 
     362              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_dsdv_moments'
     363              : 
     364              :       INTEGER :: handle, i, iatom, icol, ikind, inode, irow, iset, jatom, jkind, jset, last_jatom, &
     365              :                  maxco, maxsgf, natom, ncoa, ncob, nkind, nm, nseta, nsetb, sgfa, sgfb
     366              :       INTEGER, DIMENSION(3)                              :: image_cell
     367              :       LOGICAL                                            :: found
     368              :       REAL(KIND=dp)                                      :: dab
     369            6 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: work
     370            6 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: mab
     371              :       REAL(KIND=dp), DIMENSION(3)                        :: ra, rab, rac, rb, rbc, rc
     372            6 :       TYPE(block_p_type), ALLOCATABLE, DIMENSION(:)      :: mint
     373              :       TYPE(cell_type), POINTER                           :: cell
     374            6 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
     375              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set_a, basis_set_b
     376              :       TYPE(neighbor_list_iterator_p_type), &
     377            6 :          DIMENSION(:), POINTER                           :: nl_iterator
     378              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     379            6 :          POINTER                                         :: sab_orb
     380            6 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     381            6 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     382              :       TYPE(qs_kind_type), POINTER                        :: qs_kind
     383              : 
     384            6 :       IF (nmoments < 1) RETURN
     385              : 
     386            6 :       CALL timeset(routineN, handle)
     387              : 
     388            6 :       NULLIFY (qs_kind_set, cell, particle_set, sab_orb)
     389              : 
     390            6 :       nm = (6 + 11*nmoments + 6*nmoments**2 + nmoments**3)/6 - 1
     391            6 :       CPASSERT(SIZE(moments) >= nm)
     392              : 
     393            6 :       NULLIFY (qs_kind_set, particle_set, sab_orb, cell)
     394              :       CALL get_qs_env(qs_env=qs_env, &
     395              :                       qs_kind_set=qs_kind_set, &
     396              :                       particle_set=particle_set, cell=cell, &
     397            6 :                       sab_orb=sab_orb)
     398              : 
     399            6 :       nkind = SIZE(qs_kind_set)
     400            6 :       natom = SIZE(particle_set)
     401              : 
     402              :       ! Allocate work storage
     403              :       CALL get_qs_kind_set(qs_kind_set=qs_kind_set, &
     404              :                            maxco=maxco, maxsgf=maxsgf, &
     405           12 :                            basis_type=basis_type)
     406              : 
     407           30 :       ALLOCATE (mab(maxco, maxco, nm))
     408         4920 :       mab(:, :, :) = 0.0_dp
     409              : 
     410           24 :       ALLOCATE (work(maxco, maxsgf))
     411          414 :       work(:, :) = 0.0_dp
     412              : 
     413           36 :       ALLOCATE (mint(nm))
     414           24 :       DO i = 1, nm
     415           24 :          NULLIFY (mint(i)%block)
     416              :       END DO
     417              : 
     418           30 :       ALLOCATE (basis_set_list(nkind))
     419           18 :       DO ikind = 1, nkind
     420           12 :          qs_kind => qs_kind_set(ikind)
     421           12 :          CALL get_qs_kind(qs_kind=qs_kind, basis_set=basis_set_a, basis_type=basis_type)
     422           18 :          IF (ASSOCIATED(basis_set_a)) THEN
     423           12 :             basis_set_list(ikind)%gto_basis_set => basis_set_a
     424              :          ELSE
     425            0 :             NULLIFY (basis_set_list(ikind)%gto_basis_set)
     426              :          END IF
     427              :       END DO
     428            6 :       CALL neighbor_list_iterator_create(nl_iterator, sab_orb)
     429           24 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
     430              :          CALL get_iterator_info(nl_iterator, ikind=ikind, jkind=jkind, inode=inode, &
     431           18 :                                 iatom=iatom, jatom=jatom, r=rab, cell=image_cell)
     432           18 :          basis_set_a => basis_set_list(ikind)%gto_basis_set
     433           18 :          IF (.NOT. ASSOCIATED(basis_set_a)) CYCLE
     434           18 :          basis_set_b => basis_set_list(jkind)%gto_basis_set
     435           18 :          IF (.NOT. ASSOCIATED(basis_set_b)) CYCLE
     436              :          ! basis ikind
     437              :          ASSOCIATE ( &
     438              :             first_sgfa => basis_set_a%first_sgf, &
     439              :             la_max => basis_set_a%lmax, &
     440              :             la_min => basis_set_a%lmin, &
     441              :             npgfa => basis_set_a%npgf, &
     442              :             nsgfa => basis_set_a%nsgf_set, &
     443              :             rpgfa => basis_set_a%pgf_radius, &
     444              :             set_radius_a => basis_set_a%set_radius, &
     445              :             sphi_a => basis_set_a%sphi, &
     446              :             zeta => basis_set_a%zet, &
     447              :             ! basis jkind, &
     448              :             first_sgfb => basis_set_b%first_sgf, &
     449              :             lb_max => basis_set_b%lmax, &
     450              :             lb_min => basis_set_b%lmin, &
     451              :             npgfb => basis_set_b%npgf, &
     452              :             nsgfb => basis_set_b%nsgf_set, &
     453              :             rpgfb => basis_set_b%pgf_radius, &
     454              :             set_radius_b => basis_set_b%set_radius, &
     455              :             sphi_b => basis_set_b%sphi, &
     456              :             zetb => basis_set_b%zet)
     457              : 
     458           18 :             nseta = basis_set_a%nset
     459           18 :             nsetb = basis_set_b%nset
     460              : 
     461           15 :             IF (inode == 1) last_jatom = 0
     462              : 
     463              :             ! this guarantees minimum image convention
     464              :             ! anything else would not make sense
     465           18 :             IF (jatom == last_jatom) THEN
     466              :                CYCLE
     467              :             END IF
     468              : 
     469           18 :             last_jatom = jatom
     470              : 
     471           18 :             IF (iatom <= jatom) THEN
     472           12 :                irow = iatom
     473           12 :                icol = jatom
     474              :             ELSE
     475            6 :                irow = jatom
     476            6 :                icol = iatom
     477              :             END IF
     478              : 
     479           72 :             DO i = 1, nm
     480           54 :                NULLIFY (mint(i)%block)
     481              :                CALL dbcsr_get_block_p(matrix=moments(i)%matrix, &
     482           54 :                                       row=irow, col=icol, BLOCK=mint(i)%block, found=found)
     483          396 :                mint(i)%block = 0._dp
     484              :             END DO
     485              : 
     486              :             ! fold atomic position back into unit cell
     487           18 :             IF (PRESENT(ref_points)) THEN
     488            0 :                rc(:) = 0.5_dp*(ref_points(:, iatom) + ref_points(:, jatom))
     489           18 :             ELSE IF (PRESENT(ref_point)) THEN
     490           72 :                rc(:) = ref_point(:)
     491              :             ELSE
     492            0 :                rc(:) = 0._dp
     493              :             END IF
     494              :             ! using PBC here might screw a molecule that fits the box (but e.g. hasn't been shifted by center_molecule)
     495              :             ! by folding around the center, such screwing can be avoided for a proper choice of center.
     496              :             ! we dont use PBC at this point
     497              : 
     498              :             ! With and without MIC, rab(:) is the vector giving us the coordinates of rb.
     499           72 :             ra(:) = particle_set(iatom)%r(:)
     500           72 :             rb(:) = ra(:) + rab(:)
     501           18 :             rac = pbc(rc, ra, cell)
     502           72 :             rbc = rac + rab
     503              : 
     504           72 :             dab = NORM2(rab)
     505              : 
     506           54 :             DO iset = 1, nseta
     507              : 
     508           18 :                ncoa = npgfa(iset)*ncoset(la_max(iset))
     509           18 :                sgfa = first_sgfa(1, iset)
     510              : 
     511           54 :                DO jset = 1, nsetb
     512              : 
     513           18 :                   IF (set_radius_a(iset) + set_radius_b(jset) < dab) CYCLE
     514              : 
     515           18 :                   ncob = npgfb(jset)*ncoset(lb_max(jset))
     516           18 :                   sgfb = first_sgfb(1, jset)
     517              : 
     518              :                   ! Calculate the primitive integrals
     519              :                   CALL moment(la_max(iset), npgfa(iset), zeta(:, iset), &
     520              :                               rpgfa(:, iset), la_min(iset), &
     521              :                               lb_max(jset), npgfb(jset), zetb(:, jset), &
     522           18 :                               rpgfb(:, jset), nmoments, rac, rbc, mab)
     523              : 
     524              :                   ! Contraction step
     525           90 :                   DO i = 1, nm
     526              : 
     527              :                      CALL dgemm("N", "N", ncoa, nsgfb(jset), ncob, &
     528              :                                 1.0_dp, mab(1, 1, i), SIZE(mab, 1), &
     529              :                                 sphi_b(1, sgfb), SIZE(sphi_b, 1), &
     530           54 :                                 0.0_dp, work(1, 1), SIZE(work, 1))
     531              : 
     532           72 :                      IF (iatom <= jatom) THEN
     533              : 
     534              :                         CALL dgemm("T", "N", nsgfa(iset), nsgfb(jset), ncoa, &
     535              :                                    1.0_dp, sphi_a(1, sgfa), SIZE(sphi_a, 1), &
     536              :                                    work(1, 1), SIZE(work, 1), &
     537              :                                    1.0_dp, mint(i)%block(sgfa, sgfb), &
     538           36 :                                    SIZE(mint(i)%block, 1))
     539              : 
     540              :                      ELSE
     541              : 
     542              :                         CALL dgemm("T", "N", nsgfb(jset), nsgfa(iset), ncoa, &
     543              :                                    1.0_dp, work(1, 1), SIZE(work, 1), &
     544              :                                    sphi_a(1, sgfa), SIZE(sphi_a, 1), &
     545              :                                    1.0_dp, mint(i)%block(sgfb, sgfa), &
     546           18 :                                    SIZE(mint(i)%block, 1))
     547              : 
     548              :                      END IF
     549              : 
     550              :                   END DO
     551              : 
     552              :                END DO
     553              :             END DO
     554              :          END ASSOCIATE
     555              : 
     556              :       END DO ! iterator
     557              : 
     558            6 :       CALL neighbor_list_iterator_release(nl_iterator)
     559              : 
     560              :       ! Release work storage
     561            6 :       DEALLOCATE (mab, basis_set_list)
     562            6 :       DEALLOCATE (work)
     563           24 :       DO i = 1, nm
     564           24 :          NULLIFY (mint(i)%block)
     565              :       END DO
     566            6 :       DEALLOCATE (mint)
     567              : 
     568            6 :       CALL timestop(handle)
     569              : 
     570           12 :    END SUBROUTINE build_dsdv_moments
     571              : 
     572              : ! **************************************************************************************************
     573              : !> \brief ...
     574              : !> \param qs_env ...
     575              : !> \param moments ...
     576              : !> \param nmoments ...
     577              : !> \param ref_point ...
     578              : !> \param ref_points ...
     579              : !> \param basis_type ...
     580              : ! **************************************************************************************************
     581         2594 :    SUBROUTINE build_local_moment_matrix(qs_env, moments, nmoments, ref_point, ref_points, basis_type)
     582              : 
     583              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     584              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: moments
     585              :       INTEGER, INTENT(IN)                                :: nmoments
     586              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: ref_point
     587              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
     588              :          OPTIONAL                                        :: ref_points
     589              :       CHARACTER(len=*), OPTIONAL                         :: basis_type
     590              : 
     591              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_local_moment_matrix'
     592              : 
     593              :       INTEGER :: handle, i, iatom, icol, ikind, inode, irow, iset, jatom, jkind, jset, last_jatom, &
     594              :                  maxco, maxsgf, natom, ncoa, ncob, nkind, nm, nseta, nsetb, sgfa, sgfb
     595              :       LOGICAL                                            :: found
     596              :       REAL(KIND=dp)                                      :: dab
     597         2594 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: work
     598         2594 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: mab
     599              :       REAL(KIND=dp), DIMENSION(3)                        :: ra, rab, rac, rb, rbc, rc
     600         2594 :       TYPE(block_p_type), ALLOCATABLE, DIMENSION(:)      :: mint
     601              :       TYPE(cell_type), POINTER                           :: cell
     602         2594 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
     603              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set_a, basis_set_b
     604              :       TYPE(neighbor_list_iterator_p_type), &
     605         2594 :          DIMENSION(:), POINTER                           :: nl_iterator
     606              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     607         2594 :          POINTER                                         :: sab_orb
     608         2594 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     609         2594 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     610              :       TYPE(qs_kind_type), POINTER                        :: qs_kind
     611              : 
     612         2594 :       IF (nmoments < 1) RETURN
     613              : 
     614         2594 :       CALL timeset(routineN, handle)
     615              : 
     616         2594 :       NULLIFY (qs_kind_set, cell, particle_set, sab_orb)
     617              : 
     618         2594 :       nm = (6 + 11*nmoments + 6*nmoments**2 + nmoments**3)/6 - 1
     619         2594 :       CPASSERT(SIZE(moments) >= nm)
     620              : 
     621         2594 :       NULLIFY (qs_kind_set, particle_set, sab_orb, cell)
     622              :       CALL get_qs_env(qs_env=qs_env, &
     623              :                       qs_kind_set=qs_kind_set, &
     624              :                       particle_set=particle_set, cell=cell, &
     625         2594 :                       sab_orb=sab_orb)
     626              : 
     627         2594 :       nkind = SIZE(qs_kind_set)
     628         2594 :       natom = SIZE(particle_set)
     629              : 
     630              :       ! Allocate work storage
     631              :       CALL get_qs_kind_set(qs_kind_set=qs_kind_set, &
     632              :                            maxco=maxco, maxsgf=maxsgf, &
     633         5082 :                            basis_type=basis_type)
     634              : 
     635        12970 :       ALLOCATE (mab(maxco, maxco, nm))
     636      3155690 :       mab(:, :, :) = 0.0_dp
     637              : 
     638        10376 :       ALLOCATE (work(maxco, maxsgf))
     639       481174 :       work(:, :) = 0.0_dp
     640              : 
     641        15722 :       ALLOCATE (mint(nm))
     642        10534 :       DO i = 1, nm
     643        10534 :          NULLIFY (mint(i)%block)
     644              :       END DO
     645              : 
     646        13044 :       ALLOCATE (basis_set_list(nkind))
     647         7856 :       DO ikind = 1, nkind
     648         5262 :          qs_kind => qs_kind_set(ikind)
     649         5262 :          CALL get_qs_kind(qs_kind=qs_kind, basis_set=basis_set_a, basis_type=basis_type)
     650         7856 :          IF (ASSOCIATED(basis_set_a)) THEN
     651         5262 :             basis_set_list(ikind)%gto_basis_set => basis_set_a
     652              :          ELSE
     653            0 :             NULLIFY (basis_set_list(ikind)%gto_basis_set)
     654              :          END IF
     655              :       END DO
     656         2594 :       CALL neighbor_list_iterator_create(nl_iterator, sab_orb)
     657        30679 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
     658              :          CALL get_iterator_info(nl_iterator, ikind=ikind, jkind=jkind, inode=inode, &
     659        28085 :                                 iatom=iatom, jatom=jatom, r=rab)
     660        28085 :          basis_set_a => basis_set_list(ikind)%gto_basis_set
     661        28085 :          IF (.NOT. ASSOCIATED(basis_set_a)) CYCLE
     662        28085 :          basis_set_b => basis_set_list(jkind)%gto_basis_set
     663        28085 :          IF (.NOT. ASSOCIATED(basis_set_b)) CYCLE
     664              :          ASSOCIATE ( &
     665              :             ! basis ikind
     666              :             first_sgfa => basis_set_a%first_sgf, &
     667              :             la_max => basis_set_a%lmax, &
     668              :             la_min => basis_set_a%lmin, &
     669              :             npgfa => basis_set_a%npgf, &
     670              :             nsgfa => basis_set_a%nsgf_set, &
     671              :             rpgfa => basis_set_a%pgf_radius, &
     672              :             set_radius_a => basis_set_a%set_radius, &
     673              :             sphi_a => basis_set_a%sphi, &
     674              :             zeta => basis_set_a%zet, &
     675              :             ! basis jkind, &
     676              :             first_sgfb => basis_set_b%first_sgf, &
     677              :             lb_max => basis_set_b%lmax, &
     678              :             lb_min => basis_set_b%lmin, &
     679              :             npgfb => basis_set_b%npgf, &
     680              :             nsgfb => basis_set_b%nsgf_set, &
     681              :             rpgfb => basis_set_b%pgf_radius, &
     682              :             set_radius_b => basis_set_b%set_radius, &
     683              :             sphi_b => basis_set_b%sphi, &
     684              :             zetb => basis_set_b%zet)
     685              : 
     686        28085 :             nseta = basis_set_a%nset
     687        28085 :             nsetb = basis_set_b%nset
     688              : 
     689         6719 :             IF (inode == 1) last_jatom = 0
     690              : 
     691              :             ! this guarantees minimum image convention
     692              :             ! anything else would not make sense
     693        28085 :             IF (jatom == last_jatom) THEN
     694              :                CYCLE
     695              :             END IF
     696              : 
     697         8005 :             last_jatom = jatom
     698              : 
     699         8005 :             IF (iatom <= jatom) THEN
     700         5213 :                irow = iatom
     701         5213 :                icol = jatom
     702              :             ELSE
     703         2792 :                irow = jatom
     704         2792 :                icol = iatom
     705              :             END IF
     706              : 
     707        32722 :             DO i = 1, nm
     708        24717 :                NULLIFY (mint(i)%block)
     709              :                CALL dbcsr_get_block_p(matrix=moments(i)%matrix, &
     710        24717 :                                       row=irow, col=icol, BLOCK=mint(i)%block, found=found)
     711      1310468 :                mint(i)%block = 0._dp
     712              :             END DO
     713              : 
     714              :             ! fold atomic position back into unit cell
     715         8005 :             IF (PRESENT(ref_points)) THEN
     716            0 :                rc(:) = 0.5_dp*(ref_points(:, iatom) + ref_points(:, jatom))
     717         8005 :             ELSE IF (PRESENT(ref_point)) THEN
     718        29492 :                rc(:) = ref_point(:)
     719              :             ELSE
     720          632 :                rc(:) = 0._dp
     721              :             END IF
     722              :             ! using PBC here might screw a molecule that fits the box (but e.g. hasn't been shifted by center_molecule)
     723              :             ! by folding around the center, such screwing can be avoided for a proper choice of center.
     724        64040 :             ra(:) = pbc(particle_set(iatom)%r(:) - rc, cell) + rc
     725        64040 :             rb(:) = pbc(particle_set(jatom)%r(:) - rc, cell) + rc
     726              :             ! we dont use PBC at this point
     727        32020 :             rab(:) = ra(:) - rb(:)
     728        32020 :             rac(:) = ra(:) - rc(:)
     729        32020 :             rbc(:) = rb(:) - rc(:)
     730        32020 :             dab = NORM2(rab)
     731              : 
     732        48724 :             DO iset = 1, nseta
     733              : 
     734        12634 :                ncoa = npgfa(iset)*ncoset(la_max(iset))
     735        12634 :                sgfa = first_sgfa(1, iset)
     736              : 
     737        42741 :                DO jset = 1, nsetb
     738              : 
     739        22102 :                   IF (set_radius_a(iset) + set_radius_b(jset) < dab) CYCLE
     740              : 
     741        22021 :                   ncob = npgfb(jset)*ncoset(lb_max(jset))
     742        22021 :                   sgfb = first_sgfb(1, jset)
     743              : 
     744              :                   ! Calculate the primitive integrals
     745              :                   CALL moment(la_max(iset), npgfa(iset), zeta(:, iset), &
     746              :                               rpgfa(:, iset), la_min(iset), &
     747              :                               lb_max(jset), npgfb(jset), zetb(:, jset), &
     748        22021 :                               rpgfb(:, jset), nmoments, rac, rbc, mab)
     749              : 
     750              :                   ! Contraction step
     751       103628 :                   DO i = 1, nm
     752              : 
     753              :                      CALL dgemm("N", "N", ncoa, nsgfb(jset), ncob, &
     754              :                                 1.0_dp, mab(1, 1, i), SIZE(mab, 1), &
     755              :                                 sphi_b(1, sgfb), SIZE(sphi_b, 1), &
     756        68973 :                                 0.0_dp, work(1, 1), SIZE(work, 1))
     757              : 
     758        91075 :                      IF (iatom <= jatom) THEN
     759              : 
     760              :                         CALL dgemm("T", "N", nsgfa(iset), nsgfb(jset), ncoa, &
     761              :                                    1.0_dp, sphi_a(1, sgfa), SIZE(sphi_a, 1), &
     762              :                                    work(1, 1), SIZE(work, 1), &
     763              :                                    1.0_dp, mint(i)%block(sgfa, sgfb), &
     764        45283 :                                    SIZE(mint(i)%block, 1))
     765              : 
     766              :                      ELSE
     767              : 
     768              :                         CALL dgemm("T", "N", nsgfb(jset), nsgfa(iset), ncoa, &
     769              :                                    1.0_dp, work(1, 1), SIZE(work, 1), &
     770              :                                    sphi_a(1, sgfa), SIZE(sphi_a, 1), &
     771              :                                    1.0_dp, mint(i)%block(sgfb, sgfa), &
     772        23690 :                                    SIZE(mint(i)%block, 1))
     773              : 
     774              :                      END IF
     775              : 
     776              :                   END DO
     777              : 
     778              :                END DO
     779              :             END DO
     780              :          END ASSOCIATE
     781              : 
     782              :       END DO
     783         2594 :       CALL neighbor_list_iterator_release(nl_iterator)
     784              : 
     785              :       ! Release work storage
     786         2594 :       DEALLOCATE (mab, basis_set_list)
     787         2594 :       DEALLOCATE (work)
     788        10534 :       DO i = 1, nm
     789        10534 :          NULLIFY (mint(i)%block)
     790              :       END DO
     791         2594 :       DEALLOCATE (mint)
     792              : 
     793         2594 :       CALL timestop(handle)
     794              : 
     795         5188 :    END SUBROUTINE build_local_moment_matrix
     796              : 
     797              : ! **************************************************************************************************
     798              : !> \brief Calculate right-hand sided derivatives of multipole moments, e. g. < a | xy d/dz | b >
     799              : !>        Optionally stores the multipole moments themselves for free.
     800              : !>        Note that the multipole moments are symmetric while their derivatives are anti-symmetric
     801              : !>        Only first derivatives are performed, e. g. x d/dy
     802              : !> \param qs_env ...
     803              : !> \param moments_der will contain the derivatives of the multipole moments
     804              : !> \param nmoments_der order of the moments with derivatives
     805              : !> \param nmoments order of the multipole moments (no derivatives, same output as
     806              : !>        build_local_moment_matrix, needs moments as arguments to store results)
     807              : !> \param ref_point ...
     808              : !> \param moments contains the multipole moments, optionally for free, up to order nmoments
     809              : !> \note
     810              : !>        Adapted from rRc_xyz_der_ao in qs_operators_ao
     811              : ! **************************************************************************************************
     812           30 :    SUBROUTINE build_local_moments_der_matrix(qs_env, moments_der, nmoments_der, nmoments, &
     813           30 :                                              ref_point, moments)
     814              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     815              :       TYPE(dbcsr_p_type), DIMENSION(:, :), &
     816              :          INTENT(INOUT), POINTER                          :: moments_der
     817              :       INTEGER, INTENT(IN)                                :: nmoments_der, nmoments
     818              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: ref_point
     819              :       TYPE(dbcsr_p_type), DIMENSION(:), INTENT(INOUT), &
     820              :          OPTIONAL, POINTER                               :: moments
     821              : 
     822              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_local_moments_der_matrix'
     823              : 
     824              :       INTEGER :: dimders, handle, i, iatom, icol, ider, ii, ikind, inode, ipgf, irow, iset, j, &
     825              :                  jatom, jkind, jpgf, jset, last_jatom, M_dim, maxco, maxsgf, na, nb, ncoa, ncob, nda, ndb, &
     826              :                  nders, nkind, nm, nmom_build, nseta, nsetb, sgfa, sgfb
     827              :       LOGICAL                                            :: found
     828              :       REAL(KIND=dp)                                      :: dab
     829           30 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: work
     830           30 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: mab
     831           30 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :, :)  :: difmab
     832              :       REAL(KIND=dp), DIMENSION(3)                        :: ra, rab, rac, rb, rbc, rc
     833           30 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: mab_tmp
     834           30 :       TYPE(block_p_type), ALLOCATABLE, DIMENSION(:)      :: mom_block
     835           30 :       TYPE(block_p_type), ALLOCATABLE, DIMENSION(:, :)   :: mom_block_der
     836              :       TYPE(cell_type), POINTER                           :: cell
     837           30 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
     838              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set_a, basis_set_b
     839              :       TYPE(neighbor_list_iterator_p_type), &
     840           30 :          DIMENSION(:), POINTER                           :: nl_iterator
     841              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     842           30 :          POINTER                                         :: sab_orb
     843           30 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     844           30 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     845              :       TYPE(qs_kind_type), POINTER                        :: qs_kind
     846              : 
     847           30 :       nmom_build = MAX(nmoments, nmoments_der)      ! build moments up to order nmom_buiod
     848           30 :       IF (nmom_build < 1) RETURN
     849              : 
     850           30 :       CALL timeset(routineN, handle)
     851              : 
     852           30 :       nders = 1                                    ! only first order derivatives
     853           30 :       dimders = ncoset(nders) - 1
     854              : 
     855           30 :       NULLIFY (qs_kind_set, particle_set, sab_orb, cell)
     856              :       CALL get_qs_env(qs_env=qs_env, &
     857              :                       qs_kind_set=qs_kind_set, &
     858              :                       particle_set=particle_set, &
     859              :                       cell=cell, &
     860           30 :                       sab_orb=sab_orb)
     861              : 
     862           30 :       nkind = SIZE(qs_kind_set)
     863              : 
     864              :       ! Work storage
     865              :       CALL get_qs_kind_set(qs_kind_set=qs_kind_set, &
     866           30 :                            maxco=maxco, maxsgf=maxsgf)
     867              : 
     868           30 :       IF (nmoments > 0) THEN
     869           28 :          CPASSERT(PRESENT(moments))
     870           28 :          nm = (6 + 11*nmoments + 6*nmoments**2 + nmoments**3)/6 - 1
     871           28 :          CPASSERT(SIZE(moments) == nm)
     872              :          ! storage for integrals
     873          140 :          ALLOCATE (mab(maxco, maxco, nm))
     874              :          ! blocks
     875       272620 :          mab(:, :, :) = 0.0_dp
     876          336 :          ALLOCATE (mom_block(nm))
     877          280 :          DO i = 1, nm
     878          280 :             NULLIFY (mom_block(i)%block)
     879              :          END DO
     880              :       END IF
     881              : 
     882           30 :       IF (nmoments_der > 0) THEN
     883           30 :          M_dim = ncoset(nmoments_der) - 1
     884           30 :          CPASSERT(SIZE(moments_der, dim=1) == M_dim)
     885           30 :          CPASSERT(SIZE(moments_der, dim=2) == dimders)
     886              :          ! storage for integrals
     887          180 :          ALLOCATE (difmab(maxco, maxco, M_dim, dimders))
     888       287454 :          difmab(:, :, :, :) = 0.0_dp
     889              :          ! blocks
     890          516 :          ALLOCATE (mom_block_der(M_dim, dimders))
     891          132 :          DO i = 1, M_dim
     892          438 :             DO ider = 1, dimders
     893          408 :                NULLIFY (mom_block_der(i, ider)%block)
     894              :             END DO
     895              :          END DO
     896              :       END IF
     897              : 
     898          120 :       ALLOCATE (work(maxco, maxsgf))
     899         6254 :       work(:, :) = 0.0_dp
     900              : 
     901           30 :       NULLIFY (basis_set_a, basis_set_b, basis_set_list)
     902           30 :       NULLIFY (qs_kind)
     903          128 :       ALLOCATE (basis_set_list(nkind))
     904           68 :       DO ikind = 1, nkind
     905           38 :          qs_kind => qs_kind_set(ikind)
     906           38 :          CALL get_qs_kind(qs_kind=qs_kind, basis_set=basis_set_a)
     907           68 :          IF (ASSOCIATED(basis_set_a)) THEN
     908           38 :             basis_set_list(ikind)%gto_basis_set => basis_set_a
     909              :          ELSE
     910            0 :             NULLIFY (basis_set_list(ikind)%gto_basis_set)
     911              :          END IF
     912              :       END DO
     913              : 
     914              :       ! Calculate derivatives looping over neighbour list
     915           30 :       NULLIFY (nl_iterator)
     916           30 :       CALL neighbor_list_iterator_create(nl_iterator, sab_orb)
     917          213 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
     918              :          CALL get_iterator_info(nl_iterator, ikind=ikind, jkind=jkind, inode=inode, &
     919          183 :                                 iatom=iatom, jatom=jatom, r=rab)
     920          183 :          basis_set_a => basis_set_list(ikind)%gto_basis_set
     921          183 :          IF (.NOT. ASSOCIATED(basis_set_a)) CYCLE
     922          183 :          basis_set_b => basis_set_list(jkind)%gto_basis_set
     923          183 :          IF (.NOT. ASSOCIATED(basis_set_b)) CYCLE
     924              :          ASSOCIATE ( &
     925              :             ! basis ikind
     926              :             first_sgfa => basis_set_a%first_sgf, &
     927              :             la_max => basis_set_a%lmax, &
     928              :             la_min => basis_set_a%lmin, &
     929              :             npgfa => basis_set_a%npgf, &
     930              :             nsgfa => basis_set_a%nsgf_set, &
     931              :             rpgfa => basis_set_a%pgf_radius, &
     932              :             set_radius_a => basis_set_a%set_radius, &
     933              :             sphi_a => basis_set_a%sphi, &
     934              :             zeta => basis_set_a%zet, &
     935              :             ! basis jkind, &
     936              :             first_sgfb => basis_set_b%first_sgf, &
     937              :             lb_max => basis_set_b%lmax, &
     938              :             lb_min => basis_set_b%lmin, &
     939              :             npgfb => basis_set_b%npgf, &
     940              :             nsgfb => basis_set_b%nsgf_set, &
     941              :             rpgfb => basis_set_b%pgf_radius, &
     942              :             set_radius_b => basis_set_b%set_radius, &
     943              :             sphi_b => basis_set_b%sphi, &
     944              :             zetb => basis_set_b%zet)
     945              : 
     946          183 :             nseta = basis_set_a%nset
     947          183 :             nsetb = basis_set_b%nset
     948              : 
     949              :             ! reference point
     950          183 :             IF (PRESENT(ref_point)) THEN
     951          732 :                rc(:) = ref_point(:)
     952              :             ELSE
     953            0 :                rc(:) = 0._dp
     954              :             END IF
     955              :             ! using PBC here might screw a molecule that fits the box (but e.g. hasn't been shifted by center_molecule)
     956              :             ! by folding around the center, such screwing can be avoided for a proper choice of center.
     957         1464 :             ra(:) = pbc(particle_set(iatom)%r(:) - rc, cell) + rc
     958         1464 :             rb(:) = pbc(particle_set(jatom)%r(:) - rc, cell) + rc
     959              :             ! we dont use PBC at this point
     960          732 :             rab(:) = ra(:) - rb(:)
     961          732 :             rac(:) = ra(:) - rc(:)
     962          732 :             rbc(:) = rb(:) - rc(:)
     963          732 :             dab = NORM2(rab)
     964              : 
     965              :             ! get blocks
     966          183 :             IF (inode == 1) last_jatom = 0
     967              : 
     968          183 :             IF (jatom == last_jatom) THEN
     969              :                CYCLE
     970              :             END IF
     971              : 
     972           57 :             last_jatom = jatom
     973              : 
     974           57 :             IF (iatom <= jatom) THEN
     975           38 :                irow = iatom
     976           38 :                icol = jatom
     977              :             ELSE
     978           19 :                irow = jatom
     979           19 :                icol = iatom
     980              :             END IF
     981              : 
     982           57 :             IF (nmoments > 0) THEN
     983          510 :                DO i = 1, nm
     984          459 :                   NULLIFY (mom_block(i)%block)
     985              :                   ! get block from pre calculated overlap matrix
     986              :                   CALL dbcsr_get_block_p(matrix=moments(i)%matrix, &
     987          459 :                                          row=irow, col=icol, BLOCK=mom_block(i)%block, found=found)
     988          459 :                   CPASSERT(found .AND. ASSOCIATED(mom_block(i)%block))
     989        21003 :                   mom_block(i)%block = 0._dp
     990              :                END DO
     991              :             END IF
     992           57 :             IF (nmoments_der > 0) THEN
     993          264 :                DO i = 1, M_dim
     994          885 :                   DO ider = 1, dimders
     995          621 :                      NULLIFY (mom_block_der(i, ider)%block)
     996              :                      CALL dbcsr_get_block_p(matrix=moments_der(i, ider)%matrix, &
     997              :                                             row=irow, col=icol, &
     998              :                                             block=mom_block_der(i, ider)%block, &
     999          621 :                                             found=found)
    1000          621 :                      CPASSERT(found .AND. ASSOCIATED(mom_block_der(i, ider)%block))
    1001        22455 :                      mom_block_der(i, ider)%block = 0._dp
    1002              :                   END DO
    1003              :                END DO
    1004              :             END IF
    1005              : 
    1006          330 :             DO iset = 1, nseta
    1007              : 
    1008           90 :                ncoa = npgfa(iset)*ncoset(la_max(iset))
    1009           90 :                sgfa = first_sgfa(1, iset)
    1010              : 
    1011          303 :                DO jset = 1, nsetb
    1012              : 
    1013          156 :                   IF (set_radius_a(iset) + set_radius_b(jset) < dab) CYCLE
    1014              : 
    1015          156 :                   ncob = npgfb(jset)*ncoset(lb_max(jset))
    1016          156 :                   sgfb = first_sgfb(1, jset)
    1017              : 
    1018          156 :                   NULLIFY (mab_tmp)
    1019              :                   ALLOCATE (mab_tmp(npgfa(iset)*ncoset(la_max(iset) + 1), &
    1020          780 :                                     npgfb(jset)*ncoset(lb_max(jset) + 1), ncoset(nmom_build) - 1))
    1021              : 
    1022              :                   ! Calculate the primitive integrals (need l+1 for derivatives)
    1023              :                   CALL moment(la_max(iset) + 1, npgfa(iset), zeta(:, iset), &
    1024              :                               rpgfa(:, iset), la_min(iset), &
    1025              :                               lb_max(jset) + 1, npgfb(jset), zetb(:, jset), &
    1026          156 :                               rpgfb(:, jset), nmom_build, rac, rbc, mab_tmp)
    1027              : 
    1028          156 :                   IF (nmoments_der > 0) THEN
    1029              :                      CALL diff_momop(la_max(iset), npgfa(iset), zeta(:, iset), &
    1030              :                                      rpgfa(:, iset), la_min(iset), &
    1031              :                                      lb_max(jset), npgfb(jset), zetb(:, jset), &
    1032              :                                      rpgfb(:, jset), lb_min(jset), &
    1033          156 :                                      nmoments_der, rac, rbc, difmab, mab_ext=mab_tmp)
    1034              :                   END IF
    1035              : 
    1036          156 :                   IF (nmoments > 0) THEN
    1037              :                      ! copy subset of mab_tmp (l+1) to mab (l)
    1038       830400 :                      mab = 0.0_dp
    1039         1500 :                      DO ii = 1, nm
    1040         1350 :                         na = 0
    1041         1350 :                         nda = 0
    1042         5604 :                         DO ipgf = 1, npgfa(iset)
    1043         4104 :                            nb = 0
    1044         4104 :                            ndb = 0
    1045        19467 :                            DO jpgf = 1, npgfb(jset)
    1046        74871 :                               DO j = 1, ncoset(lb_max(jset))
    1047       395523 :                                  DO i = 1, ncoset(la_max(iset))
    1048       380160 :                                     mab(i + na, j + nb, ii) = mab_tmp(i + nda, j + ndb, ii)
    1049              :                                  END DO ! i
    1050              :                               END DO ! j
    1051        15363 :                               nb = nb + ncoset(lb_max(jset))
    1052        19467 :                               ndb = ndb + ncoset(lb_max(jset) + 1)
    1053              :                            END DO ! jpgf
    1054         4104 :                            na = na + ncoset(la_max(iset))
    1055         5454 :                            nda = nda + ncoset(la_max(iset) + 1)
    1056              :                         END DO ! ipgf
    1057              :                      END DO
    1058              :                      ! Contraction step
    1059         1500 :                      DO i = 1, nm
    1060              : 
    1061              :                         CALL dgemm("N", "N", ncoa, nsgfb(jset), ncob, &
    1062              :                                    1.0_dp, mab(1, 1, i), SIZE(mab, 1), &
    1063              :                                    sphi_b(1, sgfb), SIZE(sphi_b, 1), &
    1064         1350 :                                    0.0_dp, work(1, 1), SIZE(work, 1))
    1065              : 
    1066         1500 :                         IF (iatom <= jatom) THEN
    1067              :                            CALL dgemm("T", "N", nsgfa(iset), nsgfb(jset), ncoa, &
    1068              :                                       1.0_dp, sphi_a(1, sgfa), SIZE(sphi_a, 1), &
    1069              :                                       work(1, 1), SIZE(work, 1), &
    1070              :                                       1.0_dp, mom_block(i)%block(sgfa, sgfb), &
    1071          900 :                                       SIZE(mom_block(i)%block, 1))
    1072              :                         ELSE
    1073              :                            CALL dgemm("T", "N", nsgfb(jset), nsgfa(iset), ncoa, &
    1074              :                                       1.0_dp, work(1, 1), SIZE(work, 1), &
    1075              :                                       sphi_a(1, sgfa), SIZE(sphi_a, 1), &
    1076              :                                       1.0_dp, mom_block(i)%block(sgfb, sgfa), &
    1077          450 :                                       SIZE(mom_block(i)%block, 1))
    1078              :                         END IF
    1079              :                      END DO
    1080              :                   END IF
    1081              : 
    1082          156 :                   IF (nmoments_der > 0) THEN
    1083          660 :                      DO i = 1, M_dim
    1084         2172 :                         DO ider = 1, dimders
    1085              :                            CALL dgemm("N", "N", ncoa, nsgfb(jset), ncob, &
    1086              :                                       1.0_dp, difmab(1, 1, i, ider), SIZE(difmab, 1), &
    1087              :                                       sphi_b(1, sgfb), SIZE(sphi_b, 1), &
    1088         1512 :                                       0._dp, work(1, 1), SIZE(work, 1))
    1089              : 
    1090         2016 :                            IF (iatom <= jatom) THEN
    1091              :                               CALL dgemm("T", "N", nsgfa(iset), nsgfb(jset), ncoa, &
    1092              :                                          1.0_dp, sphi_a(1, sgfa), SIZE(sphi_a, 1), &
    1093              :                                          work(1, 1), SIZE(work, 1), &
    1094              :                                          1._dp, mom_block_der(i, ider)%block(sgfa, sgfb), &
    1095         1008 :                                          SIZE(mom_block_der(i, ider)%block, 1))
    1096              :                            ELSE
    1097              :                               CALL dgemm("T", "N", nsgfb(jset), nsgfa(iset), ncoa, &
    1098              :                                          -1.0_dp, work(1, 1), SIZE(work, 1), &
    1099              :                                          sphi_a(1, sgfa), SIZE(sphi_a, 1), &
    1100              :                                          1.0_dp, mom_block_der(i, ider)%block(sgfb, sgfa), &
    1101          504 :                                          SIZE(mom_block_der(i, ider)%block, 1))
    1102              :                            END IF
    1103              :                         END DO
    1104              :                      END DO
    1105              :                   END IF
    1106          246 :                   DEALLOCATE (mab_tmp)
    1107              :                END DO
    1108              :             END DO
    1109              :          END ASSOCIATE
    1110              :       END DO
    1111           30 :       CALL neighbor_list_iterator_release(nl_iterator)
    1112              : 
    1113              :       ! deallocations
    1114           30 :       DEALLOCATE (basis_set_list)
    1115           30 :       DEALLOCATE (work)
    1116           30 :       IF (nmoments > 0) THEN
    1117           28 :          DEALLOCATE (mab)
    1118          280 :          DO i = 1, nm
    1119          280 :             NULLIFY (mom_block(i)%block)
    1120              :          END DO
    1121           28 :          DEALLOCATE (mom_block)
    1122              :       END IF
    1123           30 :       IF (nmoments_der > 0) THEN
    1124           30 :          DEALLOCATE (difmab)
    1125          132 :          DO i = 1, M_dim
    1126          438 :             DO ider = 1, dimders
    1127          408 :                NULLIFY (mom_block_der(i, ider)%block)
    1128              :             END DO
    1129              :          END DO
    1130           30 :          DEALLOCATE (mom_block_der)
    1131              :       END IF
    1132              : 
    1133           30 :       CALL timestop(handle)
    1134              : 
    1135           90 :    END SUBROUTINE build_local_moments_der_matrix
    1136              : 
    1137              : ! **************************************************************************************************
    1138              : !> \brief ...
    1139              : !> \param qs_env ...
    1140              : !> \param magmom ...
    1141              : !> \param nmoments ...
    1142              : !> \param ref_point ...
    1143              : !> \param ref_points ...
    1144              : !> \param basis_type ...
    1145              : ! **************************************************************************************************
    1146           16 :    SUBROUTINE build_local_magmom_matrix(qs_env, magmom, nmoments, ref_point, ref_points, basis_type)
    1147              : 
    1148              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1149              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: magmom
    1150              :       INTEGER, INTENT(IN)                                :: nmoments
    1151              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: ref_point
    1152              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
    1153              :          OPTIONAL                                        :: ref_points
    1154              :       CHARACTER(len=*), OPTIONAL                         :: basis_type
    1155              : 
    1156              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_local_magmom_matrix'
    1157              : 
    1158              :       INTEGER :: handle, i, iatom, icol, ikind, inode, irow, iset, jatom, jkind, jset, maxco, &
    1159              :                  maxsgf, natom, ncoa, ncob, nkind, nm, nseta, nsetb, sgfa, sgfb
    1160              :       LOGICAL                                            :: found
    1161              :       REAL(KIND=dp)                                      :: dab
    1162           16 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: work
    1163           16 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: mab
    1164              :       REAL(KIND=dp), DIMENSION(3)                        :: ra, rab, rac, rb, rbc, rc
    1165           16 :       TYPE(block_p_type), ALLOCATABLE, DIMENSION(:)      :: mint
    1166              :       TYPE(cell_type), POINTER                           :: cell
    1167           16 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
    1168           16 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
    1169              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set_a, basis_set_b
    1170              :       TYPE(neighbor_list_iterator_p_type), &
    1171           16 :          DIMENSION(:), POINTER                           :: nl_iterator
    1172              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    1173           16 :          POINTER                                         :: sab_orb
    1174           16 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1175           16 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1176              :       TYPE(qs_kind_type), POINTER                        :: qs_kind
    1177              : 
    1178           16 :       IF (nmoments < 1) RETURN
    1179              : 
    1180           16 :       CALL timeset(routineN, handle)
    1181              : 
    1182           16 :       NULLIFY (qs_kind_set, cell, particle_set, sab_orb)
    1183           16 :       NULLIFY (matrix_s)
    1184              : 
    1185           16 :       CALL get_qs_env(qs_env=qs_env, matrix_s=matrix_s)
    1186              : 
    1187              :       ! magnetic dipoles/angular moments only
    1188           16 :       nm = 3
    1189              : 
    1190           16 :       NULLIFY (qs_kind_set, particle_set, sab_orb, cell)
    1191              :       CALL get_qs_env(qs_env=qs_env, &
    1192              :                       qs_kind_set=qs_kind_set, &
    1193              :                       particle_set=particle_set, cell=cell, &
    1194           16 :                       sab_orb=sab_orb)
    1195              : 
    1196           16 :       nkind = SIZE(qs_kind_set)
    1197           16 :       natom = SIZE(particle_set)
    1198              : 
    1199              :       ! Allocate work storage
    1200              :       CALL get_qs_kind_set(qs_kind_set=qs_kind_set, &
    1201           16 :                            maxco=maxco, maxsgf=maxsgf)
    1202              : 
    1203           80 :       ALLOCATE (mab(maxco, maxco, nm))
    1204       210436 :       mab(:, :, :) = 0.0_dp
    1205              : 
    1206           64 :       ALLOCATE (work(maxco, maxsgf))
    1207        13380 :       work(:, :) = 0.0_dp
    1208              : 
    1209           64 :       ALLOCATE (mint(nm))
    1210           64 :       DO i = 1, nm
    1211           64 :          NULLIFY (mint(i)%block)
    1212              :       END DO
    1213              : 
    1214           80 :       ALLOCATE (basis_set_list(nkind))
    1215           48 :       DO ikind = 1, nkind
    1216           32 :          qs_kind => qs_kind_set(ikind)
    1217           64 :          CALL get_qs_kind(qs_kind=qs_kind, basis_set=basis_set_a, basis_type=basis_type)
    1218           48 :          IF (ASSOCIATED(basis_set_a)) THEN
    1219           32 :             basis_set_list(ikind)%gto_basis_set => basis_set_a
    1220              :          ELSE
    1221            0 :             NULLIFY (basis_set_list(ikind)%gto_basis_set)
    1222              :          END IF
    1223              :       END DO
    1224           16 :       CALL neighbor_list_iterator_create(nl_iterator, sab_orb)
    1225          175 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
    1226              :          CALL get_iterator_info(nl_iterator, ikind=ikind, jkind=jkind, inode=inode, &
    1227          159 :                                 iatom=iatom, jatom=jatom, r=rab)
    1228          159 :          basis_set_a => basis_set_list(ikind)%gto_basis_set
    1229          159 :          IF (.NOT. ASSOCIATED(basis_set_a)) CYCLE
    1230          159 :          basis_set_b => basis_set_list(jkind)%gto_basis_set
    1231          159 :          IF (.NOT. ASSOCIATED(basis_set_b)) CYCLE
    1232              :          ASSOCIATE ( &
    1233              :             ! basis ikind
    1234              :             first_sgfa => basis_set_a%first_sgf, &
    1235              :             la_max => basis_set_a%lmax, &
    1236              :             la_min => basis_set_a%lmin, &
    1237              :             npgfa => basis_set_a%npgf, &
    1238              :             nsgfa => basis_set_a%nsgf_set, &
    1239              :             rpgfa => basis_set_a%pgf_radius, &
    1240              :             set_radius_a => basis_set_a%set_radius, &
    1241              :             sphi_a => basis_set_a%sphi, &
    1242              :             zeta => basis_set_a%zet, &
    1243              :             ! basis jkind, &
    1244              :             first_sgfb => basis_set_b%first_sgf, &
    1245              :             lb_max => basis_set_b%lmax, &
    1246              :             lb_min => basis_set_b%lmin, &
    1247              :             npgfb => basis_set_b%npgf, &
    1248              :             nsgfb => basis_set_b%nsgf_set, &
    1249              :             rpgfb => basis_set_b%pgf_radius, &
    1250              :             set_radius_b => basis_set_b%set_radius, &
    1251              :             sphi_b => basis_set_b%sphi, &
    1252              :             zetb => basis_set_b%zet)
    1253              : 
    1254          159 :             nseta = basis_set_a%nset
    1255          159 :             nsetb = basis_set_b%nset
    1256              : 
    1257          159 :             IF (iatom <= jatom) THEN
    1258          106 :                irow = iatom
    1259          106 :                icol = jatom
    1260              :             ELSE
    1261           53 :                irow = jatom
    1262           53 :                icol = iatom
    1263              :             END IF
    1264              : 
    1265          636 :             DO i = 1, nm
    1266          477 :                NULLIFY (mint(i)%block)
    1267              :                CALL dbcsr_get_block_p(matrix=magmom(i)%matrix, &
    1268          477 :                                       row=irow, col=icol, BLOCK=mint(i)%block, found=found)
    1269        33123 :                mint(i)%block = 0._dp
    1270         1113 :                CPASSERT(ASSOCIATED(mint(i)%block))
    1271              :             END DO
    1272              : 
    1273              :             ! fold atomic position back into unit cell
    1274          159 :             IF (PRESENT(ref_points)) THEN
    1275            0 :                rc(:) = 0.5_dp*(ref_points(:, iatom) + ref_points(:, jatom))
    1276          159 :             ELSE IF (PRESENT(ref_point)) THEN
    1277          636 :                rc(:) = ref_point(:)
    1278              :             ELSE
    1279            0 :                rc(:) = 0._dp
    1280              :             END IF
    1281              :             ! using PBC here might screw a molecule that fits the box (but e.g. hasn't been shifted by center_molecule)
    1282              :             ! by folding around the center, such screwing can be avoided for a proper choice of center.
    1283         1272 :             ra(:) = pbc(particle_set(iatom)%r(:) - rc, cell) + rc
    1284         1272 :             rb(:) = pbc(particle_set(jatom)%r(:) - rc, cell) + rc
    1285              :             ! we dont use PBC at this point
    1286          636 :             rab(:) = ra(:) - rb(:)
    1287          636 :             rac(:) = ra(:) - rc(:)
    1288          636 :             rbc(:) = rb(:) - rc(:)
    1289          636 :             dab = NORM2(rab)
    1290              : 
    1291          594 :             DO iset = 1, nseta
    1292              : 
    1293          276 :                ncoa = npgfa(iset)*ncoset(la_max(iset))
    1294          276 :                sgfa = first_sgfa(1, iset)
    1295              : 
    1296          945 :                DO jset = 1, nsetb
    1297              : 
    1298          510 :                   IF (set_radius_a(iset) + set_radius_b(jset) < dab) CYCLE
    1299              : 
    1300          510 :                   ncob = npgfb(jset)*ncoset(lb_max(jset))
    1301          510 :                   sgfb = first_sgfb(1, jset)
    1302              : 
    1303              :                   ! Calculate the primitive integrals
    1304              :                   CALL angmom(la_max(iset), npgfa(iset), zeta(:, iset), &
    1305              :                               rpgfa(:, iset), la_min(iset), &
    1306              :                               lb_max(jset), npgfb(jset), zetb(:, jset), &
    1307          510 :                               rpgfb(:, jset), rac, rbc, mab)
    1308              : 
    1309              :                   ! Contraction step
    1310         2316 :                   DO i = 1, nm
    1311              :                      CALL dgemm("N", "N", ncoa, nsgfb(jset), ncob, &
    1312              :                                 1.0_dp, mab(1, 1, i), SIZE(mab, 1), &
    1313              :                                 sphi_b(1, sgfb), SIZE(sphi_b, 1), &
    1314         1530 :                                 0.0_dp, work(1, 1), SIZE(work, 1))
    1315              : 
    1316         2040 :                      IF (iatom <= jatom) THEN
    1317              :                         CALL dgemm("T", "N", nsgfa(iset), nsgfb(jset), ncoa, &
    1318              :                                    1.0_dp, sphi_a(1, sgfa), SIZE(sphi_a, 1), &
    1319              :                                    work(1, 1), SIZE(work, 1), &
    1320              :                                    1.0_dp, mint(i)%block(sgfa, sgfb), &
    1321         1020 :                                    SIZE(mint(i)%block, 1))
    1322              :                      ELSE
    1323              :                         CALL dgemm("T", "N", nsgfb(jset), nsgfa(iset), ncoa, &
    1324              :                                    -1.0_dp, work(1, 1), SIZE(work, 1), &
    1325              :                                    sphi_a(1, sgfa), SIZE(sphi_a, 1), &
    1326              :                                    1.0_dp, mint(i)%block(sgfb, sgfa), &
    1327          510 :                                    SIZE(mint(i)%block, 1))
    1328              :                      END IF
    1329              : 
    1330              :                   END DO
    1331              : 
    1332              :                END DO
    1333              :             END DO
    1334              :          END ASSOCIATE
    1335              :       END DO
    1336           16 :       CALL neighbor_list_iterator_release(nl_iterator)
    1337              : 
    1338              :       ! Release work storage
    1339           16 :       DEALLOCATE (mab, basis_set_list)
    1340           16 :       DEALLOCATE (work)
    1341           64 :       DO i = 1, nm
    1342           64 :          NULLIFY (mint(i)%block)
    1343              :       END DO
    1344           16 :       DEALLOCATE (mint)
    1345              : 
    1346           16 :       CALL timestop(handle)
    1347              : 
    1348           48 :    END SUBROUTINE build_local_magmom_matrix
    1349              : 
    1350              : ! **************************************************************************************************
    1351              : !> \brief ...
    1352              : !> \param qs_env ...
    1353              : !> \param cosmat ...
    1354              : !> \param sinmat ...
    1355              : !> \param kvec ...
    1356              : !> \param sab_orb_external ...
    1357              : !> \param basis_type ...
    1358              : ! **************************************************************************************************
    1359        13988 :    SUBROUTINE build_berry_moment_matrix(qs_env, cosmat, sinmat, kvec, sab_orb_external, basis_type)
    1360              : 
    1361              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1362              :       TYPE(dbcsr_type), POINTER                          :: cosmat, sinmat
    1363              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: kvec
    1364              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    1365              :          OPTIONAL, POINTER                               :: sab_orb_external
    1366              :       CHARACTER(len=*), OPTIONAL                         :: basis_type
    1367              : 
    1368              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_berry_moment_matrix'
    1369              : 
    1370              :       INTEGER :: handle, iatom, icol, ikind, inode, irow, iset, jatom, jkind, jset, ldab, ldsa, &
    1371              :                  ldsb, ldwork, natom, ncoa, ncob, nkind, nseta, nsetb, sgfa, sgfb
    1372              :       LOGICAL                                            :: found
    1373        13988 :       REAL(dp), DIMENSION(:, :), POINTER                 :: cblock, cosab, sblock, sinab, work
    1374              :       REAL(KIND=dp)                                      :: dab
    1375              :       REAL(KIND=dp), DIMENSION(3)                        :: ra, rab, rb
    1376              :       TYPE(cell_type), POINTER                           :: cell
    1377        13988 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
    1378              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set_a, basis_set_b
    1379              :       TYPE(neighbor_list_iterator_p_type), &
    1380        13988 :          DIMENSION(:), POINTER                           :: nl_iterator
    1381              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    1382        13988 :          POINTER                                         :: sab_orb
    1383        13988 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1384        13988 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1385              :       TYPE(qs_kind_type), POINTER                        :: qs_kind
    1386              : 
    1387        13988 :       CALL timeset(routineN, handle)
    1388              : 
    1389        13988 :       NULLIFY (qs_kind_set, particle_set, sab_orb, cell)
    1390              :       CALL get_qs_env(qs_env=qs_env, &
    1391              :                       qs_kind_set=qs_kind_set, &
    1392              :                       particle_set=particle_set, cell=cell, &
    1393        13988 :                       sab_orb=sab_orb)
    1394              : 
    1395        13988 :       IF (PRESENT(sab_orb_external)) sab_orb => sab_orb_external
    1396              : 
    1397        13988 :       CALL dbcsr_set(sinmat, 0.0_dp)
    1398        13988 :       CALL dbcsr_set(cosmat, 0.0_dp)
    1399              : 
    1400        16816 :       CALL get_qs_kind_set(qs_kind_set=qs_kind_set, maxco=ldwork, basis_type=basis_type)
    1401        13988 :       ldab = ldwork
    1402        55952 :       ALLOCATE (cosab(ldab, ldab))
    1403        41964 :       ALLOCATE (sinab(ldab, ldab))
    1404        41964 :       ALLOCATE (work(ldwork, ldwork))
    1405              : 
    1406        13988 :       nkind = SIZE(qs_kind_set)
    1407        13988 :       natom = SIZE(particle_set)
    1408              : 
    1409        70000 :       ALLOCATE (basis_set_list(nkind))
    1410        42024 :       DO ikind = 1, nkind
    1411        28036 :          qs_kind => qs_kind_set(ikind)
    1412        28036 :          CALL get_qs_kind(qs_kind=qs_kind, basis_set=basis_set_a, basis_type=basis_type)
    1413        42024 :          IF (ASSOCIATED(basis_set_a)) THEN
    1414        28036 :             basis_set_list(ikind)%gto_basis_set => basis_set_a
    1415              :          ELSE
    1416            0 :             NULLIFY (basis_set_list(ikind)%gto_basis_set)
    1417              :          END IF
    1418              :       END DO
    1419        13988 :       CALL neighbor_list_iterator_create(nl_iterator, sab_orb)
    1420       437964 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
    1421              :          CALL get_iterator_info(nl_iterator, ikind=ikind, jkind=jkind, inode=inode, &
    1422       423976 :                                 iatom=iatom, jatom=jatom, r=rab)
    1423       423976 :          basis_set_a => basis_set_list(ikind)%gto_basis_set
    1424       423976 :          IF (.NOT. ASSOCIATED(basis_set_a)) CYCLE
    1425       423976 :          basis_set_b => basis_set_list(jkind)%gto_basis_set
    1426       423976 :          IF (.NOT. ASSOCIATED(basis_set_b)) CYCLE
    1427              :          ASSOCIATE ( &
    1428              :             ! basis ikind
    1429              :             first_sgfa => basis_set_a%first_sgf, &
    1430              :             la_max => basis_set_a%lmax, &
    1431              :             la_min => basis_set_a%lmin, &
    1432              :             npgfa => basis_set_a%npgf, &
    1433              :             nsgfa => basis_set_a%nsgf_set, &
    1434              :             rpgfa => basis_set_a%pgf_radius, &
    1435              :             set_radius_a => basis_set_a%set_radius, &
    1436              :             sphi_a => basis_set_a%sphi, &
    1437              :             zeta => basis_set_a%zet, &
    1438              :             ! basis jkind, &
    1439              :             first_sgfb => basis_set_b%first_sgf, &
    1440              :             lb_max => basis_set_b%lmax, &
    1441              :             lb_min => basis_set_b%lmin, &
    1442              :             npgfb => basis_set_b%npgf, &
    1443              :             nsgfb => basis_set_b%nsgf_set, &
    1444              :             rpgfb => basis_set_b%pgf_radius, &
    1445              :             set_radius_b => basis_set_b%set_radius, &
    1446              :             sphi_b => basis_set_b%sphi, &
    1447              :             zetb => basis_set_b%zet)
    1448              : 
    1449       423976 :             nseta = basis_set_a%nset
    1450       423976 :             nsetb = basis_set_b%nset
    1451              : 
    1452       423976 :             ldsa = SIZE(sphi_a, 1)
    1453       423976 :             ldsb = SIZE(sphi_b, 1)
    1454              : 
    1455       423976 :             IF (iatom <= jatom) THEN
    1456       245192 :                irow = iatom
    1457       245192 :                icol = jatom
    1458              :             ELSE
    1459       178784 :                irow = jatom
    1460       178784 :                icol = iatom
    1461              :             END IF
    1462              : 
    1463       423976 :             NULLIFY (cblock)
    1464              :             CALL dbcsr_get_block_p(matrix=cosmat, &
    1465       423976 :                                    row=irow, col=icol, BLOCK=cblock, found=found)
    1466       423976 :             NULLIFY (sblock)
    1467              :             CALL dbcsr_get_block_p(matrix=sinmat, &
    1468       423976 :                                    row=irow, col=icol, BLOCK=sblock, found=found)
    1469       423976 :             IF (ASSOCIATED(cblock) .AND. .NOT. ASSOCIATED(sblock) .OR. &
    1470       423976 :                 .NOT. ASSOCIATED(cblock) .AND. ASSOCIATED(sblock)) THEN
    1471            0 :                CPABORT("")
    1472              :             END IF
    1473              : 
    1474      1271928 :             IF (ASSOCIATED(cblock) .AND. ASSOCIATED(sblock)) THEN
    1475              : 
    1476       423976 :                ra(:) = pbc(particle_set(iatom)%r(:), cell)
    1477      1695904 :                rb(:) = ra + rab
    1478       423976 :                dab = SQRT(rab(1)*rab(1) + rab(2)*rab(2) + rab(3)*rab(3))
    1479              : 
    1480      1473026 :                DO iset = 1, nseta
    1481              : 
    1482      1049050 :                   ncoa = npgfa(iset)*ncoset(la_max(iset))
    1483      1049050 :                   sgfa = first_sgfa(1, iset)
    1484              : 
    1485      4999497 :                   DO jset = 1, nsetb
    1486              : 
    1487      3526471 :                      IF (set_radius_a(iset) + set_radius_b(jset) < dab) CYCLE
    1488              : 
    1489      1647871 :                      ncob = npgfb(jset)*ncoset(lb_max(jset))
    1490      1647871 :                      sgfb = first_sgfb(1, jset)
    1491              : 
    1492              :                      ! Calculate the primitive integrals
    1493              :                      CALL cossin(la_max(iset), npgfa(iset), zeta(:, iset), rpgfa(:, iset), la_min(iset), &
    1494              :                                  lb_max(jset), npgfb(jset), zetb(:, jset), rpgfb(:, jset), lb_min(jset), &
    1495      1647871 :                                  ra, rb, kvec, cosab, sinab)
    1496              :                      CALL contract_cossin(cblock, sblock, &
    1497              :                                           iatom, ncoa, nsgfa(iset), sgfa, sphi_a, ldsa, &
    1498              :                                           jatom, ncob, nsgfb(jset), sgfb, sphi_b, ldsb, &
    1499      4575521 :                                           cosab, sinab, ldab, work, ldwork)
    1500              : 
    1501              :                   END DO
    1502              :                END DO
    1503              : 
    1504              :             END IF
    1505              :          END ASSOCIATE
    1506              :       END DO
    1507        13988 :       CALL neighbor_list_iterator_release(nl_iterator)
    1508              : 
    1509        13988 :       DEALLOCATE (cosab)
    1510        13988 :       DEALLOCATE (sinab)
    1511        13988 :       DEALLOCATE (work)
    1512        13988 :       DEALLOCATE (basis_set_list)
    1513              : 
    1514        13988 :       CALL timestop(handle)
    1515              : 
    1516        13988 :    END SUBROUTINE build_berry_moment_matrix
    1517              : 
    1518              : ! **************************************************************************************************
    1519              : !> \brief ...
    1520              : !> \param qs_env ...
    1521              : !> \param cosmat ...
    1522              : !> \param sinmat ...
    1523              : !> \param kvec ...
    1524              : !> \param basis_type ...
    1525              : ! **************************************************************************************************
    1526            0 :    SUBROUTINE build_berry_kpoint_matrix(qs_env, cosmat, sinmat, kvec, basis_type)
    1527              : 
    1528              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1529              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: cosmat, sinmat
    1530              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: kvec
    1531              :       CHARACTER(len=*), OPTIONAL                         :: basis_type
    1532              : 
    1533              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_berry_kpoint_matrix'
    1534              : 
    1535              :       INTEGER :: handle, i, iatom, ic, icol, ikind, inode, irow, iset, jatom, jkind, jset, ldab, &
    1536              :                  ldsa, ldsb, ldwork, natom, ncoa, ncob, nimg, nkind, nseta, nsetb, sgfa, sgfb
    1537              :       INTEGER, DIMENSION(3)                              :: icell
    1538            0 :       INTEGER, DIMENSION(:), POINTER                     :: row_blk_sizes
    1539            0 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    1540              :       LOGICAL                                            :: found, use_cell_mapping
    1541            0 :       REAL(dp), DIMENSION(:, :), POINTER                 :: cblock, cosab, sblock, sinab, work
    1542              :       REAL(KIND=dp)                                      :: dab
    1543              :       REAL(KIND=dp), DIMENSION(3)                        :: ra, rab, rb
    1544              :       TYPE(cell_type), POINTER                           :: cell
    1545              :       TYPE(dbcsr_distribution_type), POINTER             :: dbcsr_dist
    1546              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1547            0 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
    1548              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set, basis_set_a, basis_set_b
    1549              :       TYPE(kpoint_type), POINTER                         :: kpoints
    1550              :       TYPE(neighbor_list_iterator_p_type), &
    1551            0 :          DIMENSION(:), POINTER                           :: nl_iterator
    1552              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    1553            0 :          POINTER                                         :: sab_orb
    1554            0 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1555            0 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1556              :       TYPE(qs_kind_type), POINTER                        :: qs_kind
    1557              :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
    1558              : 
    1559            0 :       CALL timeset(routineN, handle)
    1560              : 
    1561              :       CALL get_qs_env(qs_env, &
    1562              :                       ks_env=ks_env, &
    1563            0 :                       dft_control=dft_control)
    1564            0 :       nimg = dft_control%nimages
    1565            0 :       IF (nimg > 1) THEN
    1566            0 :          CALL get_ks_env(ks_env=ks_env, kpoints=kpoints)
    1567            0 :          CALL get_kpoint_info(kpoint=kpoints, cell_to_index=cell_to_index)
    1568            0 :          use_cell_mapping = .TRUE.
    1569              :       ELSE
    1570              :          use_cell_mapping = .FALSE.
    1571              :       END IF
    1572              : 
    1573              :       CALL get_qs_env(qs_env=qs_env, &
    1574              :                       qs_kind_set=qs_kind_set, &
    1575              :                       particle_set=particle_set, cell=cell, &
    1576            0 :                       sab_orb=sab_orb)
    1577              : 
    1578            0 :       nkind = SIZE(qs_kind_set)
    1579            0 :       natom = SIZE(particle_set)
    1580            0 :       ALLOCATE (basis_set_list(nkind))
    1581            0 :       DO ikind = 1, nkind
    1582            0 :          qs_kind => qs_kind_set(ikind)
    1583            0 :          CALL get_qs_kind(qs_kind=qs_kind, basis_set=basis_set, basis_type=basis_type)
    1584            0 :          IF (ASSOCIATED(basis_set)) THEN
    1585            0 :             basis_set_list(ikind)%gto_basis_set => basis_set
    1586              :          ELSE
    1587            0 :             NULLIFY (basis_set_list(ikind)%gto_basis_set)
    1588              :          END IF
    1589              :       END DO
    1590              : 
    1591            0 :       ALLOCATE (row_blk_sizes(natom))
    1592              :       CALL get_particle_set(particle_set, qs_kind_set, nsgf=row_blk_sizes, &
    1593            0 :                             basis=basis_set_list)
    1594            0 :       CALL get_ks_env(ks_env, dbcsr_dist=dbcsr_dist)
    1595              :       ! (re)allocate matrix sets
    1596            0 :       CALL dbcsr_allocate_matrix_set(sinmat, 1, nimg)
    1597            0 :       CALL dbcsr_allocate_matrix_set(cosmat, 1, nimg)
    1598            0 :       DO i = 1, nimg
    1599              :          ! sin
    1600            0 :          ALLOCATE (sinmat(1, i)%matrix)
    1601              :          CALL dbcsr_create(matrix=sinmat(1, i)%matrix, &
    1602              :                            name="SINMAT", &
    1603              :                            dist=dbcsr_dist, matrix_type=dbcsr_type_symmetric, &
    1604            0 :                            row_blk_size=row_blk_sizes, col_blk_size=row_blk_sizes)
    1605            0 :          CALL cp_dbcsr_alloc_block_from_nbl(sinmat(1, i)%matrix, sab_orb)
    1606            0 :          CALL dbcsr_set(sinmat(1, i)%matrix, 0.0_dp)
    1607              :          ! cos
    1608            0 :          ALLOCATE (cosmat(1, i)%matrix)
    1609              :          CALL dbcsr_create(matrix=cosmat(1, i)%matrix, &
    1610              :                            name="COSMAT", &
    1611              :                            dist=dbcsr_dist, matrix_type=dbcsr_type_symmetric, &
    1612            0 :                            row_blk_size=row_blk_sizes, col_blk_size=row_blk_sizes)
    1613            0 :          CALL cp_dbcsr_alloc_block_from_nbl(cosmat(1, i)%matrix, sab_orb)
    1614            0 :          CALL dbcsr_set(cosmat(1, i)%matrix, 0.0_dp)
    1615              :       END DO
    1616              : 
    1617            0 :       CALL get_qs_kind_set(qs_kind_set=qs_kind_set, maxco=ldwork)
    1618            0 :       ldab = ldwork
    1619            0 :       ALLOCATE (cosab(ldab, ldab))
    1620            0 :       ALLOCATE (sinab(ldab, ldab))
    1621            0 :       ALLOCATE (work(ldwork, ldwork))
    1622              : 
    1623            0 :       CALL neighbor_list_iterator_create(nl_iterator, sab_orb)
    1624            0 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
    1625              :          CALL get_iterator_info(nl_iterator, ikind=ikind, jkind=jkind, inode=inode, &
    1626            0 :                                 iatom=iatom, jatom=jatom, r=rab, cell=icell)
    1627            0 :          basis_set_a => basis_set_list(ikind)%gto_basis_set
    1628            0 :          IF (.NOT. ASSOCIATED(basis_set_a)) CYCLE
    1629            0 :          basis_set_b => basis_set_list(jkind)%gto_basis_set
    1630            0 :          IF (.NOT. ASSOCIATED(basis_set_b)) CYCLE
    1631              :          ASSOCIATE ( &
    1632              :             ! basis ikind
    1633              :             first_sgfa => basis_set_a%first_sgf, &
    1634              :             la_max => basis_set_a%lmax, &
    1635              :             la_min => basis_set_a%lmin, &
    1636              :             npgfa => basis_set_a%npgf, &
    1637              :             nsgfa => basis_set_a%nsgf_set, &
    1638              :             rpgfa => basis_set_a%pgf_radius, &
    1639              :             set_radius_a => basis_set_a%set_radius, &
    1640              :             sphi_a => basis_set_a%sphi, &
    1641              :             zeta => basis_set_a%zet, &
    1642              :             ! basis jkind, &
    1643              :             first_sgfb => basis_set_b%first_sgf, &
    1644              :             lb_max => basis_set_b%lmax, &
    1645              :             lb_min => basis_set_b%lmin, &
    1646              :             npgfb => basis_set_b%npgf, &
    1647              :             nsgfb => basis_set_b%nsgf_set, &
    1648              :             rpgfb => basis_set_b%pgf_radius, &
    1649              :             set_radius_b => basis_set_b%set_radius, &
    1650              :             sphi_b => basis_set_b%sphi, &
    1651            0 :             zetb => basis_set_b%zet)
    1652              : 
    1653            0 :             nseta = basis_set_a%nset
    1654            0 :             nsetb = basis_set_b%nset
    1655              : 
    1656            0 :             ldsa = SIZE(sphi_a, 1)
    1657            0 :             ldsb = SIZE(sphi_b, 1)
    1658              : 
    1659            0 :             IF (iatom <= jatom) THEN
    1660            0 :                irow = iatom
    1661            0 :                icol = jatom
    1662              :             ELSE
    1663            0 :                irow = jatom
    1664            0 :                icol = iatom
    1665              :             END IF
    1666              : 
    1667            0 :             IF (use_cell_mapping) THEN
    1668            0 :                ic = cell_to_index(icell(1), icell(2), icell(3))
    1669            0 :                CPASSERT(ic > 0)
    1670              :             ELSE
    1671              :                ic = 1
    1672              :             END IF
    1673              : 
    1674            0 :             NULLIFY (sblock)
    1675              :             CALL dbcsr_get_block_p(matrix=sinmat(1, ic)%matrix, &
    1676            0 :                                    row=irow, col=icol, BLOCK=sblock, found=found)
    1677            0 :             CPASSERT(found)
    1678            0 :             NULLIFY (cblock)
    1679              :             CALL dbcsr_get_block_p(matrix=cosmat(1, ic)%matrix, &
    1680            0 :                                    row=irow, col=icol, BLOCK=cblock, found=found)
    1681            0 :             CPASSERT(found)
    1682              : 
    1683            0 :             ra(:) = pbc(particle_set(iatom)%r(:), cell)
    1684            0 :             rb(:) = ra + rab
    1685            0 :             dab = SQRT(rab(1)*rab(1) + rab(2)*rab(2) + rab(3)*rab(3))
    1686              : 
    1687            0 :             DO iset = 1, nseta
    1688              : 
    1689            0 :                ncoa = npgfa(iset)*ncoset(la_max(iset))
    1690            0 :                sgfa = first_sgfa(1, iset)
    1691              : 
    1692            0 :                DO jset = 1, nsetb
    1693              : 
    1694            0 :                   IF (set_radius_a(iset) + set_radius_b(jset) < dab) CYCLE
    1695              : 
    1696            0 :                   ncob = npgfb(jset)*ncoset(lb_max(jset))
    1697            0 :                   sgfb = first_sgfb(1, jset)
    1698              : 
    1699              :                   ! Calculate the primitive integrals
    1700              :                   CALL cossin(la_max(iset), npgfa(iset), zeta(:, iset), rpgfa(:, iset), la_min(iset), &
    1701              :                               lb_max(jset), npgfb(jset), zetb(:, jset), rpgfb(:, jset), lb_min(jset), &
    1702            0 :                               ra, rb, kvec, cosab, sinab)
    1703              :                   CALL contract_cossin(cblock, sblock, &
    1704              :                                        iatom, ncoa, nsgfa(iset), sgfa, sphi_a, ldsa, &
    1705              :                                        jatom, ncob, nsgfb(jset), sgfb, sphi_b, ldsb, &
    1706            0 :                                        cosab, sinab, ldab, work, ldwork)
    1707              : 
    1708              :                END DO
    1709              :             END DO
    1710              :          END ASSOCIATE
    1711              :       END DO
    1712            0 :       CALL neighbor_list_iterator_release(nl_iterator)
    1713              : 
    1714            0 :       DEALLOCATE (cosab)
    1715            0 :       DEALLOCATE (sinab)
    1716            0 :       DEALLOCATE (work)
    1717            0 :       DEALLOCATE (basis_set_list)
    1718            0 :       DEALLOCATE (row_blk_sizes)
    1719              : 
    1720            0 :       CALL timestop(handle)
    1721              : 
    1722            0 :    END SUBROUTINE build_berry_kpoint_matrix
    1723              : 
    1724              : ! **************************************************************************************************
    1725              : !> \brief ...
    1726              : !> \param qs_env ...
    1727              : !> \param magnetic ...
    1728              : !> \param nmoments ...
    1729              : !> \param reference ...
    1730              : !> \param ref_point ...
    1731              : !> \param unit_number ...
    1732              : ! **************************************************************************************************
    1733          472 :    SUBROUTINE qs_moment_berry_phase(qs_env, magnetic, nmoments, reference, ref_point, unit_number)
    1734              : 
    1735              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1736              :       LOGICAL, INTENT(IN)                                :: magnetic
    1737              :       INTEGER, INTENT(IN)                                :: nmoments, reference
    1738              :       REAL(dp), DIMENSION(:), POINTER                    :: ref_point
    1739              :       INTEGER, INTENT(IN)                                :: unit_number
    1740              : 
    1741              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'qs_moment_berry_phase'
    1742              : 
    1743          472 :       CHARACTER(LEN=8), ALLOCATABLE, DIMENSION(:)        :: rlab
    1744              :       CHARACTER(LEN=default_string_length)               :: description
    1745              :       COMPLEX(dp)                                        :: xphase(3), zdet, zdeta, zi(3), &
    1746              :                                                             zij(3, 3), zijk(3, 3, 3), &
    1747              :                                                             zijkl(3, 3, 3, 3), zphase(3), zz
    1748              :       INTEGER                                            :: handle, i, ia, idim, ikind, ispin, ix, &
    1749              :                                                             iy, iz, j, k, l, nao, nm, nmo, nmom, &
    1750              :                                                             nmotot, tmp_dim
    1751              :       LOGICAL                                            :: floating, ghost, uniform
    1752              :       REAL(dp)                                           :: charge, ci(3), cij(3, 3), dd, occ, trace
    1753          472 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: mmom
    1754          472 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: rmom
    1755              :       REAL(dp), DIMENSION(3)                             :: kvec, qq, rcc, ria
    1756              :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
    1757              :       TYPE(cell_type), POINTER                           :: cell
    1758          472 :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: eigrmat
    1759              :       TYPE(cp_fm_struct_type), POINTER                   :: tmp_fm_struct
    1760          472 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: opvec
    1761          472 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: op_fm_set
    1762          472 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: mos_new
    1763              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
    1764              :       TYPE(cp_result_type), POINTER                      :: results
    1765          472 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s, rho_ao
    1766              :       TYPE(dbcsr_type), POINTER                          :: cosmat, sinmat
    1767              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1768              :       TYPE(distribution_1d_type), POINTER                :: local_particles
    1769          472 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
    1770              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1771          472 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1772          472 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1773              :       TYPE(qs_rho_type), POINTER                         :: rho
    1774              :       TYPE(rt_prop_type), POINTER                        :: rtp
    1775              : 
    1776            0 :       CPASSERT(ASSOCIATED(qs_env))
    1777              : 
    1778          472 :       IF (ASSOCIATED(qs_env%ls_scf_env)) THEN
    1779            0 :          IF (unit_number > 0) WRITE (unit_number, *) "Periodic moment calculation not implemented in linear scaling code"
    1780            0 :          RETURN
    1781              :       END IF
    1782              : 
    1783          472 :       CALL timeset(routineN, handle)
    1784              : 
    1785              :       ! restrict maximum moment available
    1786          472 :       nmom = MIN(nmoments, 2)
    1787              : 
    1788          472 :       nm = (6 + 11*nmom + 6*nmom**2 + nmom**3)/6 - 1
    1789              :       ! rmom(:,1)=electronic
    1790              :       ! rmom(:,2)=nuclear
    1791              :       ! rmom(:,1)=total
    1792         2360 :       ALLOCATE (rmom(nm + 1, 3))
    1793         1416 :       ALLOCATE (rlab(nm + 1))
    1794         7552 :       rmom = 0.0_dp
    1795         2360 :       rlab = ""
    1796          472 :       IF (magnetic) THEN
    1797            0 :          nm = 3
    1798            0 :          ALLOCATE (mmom(nm))
    1799            0 :          mmom = 0._dp
    1800              :       END IF
    1801              : 
    1802          472 :       NULLIFY (dft_control, rho, cell, particle_set, results, para_env, &
    1803          472 :                local_particles, matrix_s, mos, rho_ao)
    1804              : 
    1805              :       CALL get_qs_env(qs_env, &
    1806              :                       dft_control=dft_control, &
    1807              :                       rho=rho, &
    1808              :                       cell=cell, &
    1809              :                       results=results, &
    1810              :                       particle_set=particle_set, &
    1811              :                       qs_kind_set=qs_kind_set, &
    1812              :                       para_env=para_env, &
    1813              :                       local_particles=local_particles, &
    1814              :                       matrix_s=matrix_s, &
    1815          472 :                       mos=mos)
    1816              : 
    1817          472 :       CALL qs_rho_get(rho, rho_ao=rho_ao)
    1818              : 
    1819          472 :       NULLIFY (cosmat, sinmat)
    1820          472 :       ALLOCATE (cosmat, sinmat)
    1821          472 :       CALL dbcsr_copy(cosmat, matrix_s(1)%matrix, 'COS MOM')
    1822          472 :       CALL dbcsr_copy(sinmat, matrix_s(1)%matrix, 'SIN MOM')
    1823          472 :       CALL dbcsr_set(cosmat, 0.0_dp)
    1824          472 :       CALL dbcsr_set(sinmat, 0.0_dp)
    1825              : 
    1826         2898 :       ALLOCATE (op_fm_set(2, dft_control%nspins))
    1827         1910 :       ALLOCATE (opvec(dft_control%nspins))
    1828         1910 :       ALLOCATE (eigrmat(dft_control%nspins))
    1829          472 :       nmotot = 0
    1830          966 :       DO ispin = 1, dft_control%nspins
    1831          494 :          NULLIFY (tmp_fm_struct, mo_coeff)
    1832          494 :          CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff, nao=nao, nmo=nmo)
    1833          494 :          nmotot = nmotot + nmo
    1834          494 :          CALL cp_fm_create(opvec(ispin), mo_coeff%matrix_struct)
    1835              :          CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nmo, &
    1836          494 :                                   ncol_global=nmo, para_env=para_env, context=mo_coeff%matrix_struct%context)
    1837         1482 :          DO i = 1, SIZE(op_fm_set, 1)
    1838         1482 :             CALL cp_fm_create(op_fm_set(i, ispin), tmp_fm_struct)
    1839              :          END DO
    1840          494 :          CALL cp_cfm_create(eigrmat(ispin), op_fm_set(1, ispin)%matrix_struct)
    1841         1460 :          CALL cp_fm_struct_release(tmp_fm_struct)
    1842              :       END DO
    1843              : 
    1844              :       ! occupation
    1845          966 :       DO ispin = 1, dft_control%nspins
    1846          494 :          CALL get_mo_set(mo_set=mos(ispin), maxocc=occ, uniform_occupation=uniform)
    1847          966 :          IF (.NOT. uniform) THEN
    1848            0 :             CPWARN("Berry phase moments for non uniform MOs' occupation numbers not implemented")
    1849              :          END IF
    1850              :       END DO
    1851              : 
    1852              :       ! reference point
    1853          472 :       CALL get_reference_point(rcc, qs_env=qs_env, reference=reference, ref_point=ref_point)
    1854         1888 :       rcc = pbc(rcc, cell)
    1855              : 
    1856              :       ! label
    1857         1888 :       DO l = 1, nm
    1858         1416 :          ix = indco(1, l + 1)
    1859         1416 :          iy = indco(2, l + 1)
    1860         1416 :          iz = indco(3, l + 1)
    1861         1888 :          CALL set_label(rlab(l + 1), ix, iy, iz)
    1862              :       END DO
    1863              : 
    1864              :       ! nuclear contribution
    1865         1908 :       DO ia = 1, SIZE(particle_set)
    1866         1436 :          atomic_kind => particle_set(ia)%atomic_kind
    1867         1436 :          CALL get_atomic_kind(atomic_kind, kind_number=ikind)
    1868         1436 :          CALL get_qs_kind(qs_kind_set(ikind), core_charge=charge, ghost=ghost, floating=floating)
    1869         1908 :          IF (.NOT. ghost .AND. .NOT. floating) THEN
    1870         1436 :             rmom(1, 2) = rmom(1, 2) - charge
    1871              :          END IF
    1872              :       END DO
    1873         7552 :       ria = twopi*MATMUL(cell%h_inv, rcc)
    1874         1888 :       zphase = CMPLX(COS(ria), SIN(ria), dp)**rmom(1, 2)
    1875              : 
    1876          472 :       zi = 0._dp
    1877          472 :       zij = 0._dp
    1878              :       zijk = 0._dp
    1879              :       zijkl = 0._dp
    1880              : 
    1881          944 :       DO l = 1, nmom
    1882          472 :          SELECT CASE (l)
    1883              :          CASE (1)
    1884              :             ! Dipole
    1885         1888 :             zi(:) = CMPLX(1._dp, 0._dp, dp)
    1886         1908 :             DO ia = 1, SIZE(particle_set)
    1887         1436 :                atomic_kind => particle_set(ia)%atomic_kind
    1888         1436 :                CALL get_atomic_kind(atomic_kind, kind_number=ikind)
    1889         1436 :                CALL get_qs_kind(qs_kind_set(ikind), core_charge=charge, ghost=ghost, floating=floating)
    1890         1908 :                IF (.NOT. ghost .AND. .NOT. floating) THEN
    1891         5744 :                   ria = particle_set(ia)%r
    1892         5744 :                   ria = pbc(ria, cell)
    1893         5744 :                   DO i = 1, 3
    1894        17232 :                      kvec(:) = twopi*cell%h_inv(i, :)
    1895        17232 :                      dd = SUM(kvec(:)*ria(:))
    1896         4308 :                      zdeta = CMPLX(COS(dd), SIN(dd), KIND=dp)**charge
    1897         5744 :                      zi(i) = zi(i)*zdeta
    1898              :                   END DO
    1899              :                END IF
    1900              :             END DO
    1901         1888 :             zi = zi*zphase
    1902         1888 :             ci = AIMAG(LOG(zi))/twopi
    1903         1888 :             qq = AIMAG(LOG(zi))
    1904         7552 :             rmom(2:4, 2) = MATMUL(cell%hmat, ci)
    1905              :          CASE (2)
    1906              :             ! Quadrupole
    1907            0 :             CPABORT("Berry phase moments bigger than 1 not implemented")
    1908            0 :             zij(:, :) = CMPLX(1._dp, 0._dp, dp)
    1909            0 :             DO ia = 1, SIZE(particle_set)
    1910            0 :                atomic_kind => particle_set(ia)%atomic_kind
    1911            0 :                CALL get_atomic_kind(atomic_kind, kind_number=ikind)
    1912            0 :                CALL get_qs_kind(qs_kind_set(ikind), core_charge=charge)
    1913            0 :                ria = particle_set(ia)%r
    1914            0 :                ria = pbc(ria, cell)
    1915            0 :                DO i = 1, 3
    1916            0 :                   DO j = i, 3
    1917            0 :                      kvec(:) = twopi*(cell%h_inv(i, :) + cell%h_inv(j, :))
    1918            0 :                      dd = SUM(kvec(:)*ria(:))
    1919            0 :                      zdeta = CMPLX(COS(dd), SIN(dd), KIND=dp)**charge
    1920            0 :                      zij(i, j) = zij(i, j)*zdeta
    1921            0 :                      zij(j, i) = zij(i, j)
    1922              :                   END DO
    1923              :                END DO
    1924              :             END DO
    1925            0 :             DO i = 1, 3
    1926            0 :                DO j = 1, 3
    1927            0 :                   zij(i, j) = zij(i, j)*zphase(i)*zphase(j)
    1928            0 :                   zz = zij(i, j)/zi(i)/zi(j)
    1929            0 :                   cij(i, j) = AIMAG(LOG(zz))/twopi
    1930              :                END DO
    1931              :             END DO
    1932            0 :             cij = 0.5_dp*cij/twopi/twopi
    1933            0 :             cij = MATMUL(MATMUL(cell%hmat, cij), TRANSPOSE(cell%hmat))
    1934            0 :             DO k = 4, 9
    1935            0 :                ix = indco(1, k + 1)
    1936            0 :                iy = indco(2, k + 1)
    1937            0 :                iz = indco(3, k + 1)
    1938            0 :                IF (ix == 0) THEN
    1939            0 :                   rmom(k + 1, 2) = cij(iy, iz)
    1940            0 :                ELSE IF (iy == 0) THEN
    1941            0 :                   rmom(k + 1, 2) = cij(ix, iz)
    1942            0 :                ELSE IF (iz == 0) THEN
    1943            0 :                   rmom(k + 1, 2) = cij(ix, iy)
    1944              :                END IF
    1945              :             END DO
    1946              :          CASE (3)
    1947              :             ! Octapole
    1948            0 :             CPABORT("Berry phase moments bigger than 2 not implemented")
    1949              :          CASE (4)
    1950              :             ! Hexadecapole
    1951            0 :             CPABORT("Berry phase moments bigger than 3 not implemented")
    1952              :          CASE DEFAULT
    1953          472 :             CPABORT("Berry phase moments bigger than 4 not implemented")
    1954              :          END SELECT
    1955              :       END DO
    1956              : 
    1957              :       ! electronic contribution
    1958              : 
    1959         7552 :       ria = twopi*REAL(nmotot, dp)*occ*MATMUL(cell%h_inv, rcc)
    1960         1888 :       xphase = CMPLX(COS(ria), SIN(ria), dp)
    1961              : 
    1962              :       ! charge
    1963          472 :       trace = 0.0_dp
    1964          966 :       DO ispin = 1, dft_control%nspins
    1965          494 :          CALL dbcsr_dot(rho_ao(ispin)%matrix, matrix_s(1)%matrix, trace)
    1966          966 :          rmom(1, 1) = rmom(1, 1) + trace
    1967              :       END DO
    1968              : 
    1969          472 :       zi = 0._dp
    1970          472 :       zij = 0._dp
    1971              :       zijk = 0._dp
    1972              :       zijkl = 0._dp
    1973              : 
    1974          944 :       DO l = 1, nmom
    1975          472 :          SELECT CASE (l)
    1976              :          CASE (1)
    1977              :             ! Dipole
    1978         1888 :             DO i = 1, 3
    1979         5664 :                kvec(:) = twopi*cell%h_inv(i, :)
    1980         1416 :                CALL build_berry_moment_matrix(qs_env, cosmat, sinmat, kvec)
    1981         1416 :                IF (qs_env%run_rtp) THEN
    1982           48 :                   CALL get_qs_env(qs_env, rtp=rtp)
    1983           48 :                   CALL get_rtp(rtp, mos_new=mos_new)
    1984           48 :                   CALL op_orbbas_rtp(cosmat, sinmat, mos, op_fm_set, mos_new)
    1985              :                ELSE
    1986         1368 :                   CALL op_orbbas(cosmat, sinmat, mos, op_fm_set, opvec)
    1987              :                END IF
    1988         1416 :                zdet = CMPLX(1._dp, 0._dp, dp)
    1989         2898 :                DO ispin = 1, dft_control%nspins
    1990         1482 :                   CALL cp_cfm_get_info(eigrmat(ispin), ncol_local=tmp_dim)
    1991         8232 :                   DO idim = 1, tmp_dim
    1992              :                      eigrmat(ispin)%local_data(:, idim) = &
    1993              :                         CMPLX(op_fm_set(1, ispin)%local_data(:, idim), &
    1994        43734 :                               -op_fm_set(2, ispin)%local_data(:, idim), dp)
    1995              :                   END DO
    1996              :                   ! CALL cp_cfm_lu_decompose(eigrmat(ispin), zdeta)
    1997         1482 :                   CALL cp_cfm_det(eigrmat(ispin), zdeta)
    1998         1482 :                   zdet = zdet*zdeta
    1999         4380 :                   IF (dft_control%nspins == 1) THEN
    2000         1350 :                      zdet = zdet*zdeta
    2001              :                   END IF
    2002              :                END DO
    2003         1888 :                zi(i) = zdet
    2004              :             END DO
    2005         1888 :             zi = zi*xphase
    2006              :          CASE (2)
    2007              :             ! Quadrupole
    2008            0 :             CPABORT("Berry phase moments bigger than 1 not implemented")
    2009            0 :             DO i = 1, 3
    2010            0 :                DO j = i, 3
    2011            0 :                   kvec(:) = twopi*(cell%h_inv(i, :) + cell%h_inv(j, :))
    2012            0 :                   CALL build_berry_moment_matrix(qs_env, cosmat, sinmat, kvec)
    2013            0 :                   IF (qs_env%run_rtp) THEN
    2014            0 :                      CALL get_qs_env(qs_env, rtp=rtp)
    2015            0 :                      CALL get_rtp(rtp, mos_new=mos_new)
    2016            0 :                      CALL op_orbbas_rtp(cosmat, sinmat, mos, op_fm_set, mos_new)
    2017              :                   ELSE
    2018            0 :                      CALL op_orbbas(cosmat, sinmat, mos, op_fm_set, opvec)
    2019              :                   END IF
    2020            0 :                   zdet = CMPLX(1._dp, 0._dp, dp)
    2021            0 :                   DO ispin = 1, dft_control%nspins
    2022            0 :                      CALL cp_cfm_get_info(eigrmat(ispin), ncol_local=tmp_dim)
    2023            0 :                      DO idim = 1, tmp_dim
    2024              :                         eigrmat(ispin)%local_data(:, idim) = &
    2025              :                            CMPLX(op_fm_set(1, ispin)%local_data(:, idim), &
    2026            0 :                                  -op_fm_set(2, ispin)%local_data(:, idim), dp)
    2027              :                      END DO
    2028              :                      ! CALL cp_cfm_lu_decompose(eigrmat(ispin), zdeta)
    2029            0 :                      CALL cp_cfm_det(eigrmat(ispin), zdeta)
    2030            0 :                      zdet = zdet*zdeta
    2031            0 :                      IF (dft_control%nspins == 1) THEN
    2032            0 :                         zdet = zdet*zdeta
    2033              :                      END IF
    2034              :                   END DO
    2035            0 :                   zij(i, j) = zdet*xphase(i)*xphase(j)
    2036            0 :                   zij(j, i) = zdet*xphase(i)*xphase(j)
    2037              :                END DO
    2038              :             END DO
    2039              :          CASE (3)
    2040              :             ! Octapole
    2041            0 :             CPABORT("Berry phase moments bigger than 2 not implemented")
    2042              :          CASE (4)
    2043              :             ! Hexadecapole
    2044            0 :             CPABORT("Berry phase moments bigger than 3 not implemented")
    2045              :          CASE DEFAULT
    2046          472 :             CPABORT("Berry phase moments bigger than 4 not implemented")
    2047              :          END SELECT
    2048              :       END DO
    2049          944 :       DO l = 1, nmom
    2050          472 :          SELECT CASE (l)
    2051              :          CASE (1)
    2052              :             ! Dipole (apply periodic (2 Pi) boundary conditions)
    2053         1888 :             ci = AIMAG(LOG(zi))
    2054         1888 :             DO i = 1, 3
    2055         1416 :                IF (qq(i) + ci(i) > pi) ci(i) = ci(i) - twopi
    2056         1888 :                IF (qq(i) + ci(i) < -pi) ci(i) = ci(i) + twopi
    2057              :             END DO
    2058         8968 :             rmom(2:4, 1) = MATMUL(cell%hmat, ci)/twopi
    2059              :          CASE (2)
    2060              :             ! Quadrupole
    2061            0 :             CPABORT("Berry phase moments bigger than 1 not implemented")
    2062            0 :             DO i = 1, 3
    2063            0 :                DO j = 1, 3
    2064            0 :                   zz = zij(i, j)/zi(i)/zi(j)
    2065            0 :                   cij(i, j) = AIMAG(LOG(zz))/twopi
    2066              :                END DO
    2067              :             END DO
    2068            0 :             cij = 0.5_dp*cij/twopi/twopi
    2069            0 :             cij = MATMUL(MATMUL(cell%hmat, cij), TRANSPOSE(cell%hmat))
    2070            0 :             DO k = 4, 9
    2071            0 :                ix = indco(1, k + 1)
    2072            0 :                iy = indco(2, k + 1)
    2073            0 :                iz = indco(3, k + 1)
    2074            0 :                IF (ix == 0) THEN
    2075            0 :                   rmom(k + 1, 1) = cij(iy, iz)
    2076            0 :                ELSE IF (iy == 0) THEN
    2077            0 :                   rmom(k + 1, 1) = cij(ix, iz)
    2078            0 :                ELSE IF (iz == 0) THEN
    2079            0 :                   rmom(k + 1, 1) = cij(ix, iy)
    2080              :                END IF
    2081              :             END DO
    2082              :          CASE (3)
    2083              :             ! Octapole
    2084            0 :             CPABORT("Berry phase moments bigger than 2 not implemented")
    2085              :          CASE (4)
    2086              :             ! Hexadecapole
    2087            0 :             CPABORT("Berry phase moments bigger than 3 not implemented")
    2088              :          CASE DEFAULT
    2089          472 :             CPABORT("Berry phase moments bigger than 4 not implemented")
    2090              :          END SELECT
    2091              :       END DO
    2092              : 
    2093         2360 :       rmom(:, 3) = rmom(:, 1) + rmom(:, 2)
    2094          472 :       description = "[DIPOLE]"
    2095          472 :       CALL cp_results_erase(results=results, description=description)
    2096              :       CALL put_results(results=results, description=description, &
    2097          472 :                        values=rmom(2:4, 3))
    2098          472 :       IF (magnetic) THEN
    2099            0 :          CALL print_moments(unit_number, nmom, rmom, rlab, rcc, cell, periodic=.TRUE., mmom=mmom)
    2100              :       ELSE
    2101          472 :          CALL print_moments(unit_number, nmom, rmom, rlab, rcc, cell, periodic=.TRUE.)
    2102              :       END IF
    2103              : 
    2104          472 :       DEALLOCATE (rmom)
    2105          472 :       DEALLOCATE (rlab)
    2106          472 :       IF (magnetic) THEN
    2107            0 :          DEALLOCATE (mmom)
    2108              :       END IF
    2109              : 
    2110          472 :       CALL dbcsr_deallocate_matrix(cosmat)
    2111          472 :       CALL dbcsr_deallocate_matrix(sinmat)
    2112              : 
    2113          472 :       CALL cp_fm_release(opvec)
    2114          472 :       CALL cp_fm_release(op_fm_set)
    2115          966 :       DO ispin = 1, dft_control%nspins
    2116          966 :          CALL cp_cfm_release(eigrmat(ispin))
    2117              :       END DO
    2118          472 :       DEALLOCATE (eigrmat)
    2119              : 
    2120          472 :       CALL timestop(handle)
    2121              : 
    2122         1416 :    END SUBROUTINE qs_moment_berry_phase
    2123              : 
    2124              : ! **************************************************************************************************
    2125              : !> \brief ...
    2126              : !> \param cosmat ...
    2127              : !> \param sinmat ...
    2128              : !> \param mos ...
    2129              : !> \param op_fm_set ...
    2130              : !> \param opvec ...
    2131              : ! **************************************************************************************************
    2132         1368 :    SUBROUTINE op_orbbas(cosmat, sinmat, mos, op_fm_set, opvec)
    2133              : 
    2134              :       TYPE(dbcsr_type), POINTER                          :: cosmat, sinmat
    2135              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mos
    2136              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN)      :: op_fm_set
    2137              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(INOUT)      :: opvec
    2138              : 
    2139              :       INTEGER                                            :: i, nao, nmo
    2140              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
    2141              : 
    2142         2778 :       DO i = 1, SIZE(op_fm_set, 2) ! spin
    2143         1410 :          CALL get_mo_set(mo_set=mos(i), nao=nao, mo_coeff=mo_coeff, nmo=nmo)
    2144         1410 :          CALL cp_dbcsr_sm_fm_multiply(cosmat, mo_coeff, opvec(i), ncol=nmo)
    2145              :          CALL parallel_gemm("T", "N", nmo, nmo, nao, 1.0_dp, mo_coeff, opvec(i), 0.0_dp, &
    2146         1410 :                             op_fm_set(1, i))
    2147         1410 :          CALL cp_dbcsr_sm_fm_multiply(sinmat, mo_coeff, opvec(i), ncol=nmo)
    2148              :          CALL parallel_gemm("T", "N", nmo, nmo, nao, 1.0_dp, mo_coeff, opvec(i), 0.0_dp, &
    2149         4188 :                             op_fm_set(2, i))
    2150              :       END DO
    2151              : 
    2152         1368 :    END SUBROUTINE op_orbbas
    2153              : 
    2154              : ! **************************************************************************************************
    2155              : !> \brief ...
    2156              : !> \param cosmat ...
    2157              : !> \param sinmat ...
    2158              : !> \param mos ...
    2159              : !> \param op_fm_set ...
    2160              : !> \param mos_new ...
    2161              : ! **************************************************************************************************
    2162           48 :    SUBROUTINE op_orbbas_rtp(cosmat, sinmat, mos, op_fm_set, mos_new)
    2163              : 
    2164              :       TYPE(dbcsr_type), POINTER                          :: cosmat, sinmat
    2165              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mos
    2166              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN)      :: op_fm_set
    2167              :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: mos_new
    2168              : 
    2169              :       INTEGER                                            :: i, icol, lcol, nao, newdim, nmo
    2170              :       LOGICAL                                            :: double_col, double_row
    2171              :       TYPE(cp_fm_struct_type), POINTER                   :: newstruct, newstruct1
    2172              :       TYPE(cp_fm_type)                                   :: work, work1, work2
    2173              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
    2174              : 
    2175          120 :       DO i = 1, SIZE(op_fm_set, 2) ! spin
    2176           72 :          CALL get_mo_set(mo_set=mos(i), nao=nao, mo_coeff=mo_coeff, nmo=nmo)
    2177           72 :          CALL cp_fm_get_info(mos_new(2*i), ncol_local=lcol, ncol_global=nmo)
    2178           72 :          double_col = .TRUE.
    2179           72 :          double_row = .FALSE.
    2180              :          CALL cp_fm_struct_double(newstruct, &
    2181              :                                   mos_new(2*i)%matrix_struct, &
    2182              :                                   mos_new(2*i)%matrix_struct%context, &
    2183              :                                   double_col, &
    2184           72 :                                   double_row)
    2185              : 
    2186           72 :          CALL cp_fm_create(work, matrix_struct=newstruct)
    2187           72 :          CALL cp_fm_create(work1, matrix_struct=newstruct)
    2188           72 :          CALL cp_fm_create(work2, matrix_struct=newstruct)
    2189           72 :          CALL cp_fm_get_info(work, ncol_global=newdim)
    2190              : 
    2191           72 :          CALL cp_fm_set_all(work, 0.0_dp, 0.0_dp)
    2192          336 :          DO icol = 1, lcol
    2193         3300 :             work%local_data(:, icol) = mos_new(2*i - 1)%local_data(:, icol)
    2194         3372 :             work%local_data(:, icol + lcol) = mos_new(2*i)%local_data(:, icol)
    2195              :          END DO
    2196              : 
    2197           72 :          CALL cp_dbcsr_sm_fm_multiply(cosmat, work, work1, ncol=newdim)
    2198           72 :          CALL cp_dbcsr_sm_fm_multiply(sinmat, work, work2, ncol=newdim)
    2199              : 
    2200          336 :          DO icol = 1, lcol
    2201         3300 :             work%local_data(:, icol) = work1%local_data(:, icol) - work2%local_data(:, icol + lcol)
    2202         3372 :             work%local_data(:, icol + lcol) = work1%local_data(:, icol + lcol) + work2%local_data(:, icol)
    2203              :          END DO
    2204              : 
    2205           72 :          CALL cp_fm_release(work1)
    2206           72 :          CALL cp_fm_release(work2)
    2207              : 
    2208              :          CALL cp_fm_struct_double(newstruct1, &
    2209              :                                   op_fm_set(1, i)%matrix_struct, &
    2210              :                                   op_fm_set(1, i)%matrix_struct%context, &
    2211              :                                   double_col, &
    2212           72 :                                   double_row)
    2213              : 
    2214           72 :          CALL cp_fm_create(work1, matrix_struct=newstruct1)
    2215              : 
    2216              :          CALL parallel_gemm("T", "N", nmo, newdim, nao, 1.0_dp, mos_new(2*i - 1), &
    2217           72 :                             work, 0.0_dp, work1)
    2218              : 
    2219          336 :          DO icol = 1, lcol
    2220          756 :             op_fm_set(1, i)%local_data(:, icol) = work1%local_data(:, icol)
    2221          828 :             op_fm_set(2, i)%local_data(:, icol) = work1%local_data(:, icol + lcol)
    2222              :          END DO
    2223              : 
    2224              :          CALL parallel_gemm("T", "N", nmo, newdim, nao, 1.0_dp, mos_new(2*i), &
    2225           72 :                             work, 0.0_dp, work1)
    2226              : 
    2227          336 :          DO icol = 1, lcol
    2228              :             op_fm_set(1, i)%local_data(:, icol) = &
    2229          756 :                op_fm_set(1, i)%local_data(:, icol) + work1%local_data(:, icol + lcol)
    2230              :             op_fm_set(2, i)%local_data(:, icol) = &
    2231          828 :                op_fm_set(2, i)%local_data(:, icol) - work1%local_data(:, icol)
    2232              :          END DO
    2233              : 
    2234           72 :          CALL cp_fm_release(work)
    2235           72 :          CALL cp_fm_release(work1)
    2236           72 :          CALL cp_fm_struct_release(newstruct)
    2237          336 :          CALL cp_fm_struct_release(newstruct1)
    2238              : 
    2239              :       END DO
    2240              : 
    2241           48 :    END SUBROUTINE op_orbbas_rtp
    2242              : 
    2243              : ! **************************************************************************************************
    2244              : !> \brief ...
    2245              : !> \param qs_env ...
    2246              : !> \param magnetic ...
    2247              : !> \param nmoments ...
    2248              : !> \param reference ...
    2249              : !> \param ref_point ...
    2250              : !> \param unit_number ...
    2251              : !> \param vel_reprs ...
    2252              : !> \param com_nl ...
    2253              : ! **************************************************************************************************
    2254          796 :    SUBROUTINE qs_moment_locop(qs_env, magnetic, nmoments, reference, ref_point, unit_number, vel_reprs, com_nl)
    2255              : 
    2256              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2257              :       LOGICAL, INTENT(IN)                                :: magnetic
    2258              :       INTEGER, INTENT(IN)                                :: nmoments, reference
    2259              :       REAL(dp), DIMENSION(:), INTENT(IN), POINTER        :: ref_point
    2260              :       INTEGER, INTENT(IN)                                :: unit_number
    2261              :       LOGICAL, INTENT(IN), OPTIONAL                      :: vel_reprs, com_nl
    2262              : 
    2263              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'qs_moment_locop'
    2264              : 
    2265          796 :       CHARACTER(LEN=8), ALLOCATABLE, DIMENSION(:)        :: rlab
    2266              :       CHARACTER(LEN=default_string_length)               :: description
    2267              :       INTEGER                                            :: akind, handle, i, ia, iatom, idir, &
    2268              :                                                             ikind, ispin, ix, iy, iz, l, nm, nmom, &
    2269              :                                                             order
    2270              :       LOGICAL                                            :: my_com_nl, my_velreprs
    2271              :       REAL(dp)                                           :: charge, dd, strace, trace
    2272          796 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: mmom, nlcom_rrv, nlcom_rrv_vrr, &
    2273          796 :                                                             nlcom_rv, nlcom_rvr, nlcom_rxrv, &
    2274          796 :                                                             qupole_der, rmom_vel
    2275          796 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: rmom
    2276              :       REAL(dp), DIMENSION(3)                             :: rcc, ria
    2277              :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
    2278              :       TYPE(cell_type), POINTER                           :: cell
    2279              :       TYPE(cp_result_type), POINTER                      :: results
    2280          796 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: magmom, matrix_s, moments, momentum, &
    2281          796 :                                                             rho_ao
    2282          796 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: moments_der
    2283              :       TYPE(dbcsr_type), POINTER                          :: tmp_ao
    2284              :       TYPE(dft_control_type), POINTER                    :: dft_control
    2285              :       TYPE(distribution_1d_type), POINTER                :: local_particles
    2286              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2287              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    2288          796 :          POINTER                                         :: sab_all, sab_orb
    2289          796 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    2290          796 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    2291              :       TYPE(qs_rho_type), POINTER                         :: rho
    2292              : 
    2293            0 :       CPASSERT(ASSOCIATED(qs_env))
    2294              : 
    2295          796 :       CALL timeset(routineN, handle)
    2296              : 
    2297          796 :       my_velreprs = .FALSE.
    2298          796 :       IF (PRESENT(vel_reprs)) my_velreprs = vel_reprs
    2299          796 :       IF (PRESENT(com_nl)) my_com_nl = com_nl
    2300          796 :       IF (my_velreprs) CALL cite_reference(Mattiat2019)
    2301              : 
    2302              :       ! reference point
    2303          796 :       CALL get_reference_point(rcc, qs_env=qs_env, reference=reference, ref_point=ref_point)
    2304              : 
    2305              :       ! only allow for moments up to maxl set by basis
    2306          796 :       nmom = MIN(nmoments, current_maxl)
    2307              :       ! electronic contribution
    2308          796 :       NULLIFY (dft_control, rho, cell, particle_set, qs_kind_set, results, para_env, matrix_s, rho_ao, sab_all, sab_orb)
    2309              :       CALL get_qs_env(qs_env, &
    2310              :                       dft_control=dft_control, &
    2311              :                       rho=rho, &
    2312              :                       cell=cell, &
    2313              :                       results=results, &
    2314              :                       particle_set=particle_set, &
    2315              :                       qs_kind_set=qs_kind_set, &
    2316              :                       para_env=para_env, &
    2317              :                       matrix_s=matrix_s, &
    2318              :                       sab_all=sab_all, &
    2319          796 :                       sab_orb=sab_orb)
    2320              : 
    2321          796 :       IF (my_com_nl) THEN
    2322           28 :          IF ((nmom >= 1) .AND. my_velreprs) THEN
    2323           28 :             ALLOCATE (nlcom_rv(3))
    2324          112 :             nlcom_rv(:) = 0._dp
    2325              :          END IF
    2326           28 :          IF ((nmom >= 2) .AND. my_velreprs) THEN
    2327           28 :             ALLOCATE (nlcom_rrv(6))
    2328          196 :             nlcom_rrv(:) = 0._dp
    2329           28 :             ALLOCATE (nlcom_rvr(6))
    2330          196 :             nlcom_rvr(:) = 0._dp
    2331           28 :             ALLOCATE (nlcom_rrv_vrr(6))
    2332          196 :             nlcom_rrv_vrr(:) = 0._dp
    2333              :          END IF
    2334           28 :          IF (magnetic) THEN
    2335            6 :             ALLOCATE (nlcom_rxrv(3))
    2336           24 :             nlcom_rxrv = 0._dp
    2337              :          END IF
    2338              :          ! Calculate non local correction terms
    2339           28 :          CALL calculate_commutator_nl_terms(qs_env, nlcom_rv, nlcom_rxrv, nlcom_rrv, nlcom_rvr, nlcom_rrv_vrr, rcc)
    2340              :       END IF
    2341              : 
    2342          796 :       NULLIFY (moments)
    2343          796 :       nm = (6 + 11*nmom + 6*nmom**2 + nmom**3)/6 - 1
    2344          796 :       CALL dbcsr_allocate_matrix_set(moments, nm)
    2345         3414 :       DO i = 1, nm
    2346         2618 :          ALLOCATE (moments(i)%matrix)
    2347         2618 :          IF (my_velreprs .AND. (nmom >= 2)) THEN
    2348              :             CALL dbcsr_create(moments(i)%matrix, template=matrix_s(1)%matrix, &
    2349          252 :                               matrix_type=dbcsr_type_symmetric)
    2350          252 :             CALL cp_dbcsr_alloc_block_from_nbl(moments(i)%matrix, sab_orb)
    2351              :          ELSE
    2352         2366 :             CALL dbcsr_copy(moments(i)%matrix, matrix_s(1)%matrix, "Moments")
    2353              :          END IF
    2354         3414 :          CALL dbcsr_set(moments(i)%matrix, 0.0_dp)
    2355              :       END DO
    2356              : 
    2357              :       ! calculate derivatives if quadrupole in vel. reprs. is requested
    2358          796 :       IF (my_velreprs .AND. (nmom >= 2)) THEN
    2359           28 :          NULLIFY (moments_der)
    2360           28 :          CALL dbcsr_allocate_matrix_set(moments_der, 3, 3)
    2361          112 :          DO i = 1, 3 ! x, y, z
    2362          364 :             DO idir = 1, 3 ! d/dx, d/dy, d/dz
    2363          252 :                CALL dbcsr_init_p(moments_der(i, idir)%matrix)
    2364              :                CALL dbcsr_create(moments_der(i, idir)%matrix, template=matrix_s(1)%matrix, &
    2365          252 :                                  matrix_type=dbcsr_type_antisymmetric)
    2366          252 :                CALL cp_dbcsr_alloc_block_from_nbl(moments_der(i, idir)%matrix, sab_orb)
    2367          336 :                CALL dbcsr_set(moments_der(i, idir)%matrix, 0.0_dp)
    2368              :             END DO
    2369              :          END DO
    2370           28 :          CALL build_local_moments_der_matrix(qs_env, moments_der, 1, 2, ref_point=rcc, moments=moments)
    2371              :       ELSE
    2372          768 :          CALL build_local_moment_matrix(qs_env, moments, nmom, ref_point=rcc)
    2373              :       END IF
    2374              : 
    2375          796 :       CALL qs_rho_get(rho, rho_ao=rho_ao)
    2376              : 
    2377         3184 :       ALLOCATE (rmom(nm + 1, 3))
    2378         2388 :       ALLOCATE (rlab(nm + 1))
    2379        13426 :       rmom = 0.0_dp
    2380         4210 :       rlab = ""
    2381              : 
    2382          796 :       IF ((my_velreprs .AND. (nmoments >= 1)) .OR. magnetic) THEN
    2383              :          ! Allocate matrix to store the matrix product to be traced (dbcsr_dot only works for products of
    2384              :          ! symmetric matrices)
    2385           30 :          NULLIFY (tmp_ao)
    2386           30 :          CALL dbcsr_init_p(tmp_ao)
    2387           30 :          CALL dbcsr_create(tmp_ao, template=matrix_s(1)%matrix, matrix_type=dbcsr_type_no_symmetry, name="tmp")
    2388           30 :          CALL cp_dbcsr_alloc_block_from_nbl(tmp_ao, sab_all)
    2389           30 :          CALL dbcsr_set(tmp_ao, 0.0_dp)
    2390              :       END IF
    2391              : 
    2392          796 :       trace = 0.0_dp
    2393         1664 :       DO ispin = 1, dft_control%nspins
    2394          868 :          CALL dbcsr_dot(rho_ao(ispin)%matrix, matrix_s(1)%matrix, trace)
    2395         1664 :          rmom(1, 1) = rmom(1, 1) + trace
    2396              :       END DO
    2397              : 
    2398         3414 :       DO i = 1, SIZE(moments)
    2399         2618 :          strace = 0._dp
    2400         5452 :          DO ispin = 1, dft_control%nspins
    2401         2834 :             IF (my_velreprs .AND. nmoments >= 2) THEN
    2402              :                CALL dbcsr_multiply("T", "N", 1.0_dp, rho_ao(ispin)%matrix, moments(i)%matrix, &
    2403          252 :                                    0.0_dp, tmp_ao)
    2404          252 :                CALL dbcsr_trace(tmp_ao, trace)
    2405              :             ELSE
    2406         2582 :                CALL dbcsr_dot(rho_ao(ispin)%matrix, moments(i)%matrix, trace)
    2407              :             END IF
    2408         5452 :             strace = strace + trace
    2409              :          END DO
    2410         3414 :          rmom(i + 1, 1) = strace
    2411              :       END DO
    2412              : 
    2413          796 :       CALL dbcsr_deallocate_matrix_set(moments)
    2414              : 
    2415              :       ! nuclear contribution
    2416              :       CALL get_qs_env(qs_env=qs_env, &
    2417          796 :                       local_particles=local_particles)
    2418         2488 :       DO ikind = 1, SIZE(local_particles%n_el)
    2419         3726 :          DO ia = 1, local_particles%n_el(ikind)
    2420         1238 :             iatom = local_particles%list(ikind)%array(ia)
    2421              :             ! fold atomic positions back into unit cell
    2422         9904 :             ria = pbc(particle_set(iatom)%r - rcc, cell) + rcc
    2423         4952 :             ria = ria - rcc
    2424         1238 :             atomic_kind => particle_set(iatom)%atomic_kind
    2425         1238 :             CALL get_atomic_kind(atomic_kind, kind_number=akind)
    2426         1238 :             CALL get_qs_kind(qs_kind_set(akind), core_charge=charge)
    2427         1238 :             rmom(1, 2) = rmom(1, 2) - charge
    2428         6923 :             DO l = 1, nm
    2429         3993 :                ix = indco(1, l + 1)
    2430         3993 :                iy = indco(2, l + 1)
    2431         3993 :                iz = indco(3, l + 1)
    2432         3993 :                dd = 1._dp
    2433         3993 :                IF (ix > 0) dd = dd*ria(1)**ix
    2434         3993 :                IF (iy > 0) dd = dd*ria(2)**iy
    2435         3993 :                IF (iz > 0) dd = dd*ria(3)**iz
    2436         3993 :                rmom(l + 1, 2) = rmom(l + 1, 2) - charge*dd
    2437         5231 :                CALL set_label(rlab(l + 1), ix, iy, iz)
    2438              :             END DO
    2439              :          END DO
    2440              :       END DO
    2441          796 :       CALL para_env%sum(rmom(:, 2))
    2442        13426 :       rmom(:, :) = -rmom(:, :)
    2443         4210 :       rmom(:, 3) = rmom(:, 1) + rmom(:, 2)
    2444              : 
    2445              :       ! magnetic moments
    2446          796 :       IF (magnetic) THEN
    2447            8 :          NULLIFY (magmom)
    2448            8 :          CALL dbcsr_allocate_matrix_set(magmom, 3)
    2449           32 :          DO i = 1, SIZE(magmom)
    2450           24 :             CALL dbcsr_init_p(magmom(i)%matrix)
    2451              :             CALL dbcsr_create(magmom(i)%matrix, template=matrix_s(1)%matrix, &
    2452           24 :                               matrix_type=dbcsr_type_antisymmetric)
    2453           24 :             CALL cp_dbcsr_alloc_block_from_nbl(magmom(i)%matrix, sab_orb)
    2454           32 :             CALL dbcsr_set(magmom(i)%matrix, 0.0_dp)
    2455              :          END DO
    2456              : 
    2457            8 :          CALL build_local_magmom_matrix(qs_env, magmom, nmom, ref_point=rcc)
    2458              : 
    2459           24 :          ALLOCATE (mmom(SIZE(magmom)))
    2460           32 :          mmom(:) = 0.0_dp
    2461            8 :          IF (qs_env%run_rtp) THEN
    2462              :             ! get imaginary part of the density in rho_ao (the real part is not needed since the trace of the product
    2463              :             ! of a symmetric (REAL(rho_ao)) and an anti-symmetric (L_AO) matrix is zero)
    2464              :             ! There may be other cases, where the imaginary part of the density is relevant
    2465            4 :             NULLIFY (rho_ao)
    2466            4 :             CALL qs_rho_get(rho, rho_ao_im=rho_ao)
    2467              :          END IF
    2468              :          ! if the density is purely real this is an expensive way to calculate zero
    2469           32 :          DO i = 1, SIZE(magmom)
    2470           24 :             strace = 0._dp
    2471           48 :             DO ispin = 1, dft_control%nspins
    2472           24 :                CALL dbcsr_set(tmp_ao, 0.0_dp)
    2473              :                CALL dbcsr_multiply("T", "N", 1.0_dp, rho_ao(ispin)%matrix, magmom(i)%matrix, &
    2474           24 :                                    0.0_dp, tmp_ao)
    2475           24 :                CALL dbcsr_trace(tmp_ao, trace)
    2476           48 :                strace = strace + trace
    2477              :             END DO
    2478           32 :             mmom(i) = strace
    2479              :          END DO
    2480              : 
    2481            8 :          CALL dbcsr_deallocate_matrix_set(magmom)
    2482              :       END IF
    2483              : 
    2484              :       ! velocity representations
    2485          796 :       IF (my_velreprs) THEN
    2486           84 :          ALLOCATE (rmom_vel(nm))
    2487          280 :          rmom_vel = 0.0_dp
    2488              : 
    2489           84 :          DO order = 1, nmom
    2490           28 :             SELECT CASE (order)
    2491              : 
    2492              :             CASE (1) ! expectation value of momentum
    2493           28 :                NULLIFY (momentum)
    2494           28 :                CALL dbcsr_allocate_matrix_set(momentum, 3)
    2495          112 :                DO i = 1, 3
    2496           84 :                   CALL dbcsr_init_p(momentum(i)%matrix)
    2497              :                   CALL dbcsr_create(momentum(i)%matrix, template=matrix_s(1)%matrix, &
    2498           84 :                                     matrix_type=dbcsr_type_antisymmetric)
    2499           84 :                   CALL cp_dbcsr_alloc_block_from_nbl(momentum(i)%matrix, sab_orb)
    2500          112 :                   CALL dbcsr_set(momentum(i)%matrix, 0.0_dp)
    2501              :                END DO
    2502           28 :                CALL build_lin_mom_matrix(qs_env, momentum)
    2503              : 
    2504              :                ! imaginary part of the density for RTP, real part gives 0 since momentum is antisymmetric
    2505           28 :                IF (qs_env%run_rtp) THEN
    2506           22 :                   NULLIFY (rho_ao)
    2507           22 :                   CALL qs_rho_get(rho, rho_ao_im=rho_ao)
    2508           88 :                   DO idir = 1, SIZE(momentum)
    2509           66 :                      strace = 0._dp
    2510          132 :                      DO ispin = 1, dft_control%nspins
    2511           66 :                         CALL dbcsr_set(tmp_ao, 0.0_dp)
    2512              :                         CALL dbcsr_multiply("T", "N", 1.0_dp, rho_ao(ispin)%matrix, momentum(idir)%matrix, &
    2513           66 :                                             0.0_dp, tmp_ao)
    2514           66 :                         CALL dbcsr_trace(tmp_ao, trace)
    2515          132 :                         strace = strace + trace
    2516              :                      END DO
    2517           88 :                      rmom_vel(idir) = rmom_vel(idir) + strace
    2518              :                   END DO
    2519              :                END IF
    2520              : 
    2521           28 :                CALL dbcsr_deallocate_matrix_set(momentum)
    2522              : 
    2523              :             CASE (2) ! expectation value of quadrupole moment in vel. reprs.
    2524           28 :                ALLOCATE (qupole_der(9)) ! will contain the expectation values of r_\alpha * d/d r_\beta
    2525          280 :                qupole_der = 0._dp
    2526              : 
    2527           28 :                NULLIFY (rho_ao)
    2528           28 :                CALL qs_rho_get(rho, rho_ao=rho_ao)
    2529              : 
    2530              :                ! Calculate expectation value over real part
    2531           28 :                trace = 0._dp
    2532          112 :                DO i = 1, 3
    2533          364 :                   DO idir = 1, 3
    2534          252 :                      strace = 0._dp
    2535          504 :                      DO ispin = 1, dft_control%nspins
    2536          252 :                         CALL dbcsr_set(tmp_ao, 0._dp)
    2537          252 :                         CALL dbcsr_multiply("T", "N", 1._dp, rho_ao(ispin)%matrix, moments_der(i, idir)%matrix, 0._dp, tmp_ao)
    2538          252 :                         CALL dbcsr_trace(tmp_ao, trace)
    2539          504 :                         strace = strace + trace
    2540              :                      END DO
    2541          336 :                      qupole_der((i - 1)*3 + idir) = qupole_der((i - 1)*3 + idir) + strace
    2542              :                   END DO
    2543              :                END DO
    2544              : 
    2545           28 :                IF (qs_env%run_rtp) THEN
    2546           22 :                   NULLIFY (rho_ao)
    2547           22 :                   CALL qs_rho_get(rho, rho_ao_im=rho_ao)
    2548              : 
    2549              :                   ! Calculate expectation value over imaginary part
    2550           22 :                   trace = 0._dp
    2551           88 :                   DO i = 1, 3
    2552          286 :                      DO idir = 1, 3
    2553          198 :                         strace = 0._dp
    2554          396 :                         DO ispin = 1, dft_control%nspins
    2555          198 :                            CALL dbcsr_set(tmp_ao, 0._dp)
    2556          198 :                            CALL dbcsr_multiply("T", "N", 1._dp, rho_ao(ispin)%matrix, moments_der(i, idir)%matrix, 0._dp, tmp_ao)
    2557          198 :                            CALL dbcsr_trace(tmp_ao, trace)
    2558          396 :                            strace = strace + trace
    2559              :                         END DO
    2560          264 :                         qupole_der((i - 1)*3 + idir) = qupole_der((i - 1)*3 + idir) + strace
    2561              :                      END DO
    2562              :                   END DO
    2563              :                END IF
    2564              : 
    2565              :                ! calculate vel. reprs. of quadrupole moment from derivatives
    2566           28 :                rmom_vel(4) = -2*qupole_der(1) - rmom(1, 1)
    2567           28 :                rmom_vel(5) = -qupole_der(2) - qupole_der(4)
    2568           28 :                rmom_vel(6) = -qupole_der(3) - qupole_der(7)
    2569           28 :                rmom_vel(7) = -2*qupole_der(5) - rmom(1, 1)
    2570           28 :                rmom_vel(8) = -qupole_der(6) - qupole_der(8)
    2571           28 :                rmom_vel(9) = -2*qupole_der(9) - rmom(1, 1)
    2572              : 
    2573           84 :                DEALLOCATE (qupole_der)
    2574              :             CASE DEFAULT
    2575              :             END SELECT
    2576              :          END DO
    2577              :       END IF
    2578              : 
    2579          796 :       IF ((my_velreprs .AND. (nmoments >= 1)) .OR. magnetic) THEN
    2580           30 :          CALL dbcsr_deallocate_matrix(tmp_ao)
    2581              :       END IF
    2582          796 :       IF (my_velreprs .AND. (nmoments >= 2)) THEN
    2583           28 :          CALL dbcsr_deallocate_matrix_set(moments_der)
    2584              :       END IF
    2585              : 
    2586          796 :       description = "[DIPOLE]"
    2587          796 :       CALL cp_results_erase(results=results, description=description)
    2588              :       CALL put_results(results=results, description=description, &
    2589          796 :                        values=rmom(2:4, 3))
    2590              : 
    2591          796 :       IF (magnetic .AND. my_velreprs) THEN
    2592            6 :          CALL print_moments(unit_number, nmom, rmom, rlab, rcc, cell, periodic=.FALSE., mmom=mmom, rmom_vel=rmom_vel)
    2593          790 :       ELSE IF (magnetic .AND. .NOT. my_velreprs) THEN
    2594            2 :          CALL print_moments(unit_number, nmom, rmom, rlab, rcc, cell, periodic=.FALSE., mmom=mmom)
    2595          788 :       ELSE IF (my_velreprs .AND. .NOT. magnetic) THEN
    2596           22 :          CALL print_moments(unit_number, nmom, rmom, rlab, rcc, cell, periodic=.FALSE., rmom_vel=rmom_vel)
    2597              :       ELSE
    2598          766 :          CALL print_moments(unit_number, nmom, rmom, rlab, rcc, cell, periodic=.FALSE.)
    2599              :       END IF
    2600              : 
    2601          796 :       IF (my_com_nl) THEN
    2602           28 :          IF (magnetic) THEN
    2603           24 :             mmom(:) = nlcom_rxrv(:)
    2604              :          END IF
    2605           28 :          IF (my_velreprs .AND. (nmom >= 1)) THEN
    2606           28 :             DEALLOCATE (rmom_vel)
    2607           28 :             ALLOCATE (rmom_vel(21))
    2608          112 :             rmom_vel(1:3) = nlcom_rv
    2609              :          END IF
    2610           28 :          IF (my_velreprs .AND. (nmom >= 2)) THEN
    2611          196 :             rmom_vel(4:9) = nlcom_rrv
    2612          196 :             rmom_vel(10:15) = nlcom_rvr
    2613          196 :             rmom_vel(16:21) = nlcom_rrv_vrr
    2614              :          END IF
    2615           28 :          IF (magnetic .AND. .NOT. my_velreprs) THEN
    2616            0 :             CALL print_moments_nl(unit_number, nmom, rlab, mmom=mmom)
    2617           28 :          ELSE IF (my_velreprs .AND. .NOT. magnetic) THEN
    2618           22 :             CALL print_moments_nl(unit_number, nmom, rlab, rmom_vel=rmom_vel)
    2619            6 :          ELSE IF (my_velreprs .AND. magnetic) THEN
    2620            6 :             CALL print_moments_nl(unit_number, nmom, rlab, mmom=mmom, rmom_vel=rmom_vel)
    2621              :          END IF
    2622              : 
    2623              :       END IF
    2624              : 
    2625              :       IF (my_com_nl) THEN
    2626           28 :          IF (nmom >= 1 .AND. my_velreprs) DEALLOCATE (nlcom_rv)
    2627           28 :          IF (nmom >= 2 .AND. my_velreprs) THEN
    2628           28 :             DEALLOCATE (nlcom_rrv)
    2629           28 :             DEALLOCATE (nlcom_rvr)
    2630           28 :             DEALLOCATE (nlcom_rrv_vrr)
    2631              :          END IF
    2632           28 :          IF (magnetic) DEALLOCATE (nlcom_rxrv)
    2633              :       END IF
    2634              : 
    2635          796 :       DEALLOCATE (rmom)
    2636          796 :       DEALLOCATE (rlab)
    2637          796 :       IF (magnetic) THEN
    2638            8 :          DEALLOCATE (mmom)
    2639              :       END IF
    2640          796 :       IF (my_velreprs) THEN
    2641           28 :          DEALLOCATE (rmom_vel)
    2642              :       END IF
    2643              : 
    2644          796 :       CALL timestop(handle)
    2645              : 
    2646         1592 :    END SUBROUTINE qs_moment_locop
    2647              : 
    2648              : ! **************************************************************************************************
    2649              : !> \brief ...
    2650              : !> \param label ...
    2651              : !> \param ix ...
    2652              : !> \param iy ...
    2653              : !> \param iz ...
    2654              : ! **************************************************************************************************
    2655         5409 :    SUBROUTINE set_label(label, ix, iy, iz)
    2656              :       CHARACTER(LEN=*), INTENT(OUT)                      :: label
    2657              :       INTEGER, INTENT(IN)                                :: ix, iy, iz
    2658              : 
    2659              :       INTEGER                                            :: i
    2660              : 
    2661         5409 :       label = ""
    2662         7345 :       DO i = 1, ix
    2663         7345 :          WRITE (label(i:), "(A1)") "X"
    2664              :       END DO
    2665         7345 :       DO i = ix + 1, ix + iy
    2666         7345 :          WRITE (label(i:), "(A1)") "Y"
    2667              :       END DO
    2668         7345 :       DO i = ix + iy + 1, ix + iy + iz
    2669         7345 :          WRITE (label(i:), "(A1)") "Z"
    2670              :       END DO
    2671              : 
    2672         5409 :    END SUBROUTINE set_label
    2673              : 
    2674              : ! **************************************************************************************************
    2675              : !> \brief ...
    2676              : !> \param unit_number ...
    2677              : !> \param nmom ...
    2678              : !> \param rmom ...
    2679              : !> \param rlab ...
    2680              : !> \param rcc ...
    2681              : !> \param cell ...
    2682              : !> \param periodic ...
    2683              : !> \param mmom ...
    2684              : !> \param rmom_vel ...
    2685              : ! **************************************************************************************************
    2686         1268 :    SUBROUTINE print_moments(unit_number, nmom, rmom, rlab, rcc, cell, periodic, mmom, rmom_vel)
    2687              :       INTEGER, INTENT(IN)                                :: unit_number, nmom
    2688              :       REAL(dp), DIMENSION(:, :), INTENT(IN)              :: rmom
    2689              :       CHARACTER(LEN=8), DIMENSION(:)                     :: rlab
    2690              :       REAL(dp), DIMENSION(3), INTENT(IN)                 :: rcc
    2691              :       TYPE(cell_type), POINTER                           :: cell
    2692              :       LOGICAL                                            :: periodic
    2693              :       REAL(dp), DIMENSION(:), INTENT(IN), OPTIONAL       :: mmom, rmom_vel
    2694              : 
    2695              :       INTEGER                                            :: i, i0, i1, j, l
    2696              :       REAL(dp)                                           :: dd
    2697              : 
    2698         1268 :       IF (unit_number > 0) THEN
    2699         1949 :          DO l = 0, nmom
    2700          644 :             SELECT CASE (l)
    2701              :             CASE (0)
    2702          644 :                WRITE (unit_number, "(T3,A,T33,3F16.8)") "Reference Point [Bohr]", rcc
    2703          644 :                WRITE (unit_number, "(T3,A)") "Charges"
    2704              :                WRITE (unit_number, "(T5,A,T18,F14.8,T36,A,T42,F14.8,T60,A,T67,F14.8)") &
    2705          644 :                   "Electronic=", rmom(1, 1), "Core=", rmom(1, 2), "Total=", rmom(1, 3)
    2706              :             CASE (1)
    2707          644 :                IF (periodic) THEN
    2708          246 :                   WRITE (unit_number, "(T3,A)") "Dipole vectors are based on the periodic (Berry phase) operator."
    2709          246 :                   WRITE (unit_number, "(T3,A)") "They are defined modulo integer multiples of the cell matrix [Debye]."
    2710          984 :                   WRITE (unit_number, "(T3,A,3(F14.8,1X),A)") "[X] [", cell%hmat(1, :)*debye, "] [i]"
    2711          984 :                   WRITE (unit_number, "(T3,A,3(F14.8,1X),A)") "[Y]=[", cell%hmat(2, :)*debye, "]*[j]"
    2712          984 :                   WRITE (unit_number, "(T3,A,3(F14.8,1X),A)") "[Z] [", cell%hmat(3, :)*debye, "] [k]"
    2713              :                ELSE
    2714          398 :                   WRITE (unit_number, "(T3,A)") "Dipoles are based on the traditional operator."
    2715              :                END IF
    2716         2576 :                dd = SQRT(SUM(rmom(2:4, 3)**2))*debye
    2717          644 :                WRITE (unit_number, "(T3,A)") "Dipole moment [Debye]"
    2718              :                WRITE (unit_number, "(T5,3(A,A,E15.7,1X),T60,A,T68,F13.7)") &
    2719         2576 :                   (TRIM(rlab(i)), "=", rmom(i, 3)*debye, i=2, 4), "Total=", dd
    2720              :             CASE (2)
    2721           15 :                WRITE (unit_number, "(T3,A)") "Quadrupole moment [Debye*Angstrom]"
    2722              :                WRITE (unit_number, "(T17,3(A,A,E16.8,9X))") &
    2723           60 :                   (TRIM(rlab(i)), "=", rmom(i, 3)*debye/bohr, i=5, 7)
    2724              :                WRITE (unit_number, "(T17,3(A,A,E16.8,9X))") &
    2725           60 :                   (TRIM(rlab(i)), "=", rmom(i, 3)*debye/bohr, i=8, 10)
    2726              :             CASE (3)
    2727            1 :                WRITE (unit_number, "(T3,A)") "Octapole moment [Debye*Angstrom**2]"
    2728              :                WRITE (unit_number, "(T7,4(A,A,F14.8,3X))") &
    2729            5 :                   (TRIM(rlab(i)), "=", rmom(i, 3)*debye/bohr/bohr, i=11, 14)
    2730              :                WRITE (unit_number, "(T7,4(A,A,F14.8,3X))") &
    2731            5 :                   (TRIM(rlab(i)), "=", rmom(i, 3)*debye/bohr/bohr, i=15, 18)
    2732              :                WRITE (unit_number, "(T7,4(A,A,F14.8,3X))") &
    2733            3 :                   (TRIM(rlab(i)), "=", rmom(i, 3)*debye/bohr/bohr, i=19, 20)
    2734              :             CASE (4)
    2735            1 :                WRITE (unit_number, "(T3,A)") "Hexadecapole moment [Debye*Angstrom**3]"
    2736              :                WRITE (unit_number, "(T6,4(A,A,F14.8,2X))") &
    2737            5 :                   (TRIM(rlab(i)), "=", rmom(i, 3)*debye/bohr/bohr/bohr, i=21, 24)
    2738              :                WRITE (unit_number, "(T6,4(A,A,F14.8,2X))") &
    2739            5 :                   (TRIM(rlab(i)), "=", rmom(i, 3)*debye/bohr/bohr/bohr, i=25, 28)
    2740              :                WRITE (unit_number, "(T6,4(A,A,F14.8,2X))") &
    2741            5 :                   (TRIM(rlab(i)), "=", rmom(i, 3)*debye/bohr/bohr/bohr, i=29, 32)
    2742              :                WRITE (unit_number, "(T6,4(A,A,F14.8,2X))") &
    2743            5 :                   (TRIM(rlab(i)), "=", rmom(i, 3)*debye/bohr/bohr/bohr, i=32, 35)
    2744              :             CASE DEFAULT
    2745            0 :                WRITE (unit_number, "(T3,A,A,I2)") "Higher moment [Debye*Angstrom**(L-1)]", &
    2746            0 :                   "  L=", l
    2747            0 :                i0 = (6 + 11*(l - 1) + 6*(l - 1)**2 + (l - 1)**3)/6
    2748            0 :                i1 = (6 + 11*l + 6*l**2 + l**3)/6 - 1
    2749            0 :                dd = debye/(bohr)**(l - 1)
    2750         1305 :                DO i = i0, i1, 3
    2751              :                   WRITE (unit_number, "(T18,3(A,A,F14.8,4X))") &
    2752            0 :                      (TRIM(rlab(j + 1)), "=", rmom(j + 1, 3)*dd, j=i, MIN(i1, i + 2))
    2753              :                END DO
    2754              :             END SELECT
    2755              :          END DO
    2756          644 :          IF (PRESENT(mmom)) THEN
    2757            4 :             IF (nmom >= 1) THEN
    2758           16 :                dd = SQRT(SUM(mmom(1:3)**2))
    2759            4 :                WRITE (unit_number, "(T3,A)") "Orbital angular momentum [a. u.]"
    2760              :                WRITE (unit_number, "(T5,3(A,A,E16.8,1X),T64,A,T71,F14.8)") &
    2761           16 :                   (TRIM(rlab(i + 1)), "=", mmom(i), i=1, 3), "Total=", dd
    2762              :             END IF
    2763              :          END IF
    2764          644 :          IF (PRESENT(rmom_vel)) THEN
    2765           42 :             DO l = 1, nmom
    2766           14 :                SELECT CASE (l)
    2767              :                CASE (1)
    2768           56 :                   dd = SQRT(SUM(rmom_vel(1:3)**2))
    2769           14 :                   WRITE (unit_number, "(T3,A)") "Expectation value of momentum operator [a. u.]"
    2770              :                   WRITE (unit_number, "(T5,3(A,A,E16.8,1X),T64,A,T71,F14.8)") &
    2771           56 :                      (TRIM(rlab(i + 1)), "=", rmom_vel(i), i=1, 3), "Total=", dd
    2772              :                CASE (2)
    2773           14 :                   WRITE (unit_number, "(T3,A)") "Expectation value of quadrupole operator in vel. repr. [a. u.]"
    2774              :                   WRITE (unit_number, "(T17,3(A,A,E16.8,9X))") &
    2775           56 :                      (TRIM(rlab(i + 1)), "=", rmom_vel(i), i=4, 6)
    2776              :                   WRITE (unit_number, "(T17,3(A,A,E16.8,9X))") &
    2777           84 :                      (TRIM(rlab(i + 1)), "=", rmom_vel(i), i=7, 9)
    2778              :                CASE DEFAULT
    2779              :                END SELECT
    2780              :             END DO
    2781              :          END IF
    2782              :       END IF
    2783              : 
    2784         1268 :    END SUBROUTINE print_moments
    2785              : 
    2786              : ! **************************************************************************************************
    2787              : !> \brief ...
    2788              : !> \param unit_number ...
    2789              : !> \param nmom ...
    2790              : !> \param rlab ...
    2791              : !> \param mmom ...
    2792              : !> \param rmom_vel ...
    2793              : ! **************************************************************************************************
    2794           28 :    SUBROUTINE print_moments_nl(unit_number, nmom, rlab, mmom, rmom_vel)
    2795              :       INTEGER, INTENT(IN)                                :: unit_number, nmom
    2796              :       CHARACTER(LEN=8), DIMENSION(:)                     :: rlab
    2797              :       REAL(dp), DIMENSION(:), INTENT(IN), OPTIONAL       :: mmom, rmom_vel
    2798              : 
    2799              :       INTEGER                                            :: i, l
    2800              :       REAL(dp)                                           :: dd
    2801              : 
    2802           28 :       IF (unit_number > 0) THEN
    2803           14 :          IF (PRESENT(mmom)) THEN
    2804            3 :             IF (nmom >= 1) THEN
    2805           12 :                dd = SQRT(SUM(mmom(1:3)**2))
    2806            3 :                WRITE (unit_number, "(T3,A)") "Expectation value of rx[r,V_nl] [a. u.]"
    2807              :                WRITE (unit_number, "(T5,3(A,A,E16.8,1X),T64,A,T71,F14.8)") &
    2808           12 :                   (TRIM(rlab(i + 1)), "=", mmom(i), i=1, 3), "Total=", dd
    2809              :             END IF
    2810              :          END IF
    2811           14 :          IF (PRESENT(rmom_vel)) THEN
    2812           42 :             DO l = 1, nmom
    2813           14 :                SELECT CASE (l)
    2814              :                CASE (1)
    2815           56 :                   dd = SQRT(SUM(rmom_vel(1:3)**2))
    2816           14 :                   WRITE (unit_number, "(T3,A)") "Expectation value of [r,V_nl] [a. u.]"
    2817              :                   WRITE (unit_number, "(T5,3(A,A,E16.8,1X),T64,A,T71,F14.8)") &
    2818           56 :                      (TRIM(rlab(i + 1)), "=", rmom_vel(i), i=1, 3), "Total=", dd
    2819              :                CASE (2)
    2820           14 :                   WRITE (unit_number, "(T3,A)") "Expectation value of [rr,V_nl] [a. u.]"
    2821              :                   WRITE (unit_number, "(T17,3(A,A,E16.8,9X))") &
    2822           56 :                      (TRIM(rlab(i + 1)), "=", rmom_vel(i), i=4, 6)
    2823              :                   WRITE (unit_number, "(T17,3(A,A,E16.8,9X))") &
    2824           56 :                      (TRIM(rlab(i + 1)), "=", rmom_vel(i), i=7, 9)
    2825           14 :                   WRITE (unit_number, "(T3,A)") "Expectation value of r x V_nl x r [a. u.]"
    2826              :                   WRITE (unit_number, "(T17,3(A,A,E16.8,9X))") &
    2827           56 :                      (TRIM(rlab(i + 1 - 6)), "=", rmom_vel(i), i=10, 12)
    2828              :                   WRITE (unit_number, "(T17,3(A,A,E16.8,9X))") &
    2829           56 :                      (TRIM(rlab(i + 1 - 6)), "=", rmom_vel(i), i=13, 15)
    2830           14 :                   WRITE (unit_number, "(T3,A)") "Expectation value of r x r x V_nl + V_nl x r x r [a. u.]"
    2831              :                   WRITE (unit_number, "(T17,3(A,A,E16.8,9X))") &
    2832           56 :                      (TRIM(rlab(i + 1 - 12)), "=", rmom_vel(i), i=16, 18)
    2833              :                   WRITE (unit_number, "(T17,3(A,A,E16.8,9X))") &
    2834           84 :                      (TRIM(rlab(i + 1 - 12)), "=", rmom_vel(i), i=19, 21)
    2835              :                CASE DEFAULT
    2836              :                END SELECT
    2837              :             END DO
    2838              :          END IF
    2839              :       END IF
    2840              : 
    2841           28 :    END SUBROUTINE print_moments_nl
    2842              : 
    2843              : ! **************************************************************************************************
    2844              : !> \brief Calculate the expectation value of operators related to non-local potential:
    2845              : !>        [r, Vnl], noted rv
    2846              : !>        r x [r,Vnl], noted rxrv
    2847              : !>        [rr,Vnl], noted rrv
    2848              : !>        r x Vnl x r, noted rvr
    2849              : !>        r x r x Vnl + Vnl x r x r, noted rrv_vrr
    2850              : !>        Note that the 3 first operator are commutator while the 2 last
    2851              : !>        are not. For reading clarity the same notation is used for all 5
    2852              : !>        operators.
    2853              : !> \param qs_env ...
    2854              : !> \param nlcom_rv ...
    2855              : !> \param nlcom_rxrv ...
    2856              : !> \param nlcom_rrv ...
    2857              : !> \param nlcom_rvr ...
    2858              : !> \param nlcom_rrv_vrr ...
    2859              : !> \param ref_point ...
    2860              : ! **************************************************************************************************
    2861           28 :    SUBROUTINE calculate_commutator_nl_terms(qs_env, nlcom_rv, nlcom_rxrv, nlcom_rrv, nlcom_rvr, &
    2862              :                                             nlcom_rrv_vrr, ref_point)
    2863              : 
    2864              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2865              :       REAL(dp), ALLOCATABLE, DIMENSION(:), OPTIONAL      :: nlcom_rv, nlcom_rxrv, nlcom_rrv, &
    2866              :                                                             nlcom_rvr, nlcom_rrv_vrr
    2867              :       REAL(dp), DIMENSION(3)                             :: ref_point
    2868              : 
    2869              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_commutator_nl_terms'
    2870              : 
    2871              :       INTEGER                                            :: handle, ind, ispin
    2872              :       LOGICAL                                            :: calc_rrv, calc_rrv_vrr, calc_rv, &
    2873              :                                                             calc_rvr, calc_rxrv
    2874              :       REAL(dp)                                           :: eps_ppnl, strace, trace
    2875              :       TYPE(cell_type), POINTER                           :: cell
    2876           28 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_rrv, matrix_rrv_vrr, matrix_rv, &
    2877           28 :                                                             matrix_rvr, matrix_rxrv, matrix_s, &
    2878           28 :                                                             rho_ao
    2879              :       TYPE(dbcsr_type), POINTER                          :: tmp_ao
    2880              :       TYPE(dft_control_type), POINTER                    :: dft_control
    2881              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    2882           28 :          POINTER                                         :: sab_all, sab_orb, sap_ppnl
    2883           28 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    2884           28 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    2885              :       TYPE(qs_rho_type), POINTER                         :: rho
    2886              : 
    2887           28 :       CALL timeset(routineN, handle)
    2888              : 
    2889           28 :       calc_rv = .FALSE.
    2890           28 :       calc_rxrv = .FALSE.
    2891           28 :       calc_rrv = .FALSE.
    2892           28 :       calc_rvr = .FALSE.
    2893           28 :       calc_rrv_vrr = .FALSE.
    2894              : 
    2895              :       ! rv, rxrv and rrv are commutator matrices: anti-symmetric.
    2896              :       ! The real part of the density matrix rho_ao is symmetric so that
    2897              :       ! the expectation value of real density matrix is zero. Hence, if
    2898              :       ! the density matrix is real, no need to compute these quantities.
    2899              :       ! This is not the case for rvr and rrv_vrr which are symmetric.
    2900              : 
    2901           28 :       IF (ALLOCATED(nlcom_rv)) THEN
    2902          112 :          nlcom_rv(:) = 0._dp
    2903           28 :          IF (qs_env%run_rtp) calc_rv = .TRUE.
    2904              :       END IF
    2905           28 :       IF (ALLOCATED(nlcom_rxrv)) THEN
    2906           24 :          nlcom_rxrv(:) = 0._dp
    2907            6 :          IF (qs_env%run_rtp) calc_rxrv = .TRUE.
    2908              :       END IF
    2909           28 :       IF (ALLOCATED(nlcom_rrv)) THEN
    2910          196 :          nlcom_rrv(:) = 0._dp
    2911           28 :          IF (qs_env%run_rtp) calc_rrv = .TRUE.
    2912              :       END IF
    2913           28 :       IF (ALLOCATED(nlcom_rvr)) THEN
    2914          196 :          nlcom_rvr(:) = 0._dp
    2915              :          calc_rvr = .TRUE.
    2916              :       END IF
    2917           28 :       IF (ALLOCATED(nlcom_rrv_vrr)) THEN
    2918          196 :          nlcom_rrv_vrr(:) = 0._dp
    2919              :          calc_rrv_vrr = .TRUE.
    2920              :       END IF
    2921              : 
    2922           28 :       IF (.NOT. (calc_rv .OR. calc_rrv .OR. calc_rxrv &
    2923            0 :                  .OR. calc_rvr .OR. calc_rrv_vrr)) RETURN
    2924              : 
    2925           28 :       NULLIFY (cell, matrix_s, particle_set, qs_kind_set, rho, sab_all, sab_orb, sap_ppnl)
    2926              :       CALL get_qs_env(qs_env, &
    2927              :                       cell=cell, &
    2928              :                       dft_control=dft_control, &
    2929              :                       matrix_s=matrix_s, &
    2930              :                       particle_set=particle_set, &
    2931              :                       qs_kind_set=qs_kind_set, &
    2932              :                       rho=rho, &
    2933              :                       sab_orb=sab_orb, &
    2934              :                       sab_all=sab_all, &
    2935           28 :                       sap_ppnl=sap_ppnl)
    2936              : 
    2937           28 :       eps_ppnl = dft_control%qs_control%eps_ppnl
    2938              : 
    2939              :       ! Allocate storage
    2940           28 :       NULLIFY (matrix_rv, matrix_rxrv, matrix_rrv, matrix_rvr, matrix_rrv_vrr)
    2941           28 :       IF (calc_rv) THEN
    2942           22 :          CALL dbcsr_allocate_matrix_set(matrix_rv, 3)
    2943           88 :          DO ind = 1, 3
    2944           66 :             CALL dbcsr_init_p(matrix_rv(ind)%matrix)
    2945              :             CALL dbcsr_create(matrix_rv(ind)%matrix, template=matrix_s(1)%matrix, &
    2946           66 :                               matrix_type=dbcsr_type_antisymmetric)
    2947           66 :             CALL cp_dbcsr_alloc_block_from_nbl(matrix_rv(ind)%matrix, sab_orb)
    2948           88 :             CALL dbcsr_set(matrix_rv(ind)%matrix, 0._dp)
    2949              :          END DO
    2950              :       END IF
    2951              : 
    2952           28 :       IF (calc_rxrv) THEN
    2953            4 :          CALL dbcsr_allocate_matrix_set(matrix_rxrv, 3)
    2954           16 :          DO ind = 1, 3
    2955           12 :             CALL dbcsr_init_p(matrix_rxrv(ind)%matrix)
    2956              :             CALL dbcsr_create(matrix_rxrv(ind)%matrix, template=matrix_s(1)%matrix, &
    2957           12 :                               matrix_type=dbcsr_type_antisymmetric)
    2958           12 :             CALL cp_dbcsr_alloc_block_from_nbl(matrix_rxrv(ind)%matrix, sab_orb)
    2959           16 :             CALL dbcsr_set(matrix_rxrv(ind)%matrix, 0._dp)
    2960              :          END DO
    2961              :       END IF
    2962              : 
    2963           28 :       IF (calc_rrv) THEN
    2964           22 :          CALL dbcsr_allocate_matrix_set(matrix_rrv, 6)
    2965          154 :          DO ind = 1, 6
    2966          132 :             CALL dbcsr_init_p(matrix_rrv(ind)%matrix)
    2967              :             CALL dbcsr_create(matrix_rrv(ind)%matrix, template=matrix_s(1)%matrix, &
    2968          132 :                               matrix_type=dbcsr_type_antisymmetric)
    2969          132 :             CALL cp_dbcsr_alloc_block_from_nbl(matrix_rrv(ind)%matrix, sab_orb)
    2970          154 :             CALL dbcsr_set(matrix_rrv(ind)%matrix, 0._dp)
    2971              :          END DO
    2972              :       END IF
    2973              : 
    2974           28 :       IF (calc_rvr) THEN
    2975           28 :          CALL dbcsr_allocate_matrix_set(matrix_rvr, 6)
    2976          196 :          DO ind = 1, 6
    2977          168 :             CALL dbcsr_init_p(matrix_rvr(ind)%matrix)
    2978              :             CALL dbcsr_create(matrix_rvr(ind)%matrix, template=matrix_s(1)%matrix, &
    2979          168 :                               matrix_type=dbcsr_type_symmetric)
    2980          168 :             CALL cp_dbcsr_alloc_block_from_nbl(matrix_rvr(ind)%matrix, sab_orb)
    2981          196 :             CALL dbcsr_set(matrix_rvr(ind)%matrix, 0._dp)
    2982              :          END DO
    2983              :       END IF
    2984           28 :       IF (calc_rrv_vrr) THEN
    2985           28 :          CALL dbcsr_allocate_matrix_set(matrix_rrv_vrr, 6)
    2986          196 :          DO ind = 1, 6
    2987          168 :             CALL dbcsr_init_p(matrix_rrv_vrr(ind)%matrix)
    2988              :             CALL dbcsr_create(matrix_rrv_vrr(ind)%matrix, template=matrix_s(1)%matrix, &
    2989          168 :                               matrix_type=dbcsr_type_symmetric)
    2990          168 :             CALL cp_dbcsr_alloc_block_from_nbl(matrix_rrv_vrr(ind)%matrix, sab_orb)
    2991          196 :             CALL dbcsr_set(matrix_rrv_vrr(ind)%matrix, 0._dp)
    2992              :          END DO
    2993              :       END IF
    2994              : 
    2995              :       ! calculate evaluation of operators in AO basis set
    2996              :       CALL build_com_mom_nl(qs_kind_set, sab_orb, sap_ppnl, eps_ppnl, particle_set, cell, matrix_rv=matrix_rv, &
    2997              :                             matrix_rxrv=matrix_rxrv, matrix_rrv=matrix_rrv, matrix_rvr=matrix_rvr, &
    2998           28 :                             matrix_rrv_vrr=matrix_rrv_vrr, ref_point=ref_point)
    2999              : 
    3000              :       ! Calculate expectation values
    3001              :       ! Real part
    3002           28 :       NULLIFY (tmp_ao)
    3003           28 :       CALL dbcsr_init_p(tmp_ao)
    3004           28 :       CALL dbcsr_create(tmp_ao, template=matrix_s(1)%matrix, matrix_type=dbcsr_type_no_symmetry, name="tmp")
    3005           28 :       CALL cp_dbcsr_alloc_block_from_nbl(tmp_ao, sab_all)
    3006           28 :       CALL dbcsr_set(tmp_ao, 0.0_dp)
    3007              : 
    3008           28 :       IF (calc_rvr .OR. calc_rrv_vrr) THEN
    3009           28 :          NULLIFY (rho_ao)
    3010           28 :          CALL qs_rho_get(rho, rho_ao=rho_ao)
    3011              : 
    3012           28 :          IF (calc_rvr) THEN
    3013           28 :             trace = 0._dp
    3014          196 :             DO ind = 1, SIZE(matrix_rvr)
    3015          168 :                strace = 0._dp
    3016          336 :                DO ispin = 1, dft_control%nspins
    3017          168 :                   CALL dbcsr_set(tmp_ao, 0.0_dp)
    3018              :                   CALL dbcsr_multiply("T", "N", 1.0_dp, rho_ao(ispin)%matrix, matrix_rvr(ind)%matrix, &
    3019          168 :                                       0.0_dp, tmp_ao)
    3020          168 :                   CALL dbcsr_trace(tmp_ao, trace)
    3021          336 :                   strace = strace + trace
    3022              :                END DO
    3023          196 :                nlcom_rvr(ind) = nlcom_rvr(ind) + strace
    3024              :             END DO
    3025              :          END IF
    3026              : 
    3027           28 :          IF (calc_rrv_vrr) THEN
    3028           28 :             trace = 0._dp
    3029          196 :             DO ind = 1, SIZE(matrix_rrv_vrr)
    3030          168 :                strace = 0._dp
    3031          336 :                DO ispin = 1, dft_control%nspins
    3032          168 :                   CALL dbcsr_set(tmp_ao, 0.0_dp)
    3033              :                   CALL dbcsr_multiply("T", "N", 1.0_dp, rho_ao(ispin)%matrix, matrix_rrv_vrr(ind)%matrix, &
    3034          168 :                                       0.0_dp, tmp_ao)
    3035          168 :                   CALL dbcsr_trace(tmp_ao, trace)
    3036          336 :                   strace = strace + trace
    3037              :                END DO
    3038          196 :                nlcom_rrv_vrr(ind) = nlcom_rrv_vrr(ind) + strace
    3039              :             END DO
    3040              :          END IF
    3041              :       END IF
    3042              : 
    3043              :       ! imagninary part of the density matrix
    3044           28 :       NULLIFY (rho_ao)
    3045           28 :       CALL qs_rho_get(rho, rho_ao_im=rho_ao)
    3046              : 
    3047           28 :       IF (calc_rv) THEN
    3048           22 :          trace = 0._dp
    3049           88 :          DO ind = 1, SIZE(matrix_rv)
    3050           66 :             strace = 0._dp
    3051          132 :             DO ispin = 1, dft_control%nspins
    3052           66 :                CALL dbcsr_set(tmp_ao, 0.0_dp)
    3053              :                CALL dbcsr_multiply("T", "N", 1.0_dp, rho_ao(ispin)%matrix, matrix_rv(ind)%matrix, &
    3054           66 :                                    0.0_dp, tmp_ao)
    3055           66 :                CALL dbcsr_trace(tmp_ao, trace)
    3056          132 :                strace = strace + trace
    3057              :             END DO
    3058           88 :             nlcom_rv(ind) = nlcom_rv(ind) + strace
    3059              :          END DO
    3060              :       END IF
    3061              : 
    3062           28 :       IF (calc_rrv) THEN
    3063           22 :          trace = 0._dp
    3064          154 :          DO ind = 1, SIZE(matrix_rrv)
    3065          132 :             strace = 0._dp
    3066          264 :             DO ispin = 1, dft_control%nspins
    3067          132 :                CALL dbcsr_set(tmp_ao, 0.0_dp)
    3068              :                CALL dbcsr_multiply("T", "N", 1.0_dp, rho_ao(ispin)%matrix, matrix_rrv(ind)%matrix, &
    3069          132 :                                    0.0_dp, tmp_ao)
    3070          132 :                CALL dbcsr_trace(tmp_ao, trace)
    3071          264 :                strace = strace + trace
    3072              :             END DO
    3073          154 :             nlcom_rrv(ind) = nlcom_rrv(ind) + strace
    3074              :          END DO
    3075              :       END IF
    3076              : 
    3077           28 :       IF (calc_rxrv) THEN
    3078            4 :          trace = 0._dp
    3079           16 :          DO ind = 1, SIZE(matrix_rxrv)
    3080           12 :             strace = 0._dp
    3081           24 :             DO ispin = 1, dft_control%nspins
    3082           12 :                CALL dbcsr_set(tmp_ao, 0.0_dp)
    3083              :                CALL dbcsr_multiply("T", "N", 1.0_dp, rho_ao(ispin)%matrix, matrix_rxrv(ind)%matrix, &
    3084           12 :                                    0.0_dp, tmp_ao)
    3085           12 :                CALL dbcsr_trace(tmp_ao, trace)
    3086           24 :                strace = strace + trace
    3087              :             END DO
    3088           16 :             nlcom_rxrv(ind) = nlcom_rxrv(ind) + strace
    3089              :          END DO
    3090              :       END IF
    3091           28 :       CALL dbcsr_deallocate_matrix(tmp_ao)
    3092           28 :       IF (calc_rv) CALL dbcsr_deallocate_matrix_set(matrix_rv)
    3093           28 :       IF (calc_rxrv) CALL dbcsr_deallocate_matrix_set(matrix_rxrv)
    3094           28 :       IF (calc_rrv) CALL dbcsr_deallocate_matrix_set(matrix_rrv)
    3095           28 :       IF (calc_rvr) CALL dbcsr_deallocate_matrix_set(matrix_rvr)
    3096           28 :       IF (calc_rrv_vrr) CALL dbcsr_deallocate_matrix_set(matrix_rrv_vrr)
    3097              : 
    3098           28 :       CALL timestop(handle)
    3099           28 :    END SUBROUTINE calculate_commutator_nl_terms
    3100              : 
    3101              : ! *****************************************************************************
    3102              : !> \brief ...
    3103              : !> \param qs_env ...
    3104              : !> \param difdip ...
    3105              : !> \param deltaR ...
    3106              : !> \param order ...
    3107              : !> \param rcc ...
    3108              : !> \note calculate matrix elements <a|r_beta |db/dR_alpha > + <da/dR_alpha | r_beta | b >
    3109              : !> be aware: < a | r_beta| db/dR_alpha > = - < da/dR_alpha | r_beta | b > only valid
    3110              : !>           if alpha .neq.beta
    3111              : !> if alpha=beta: < a | r_beta| db/dR_alpha > = - < da/dR_alpha | r_beta | b > - < a | b >
    3112              : !> modified from qs_efield_mo_derivatives
    3113              : !> SL July 2015
    3114              : ! **************************************************************************************************
    3115          504 :    SUBROUTINE dipole_deriv_ao(qs_env, difdip, deltaR, order, rcc)
    3116              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    3117              :       TYPE(dbcsr_p_type), DIMENSION(:, :), &
    3118              :          INTENT(INOUT), POINTER                          :: difdip
    3119              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
    3120              :          POINTER                                         :: deltaR
    3121              :       INTEGER, INTENT(IN)                                :: order
    3122              :       REAL(KIND=dp), DIMENSION(3), OPTIONAL              :: rcc
    3123              : 
    3124              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'dipole_deriv_ao'
    3125              : 
    3126              :       INTEGER :: handle, i, iatom, icol, idir, ikind, inode, irow, iset, j, jatom, jkind, jset, &
    3127              :                  last_jatom, lda, ldab, ldb, M_dim, maxsgf, natom, ncoa, ncob, nkind, nseta, nsetb, sgfa, &
    3128              :                  sgfb
    3129          504 :       INTEGER, DIMENSION(:), POINTER                     :: la_max, la_min, lb_max, lb_min, npgfa, &
    3130          504 :                                                             npgfb, nsgfa, nsgfb
    3131          504 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgfa, first_sgfb
    3132              :       LOGICAL                                            :: found
    3133              :       REAL(dp)                                           :: dab
    3134              :       REAL(dp), DIMENSION(3)                             :: ra, rab, rac, rb, rbc, rc
    3135          504 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: work
    3136          504 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :, :)  :: difmab
    3137          504 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: set_radius_a, set_radius_b
    3138          504 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: rpgfa, rpgfb, sphi_a, sphi_b, zeta, zetb
    3139          504 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: mab
    3140          504 :       REAL(KIND=dp), DIMENSION(:, :, :, :), POINTER      :: difmab2
    3141          504 :       TYPE(block_p_type), ALLOCATABLE, DIMENSION(:, :)   :: mint, mint2
    3142              :       TYPE(cell_type), POINTER                           :: cell
    3143          504 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
    3144              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set_a, basis_set_b
    3145              :       TYPE(neighbor_list_iterator_p_type), &
    3146          504 :          DIMENSION(:), POINTER                           :: nl_iterator
    3147              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    3148          504 :          POINTER                                         :: sab_all, sab_orb
    3149          504 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    3150          504 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    3151              :       TYPE(qs_kind_type), POINTER                        :: qs_kind
    3152              : 
    3153          504 :       CALL timeset(routineN, handle)
    3154              : 
    3155          504 :       NULLIFY (cell, particle_set, qs_kind_set, sab_orb, sab_all)
    3156              :       CALL get_qs_env(qs_env, cell=cell, particle_set=particle_set, &
    3157          504 :                       qs_kind_set=qs_kind_set, sab_orb=sab_orb, sab_all=sab_all)
    3158              :       CALL get_qs_kind_set(qs_kind_set=qs_kind_set, &
    3159          504 :                            maxco=ldab, maxsgf=maxsgf)
    3160              : 
    3161          504 :       nkind = SIZE(qs_kind_set)
    3162          504 :       natom = SIZE(particle_set)
    3163              : 
    3164          504 :       M_dim = ncoset(order) - 1
    3165              : 
    3166          504 :       IF (PRESENT(rcc)) THEN
    3167          504 :          rc = rcc
    3168              :       ELSE
    3169            0 :          rc = 0._dp
    3170              :       END IF
    3171              : 
    3172         2520 :       ALLOCATE (basis_set_list(nkind))
    3173              : 
    3174         2520 :       ALLOCATE (mab(ldab, ldab, M_dim))
    3175         3024 :       ALLOCATE (difmab2(ldab, ldab, M_dim, 3))
    3176         2016 :       ALLOCATE (work(ldab, maxsgf))
    3177         6552 :       ALLOCATE (mint(3, 3))
    3178         6552 :       ALLOCATE (mint2(3, 3))
    3179              : 
    3180       413280 :       mab(1:ldab, 1:ldab, 1:M_dim) = 0.0_dp
    3181      1240344 :       difmab2(1:ldab, 1:ldab, 1:M_dim, 1:3) = 0.0_dp
    3182        34776 :       work(1:ldab, 1:maxsgf) = 0.0_dp
    3183              : 
    3184         2016 :       DO i = 1, 3
    3185         6552 :       DO j = 1, 3
    3186         4536 :          NULLIFY (mint(i, j)%block)
    3187         6048 :          NULLIFY (mint2(i, j)%block)
    3188              :       END DO
    3189              :       END DO
    3190              : 
    3191              :       ! Set the basis_set_list(nkind) to point to the corresponding basis sets
    3192         1512 :       DO ikind = 1, nkind
    3193         1008 :          qs_kind => qs_kind_set(ikind)
    3194         1008 :          CALL get_qs_kind(qs_kind=qs_kind, basis_set=basis_set_a)
    3195         1512 :          IF (ASSOCIATED(basis_set_a)) THEN
    3196         1008 :             basis_set_list(ikind)%gto_basis_set => basis_set_a
    3197              :          ELSE
    3198            0 :             NULLIFY (basis_set_list(ikind)%gto_basis_set)
    3199              :          END IF
    3200              :       END DO
    3201              : 
    3202          504 :       CALL neighbor_list_iterator_create(nl_iterator, sab_all)
    3203        20784 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
    3204              :          CALL get_iterator_info(nl_iterator, ikind=ikind, jkind=jkind, inode=inode, &
    3205        20280 :                                 iatom=iatom, jatom=jatom, r=rab)
    3206              : 
    3207        20280 :          basis_set_a => basis_set_list(ikind)%gto_basis_set
    3208        20280 :          basis_set_b => basis_set_list(jkind)%gto_basis_set
    3209        20280 :          IF (.NOT. ASSOCIATED(basis_set_a)) CYCLE
    3210        20280 :          IF (.NOT. ASSOCIATED(basis_set_b)) CYCLE
    3211              : 
    3212              :          ! basis ikind
    3213        20280 :          first_sgfa => basis_set_a%first_sgf
    3214        20280 :          la_max => basis_set_a%lmax
    3215        20280 :          la_min => basis_set_a%lmin
    3216        20280 :          npgfa => basis_set_a%npgf
    3217        20280 :          nseta = basis_set_a%nset
    3218        20280 :          nsgfa => basis_set_a%nsgf_set
    3219        20280 :          rpgfa => basis_set_a%pgf_radius
    3220        20280 :          set_radius_a => basis_set_a%set_radius
    3221        20280 :          sphi_a => basis_set_a%sphi
    3222        20280 :          zeta => basis_set_a%zet
    3223              :          ! basis jkind
    3224        20280 :          first_sgfb => basis_set_b%first_sgf
    3225        20280 :          lb_max => basis_set_b%lmax
    3226        20280 :          lb_min => basis_set_b%lmin
    3227        20280 :          npgfb => basis_set_b%npgf
    3228        20280 :          nsetb = basis_set_b%nset
    3229        20280 :          nsgfb => basis_set_b%nsgf_set
    3230        20280 :          rpgfb => basis_set_b%pgf_radius
    3231        20280 :          set_radius_b => basis_set_b%set_radius
    3232        20280 :          sphi_b => basis_set_b%sphi
    3233        20280 :          zetb => basis_set_b%zet
    3234              : 
    3235        20280 :          IF (inode == 1) last_jatom = 0
    3236              : 
    3237              :          ! this guarentees minimum image convention
    3238              :          ! anything else would not make sense
    3239        20280 :          IF (jatom == last_jatom) THEN
    3240              :             CYCLE
    3241              :          END IF
    3242              : 
    3243         2268 :          last_jatom = jatom
    3244              : 
    3245         2268 :          irow = iatom
    3246         2268 :          icol = jatom
    3247              : 
    3248         9072 :          DO i = 1, 3
    3249        29484 :          DO j = 1, 3
    3250        20412 :             NULLIFY (mint(i, j)%block)
    3251              :             CALL dbcsr_get_block_p(matrix=difdip(i, j)%matrix, &
    3252              :                                    row=irow, col=icol, BLOCK=mint(i, j)%block, &
    3253        20412 :                                    found=found)
    3254        27216 :             CPASSERT(found)
    3255              :          END DO
    3256              :          END DO
    3257              : 
    3258         9072 :          ra(:) = particle_set(iatom)%r(:)
    3259         9072 :          rb(:) = particle_set(jatom)%r(:)
    3260         2268 :          rab(:) = pbc(rb, ra, cell)
    3261         9072 :          rac(:) = pbc(ra - rc, cell)
    3262         9072 :          rbc(:) = pbc(rb - rc, cell)
    3263         2268 :          dab = SQRT(rab(1)*rab(1) + rab(2)*rab(2) + rab(3)*rab(3))
    3264              : 
    3265         5040 :          DO iset = 1, nseta
    3266         2268 :             ncoa = npgfa(iset)*ncoset(la_max(iset))
    3267         2268 :             sgfa = first_sgfa(1, iset)
    3268        24816 :             DO jset = 1, nsetb
    3269         2268 :                IF (set_radius_a(iset) + set_radius_b(jset) < dab) CYCLE
    3270         2268 :                ncob = npgfb(jset)*ncoset(lb_max(jset))
    3271         2268 :                sgfb = first_sgfb(1, jset)
    3272         2268 :                ldab = MAX(ncoa, ncob)
    3273         2268 :                lda = ncoset(la_max(iset))*npgfa(iset)
    3274         2268 :                ldb = ncoset(lb_max(jset))*npgfb(jset)
    3275        13608 :                ALLOCATE (difmab(lda, ldb, M_dim, 3))
    3276              : 
    3277              :                ! Calculate integral (da|r|b)
    3278              :                CALL diff_momop2(la_max(iset), npgfa(iset), zeta(:, iset), &
    3279              :                                 rpgfa(:, iset), la_min(iset), lb_max(jset), npgfb(jset), &
    3280              :                                 zetb(:, jset), rpgfb(:, jset), lb_min(jset), order, rac, rbc, &
    3281         2268 :                                 difmab, deltaR=deltaR, iatom=iatom, jatom=jatom)
    3282              : 
    3283              : !                  *** Contraction step ***
    3284              : 
    3285         9072 :                DO idir = 1, 3 ! derivative of AO function
    3286        29484 :                DO j = 1, 3     ! position operator r_j
    3287              :                   CALL dgemm("N", "N", ncoa, nsgfb(jset), ncob, &
    3288              :                              1.0_dp, difmab(1, 1, j, idir), SIZE(difmab, 1), &
    3289              :                              sphi_b(1, sgfb), SIZE(sphi_b, 1), &
    3290        20412 :                              0.0_dp, work(1, 1), SIZE(work, 1))
    3291              : 
    3292              :                   CALL dgemm("T", "N", nsgfa(iset), nsgfb(jset), ncoa, &
    3293              :                              1.0_dp, sphi_a(1, sgfa), SIZE(sphi_a, 1), &
    3294              :                              work(1, 1), SIZE(work, 1), &
    3295              :                              1.0_dp, mint(j, idir)%block(sgfa, sgfb), &
    3296        27216 :                              SIZE(mint(j, idir)%block, 1))
    3297              :                END DO !j
    3298              :                END DO !idir
    3299         4536 :                DEALLOCATE (difmab)
    3300              :             END DO !jset
    3301              :          END DO !iset
    3302              :       END DO!iterator
    3303              : 
    3304          504 :       CALL neighbor_list_iterator_release(nl_iterator)
    3305              : 
    3306         2016 :       DO i = 1, 3
    3307         6552 :       DO j = 1, 3
    3308         6048 :          NULLIFY (mint(i, j)%block)
    3309              :       END DO
    3310              :       END DO
    3311              : 
    3312          504 :       DEALLOCATE (mab, difmab2, basis_set_list, work, mint, mint2)
    3313              : 
    3314          504 :       CALL timestop(handle)
    3315         1512 :    END SUBROUTINE dipole_deriv_ao
    3316              : 
    3317              : ! **************************************************************************************************
    3318              : !> \brief Get list of kpoints from input to compute dipole moment elements
    3319              : !> \param qs_env ...
    3320              : !> \param xkp ...
    3321              : !> \param special_pnts ...
    3322              : !> \author Shridhar Shanbhag
    3323              : ! **************************************************************************************************
    3324            8 :    SUBROUTINE get_xkp_for_dipole_calc(qs_env, xkp, special_pnts)
    3325              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    3326              :       TYPE(section_vals_type), POINTER                   :: kpnts, kpset
    3327              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: hmat
    3328              : 
    3329              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'get_xkp_for_dipole_calc'
    3330              : 
    3331              :       CHARACTER(LEN=default_string_length)               :: ustr
    3332              :       TYPE(kpoint_type), POINTER                         :: kpoint_work
    3333              :       TYPE(cell_type), POINTER                           :: cell
    3334              :       CHARACTER(LEN=default_string_length), &
    3335            8 :          DIMENSION(:), POINTER                           :: strptr
    3336              :       CHARACTER(LEN=default_string_length), &
    3337            8 :          DIMENSION(:), POINTER                           :: special_pnts, spname
    3338              :       CHARACTER(LEN=max_line_length)                     :: error_message
    3339              :       INTEGER                                            :: handle, i, ik, ikk, ip, &
    3340              :                                                             n_ptr, npline, nkp
    3341              :       LOGICAL                                            :: explicit_kpnts, explicit_kpset
    3342            8 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :)        :: kspecial, xkp
    3343              :       REAL(KIND=dp), DIMENSION(3)                        :: kpptr
    3344            8 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    3345              : 
    3346            8 :       CALL timeset(routineN, handle)
    3347            8 :       kpset => section_vals_get_subs_vals(qs_env%input, "DFT%PRINT%MOMENTS%KPOINT_SET")
    3348            8 :       kpnts => section_vals_get_subs_vals(qs_env%input, "DFT%PRINT%MOMENTS%KPOINTS")
    3349            8 :       CALL section_vals_get(kpset, explicit=explicit_kpset)
    3350            8 :       CALL section_vals_get(kpnts, explicit=explicit_kpnts)
    3351            8 :       IF (explicit_kpset .AND. explicit_kpnts) &
    3352            0 :          CPABORT("Both KPOINT_SET and KPOINTS present in MOMENTS section")
    3353              : 
    3354            8 :       IF (explicit_kpset) THEN
    3355            2 :          CALL get_qs_env(qs_env, cell=cell)
    3356            2 :          CALL get_cell(cell, h=hmat)
    3357            2 :          CALL section_vals_val_get(kpset, "NPOINTS", i_val=npline)
    3358            2 :          CALL section_vals_val_get(kpset, "UNITS", c_val=ustr)
    3359            2 :          CALL uppercase(ustr)
    3360            2 :          CALL section_vals_val_get(kpset, "SPECIAL_POINT", n_rep_val=n_ptr)
    3361            2 :          CPASSERT(n_ptr > 0)
    3362            6 :          ALLOCATE (kspecial(3, n_ptr))
    3363            6 :          ALLOCATE (spname(n_ptr))
    3364            4 :          DO ip = 1, n_ptr
    3365            2 :             CALL section_vals_val_get(kpset, "SPECIAL_POINT", i_rep_val=ip, c_vals=strptr)
    3366            2 :             IF (SIZE(strptr(:), 1) == 4) THEN
    3367            2 :                spname(ip) = strptr(1)
    3368            8 :                DO i = 1, 3
    3369            6 :                   CALL read_float_object(strptr(i + 1), kpptr(i), error_message)
    3370            8 :                   IF (LEN_TRIM(error_message) > 0) CPABORT(TRIM(error_message))
    3371              :                END DO
    3372            0 :             ELSE IF (SIZE(strptr(:), 1) == 3) THEN
    3373            0 :                spname(ip) = "not specified"
    3374            0 :                DO i = 1, 3
    3375            0 :                   CALL read_float_object(strptr(i), kpptr(i), error_message)
    3376            0 :                   IF (LEN_TRIM(error_message) > 0) CPABORT(TRIM(error_message))
    3377              :                END DO
    3378              :             ELSE
    3379            0 :                CPABORT("Input SPECIAL_POINT invalid")
    3380              :             END IF
    3381            2 :             SELECT CASE (ustr)
    3382              :             CASE ("B_VECTOR")
    3383            8 :                kspecial(1:3, ip) = kpptr(1:3)
    3384              :             CASE ("CART_ANGSTROM")
    3385              :                kspecial(1:3, ip) = (kpptr(1)*hmat(1, 1:3) + &
    3386              :                                     kpptr(2)*hmat(2, 1:3) + &
    3387            0 :                                     kpptr(3)*hmat(3, 1:3))/twopi*angstrom
    3388              :             CASE ("CART_BOHR")
    3389              :                kspecial(1:3, ip) = (kpptr(1)*hmat(1, 1:3) + &
    3390              :                                     kpptr(2)*hmat(2, 1:3) + &
    3391            0 :                                     kpptr(3)*hmat(3, 1:3))/twopi
    3392              :             CASE DEFAULT
    3393            2 :                CPABORT("Unknown unit <"//TRIM(ustr)//"> specified for k-point definition")
    3394              :             END SELECT
    3395              :          END DO
    3396            2 :          nkp = (n_ptr - 1)*npline + 1
    3397            2 :          CPASSERT(nkp >= 1)
    3398              : 
    3399              :          ! Initialize environment and calculate MOs
    3400            6 :          ALLOCATE (xkp(3, nkp))
    3401            6 :          ALLOCATE (special_pnts(nkp))
    3402            4 :          special_pnts(:) = ""
    3403            8 :          xkp(1:3, 1) = kspecial(1:3, 1)
    3404            2 :          ikk = 1
    3405            2 :          special_pnts(ikk) = spname(1)
    3406            2 :          DO ik = 2, n_ptr
    3407            0 :             DO ip = 1, npline
    3408            0 :                ikk = ikk + 1
    3409              :                xkp(1:3, ikk) = kspecial(1:3, ik - 1) + &
    3410              :                                REAL(ip, KIND=dp)/REAL(npline, KIND=dp)* &
    3411            0 :                                (kspecial(1:3, ik) - kspecial(1:3, ik - 1))
    3412              :             END DO
    3413            2 :             special_pnts(ikk) = spname(ik)
    3414              :          END DO
    3415            6 :          DEALLOCATE (spname, kspecial)
    3416            6 :       ELSE IF (explicit_kpnts) THEN
    3417            2 :          CALL get_qs_env(qs_env, particle_set=particle_set, cell=cell)
    3418            2 :          CALL get_cell(cell, h=hmat)
    3419            2 :          NULLIFY (kpoint_work)
    3420            2 :          CALL kpoint_create(kpoint_work)
    3421            2 :          CALL read_kpoint_section(kpoint_work, kpnts, hmat)
    3422            2 :          CALL kpoint_initialize(kpoint_work, particle_set, cell)
    3423            2 :          nkp = kpoint_work%nkp
    3424            6 :          ALLOCATE (xkp(3, nkp))
    3425            6 :          ALLOCATE (special_pnts(nkp))
    3426            4 :          special_pnts(:) = ""
    3427           10 :          xkp(1:3, :) = kpoint_work%xkp(1:3, :)
    3428            2 :          CALL kpoint_release(kpoint_work)
    3429              :       ELSE
    3430              :          ! use k-point mesh from DFT calculation
    3431            4 :          CALL get_qs_env(qs_env, kpoints=kpoint_work)
    3432            4 :          nkp = kpoint_work%nkp
    3433            4 :          nkp = kpoint_work%nkp
    3434           12 :          ALLOCATE (xkp(3, nkp))
    3435           12 :          ALLOCATE (special_pnts(nkp))
    3436          252 :          special_pnts(:) = ""
    3437          996 :          xkp(1:3, :) = kpoint_work%xkp(1:3, :)
    3438              :       END IF
    3439            8 :       CALL timestop(handle)
    3440              : 
    3441            8 :    END SUBROUTINE get_xkp_for_dipole_calc
    3442              : ! **************************************************************************************************
    3443              : !> \brief Calculate local moment matrix for a periodic system for all image cells
    3444              : !> \param qs_env ...
    3445              : !> \param moments_rs_img ...
    3446              : !> \param rcc ...
    3447              : !> \author Shridhar Shanbhag
    3448              : ! **************************************************************************************************
    3449            8 :    SUBROUTINE build_local_moment_matrix_rs_img(qs_env, moments_rs_img, rcc)
    3450              : 
    3451              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    3452              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: moments_rs_img
    3453              :       REAL(KIND=dp), DIMENSION(3), OPTIONAL              :: rcc
    3454              : 
    3455              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_local_moment_matrix_rs_img'
    3456              : 
    3457              :       INTEGER :: handle, i_dir, iatom, ic, ikind, iset, j, jatom, jkind, jset, &
    3458              :                  ldsa, ldsb, ldwork, ncoa, ncob, nimg, nkind, nseta, nsetb, nsize, sgfa, sgfb
    3459              :       INTEGER, DIMENSION(3)                              :: icell
    3460            8 :       INTEGER, DIMENSION(:, :), POINTER                  :: index_to_cell
    3461            8 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    3462              :       LOGICAL                                            :: found
    3463              :       REAL(dp), DIMENSION(3)                             :: ra, rab, rac, rb, rbc, rc
    3464            8 :       REAL(dp), DIMENSION(:, :), POINTER                 :: dblock, work
    3465            8 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: dipab
    3466              :       REAL(KIND=dp)                                      :: dab
    3467              :       TYPE(cell_type), POINTER                           :: cell
    3468            8 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_ks_kp
    3469              :       TYPE(dft_control_type), POINTER                    :: dft_control
    3470            8 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
    3471              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set, basis_set_a, basis_set_b
    3472              :       TYPE(kpoint_type), POINTER                         :: kpoints_all
    3473              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    3474              :       TYPE(neighbor_list_iterator_p_type), &
    3475            8 :          DIMENSION(:), POINTER                           :: nl_iterator
    3476              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    3477            8 :          POINTER                                         :: sab_all
    3478            8 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    3479            8 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    3480              :       TYPE(qs_kind_type), POINTER                        :: qs_kind
    3481              : 
    3482            8 :       CALL timeset(routineN, handle)
    3483              : 
    3484              :       CALL get_qs_env(qs_env=qs_env, &
    3485              :                       dft_control=dft_control, &
    3486              :                       qs_kind_set=qs_kind_set, &
    3487              :                       matrix_ks_kp=matrix_ks_kp, &
    3488              :                       particle_set=particle_set, &
    3489              :                       cell=cell, &
    3490              :                       para_env=para_env, &
    3491            8 :                       sab_all=sab_all)
    3492              : 
    3493            8 :       nimg = dft_control%nimages
    3494            8 :       NULLIFY (kpoints_all)
    3495            8 :       CALL kpoint_create(kpoints_all)
    3496            8 :       CALL kpoint_init_cell_index(kpoints_all, sab_all, para_env, dft_control)!changes nimages
    3497            8 :       dft_control%nimages = nimg
    3498              : 
    3499            8 :       nkind = SIZE(qs_kind_set)
    3500           32 :       ALLOCATE (basis_set_list(nkind))
    3501           16 :       DO ikind = 1, nkind
    3502            8 :          qs_kind => qs_kind_set(ikind)
    3503            8 :          CALL get_qs_kind(qs_kind=qs_kind, basis_set=basis_set)
    3504           16 :          IF (ASSOCIATED(basis_set)) THEN
    3505            8 :             basis_set_list(ikind)%gto_basis_set => basis_set
    3506              :          ELSE
    3507            0 :             NULLIFY (basis_set_list(ikind)%gto_basis_set)
    3508              :          END IF
    3509              :       END DO
    3510              : 
    3511            8 :       rc(:) = 0._dp
    3512            8 :       IF (PRESENT(rcc)) rc(:) = rcc(:)
    3513              : 
    3514            8 :       CALL get_particle_set(particle_set, qs_kind_set, basis=basis_set_list)
    3515            8 :       CALL get_kpoint_info(kpoints_all, cell_to_index=cell_to_index, index_to_cell=index_to_cell)
    3516            8 :       nsize = SIZE(index_to_cell, 2)
    3517            8 :       CPASSERT(SIZE(moments_rs_img, 2) == nsize)
    3518           32 :       DO i_dir = 1, 3
    3519         2576 :          DO j = 1, nsize
    3520         2544 :             ALLOCATE (moments_rs_img(i_dir, j)%matrix)
    3521              :             CALL dbcsr_create(matrix=moments_rs_img(i_dir, j)%matrix, &
    3522              :                               template=matrix_ks_kp(1, 1)%matrix, &
    3523              :                               matrix_type=dbcsr_type_no_symmetry, &
    3524         2544 :                               name="DIPMAT")
    3525         2544 :             CALL cp_dbcsr_alloc_block_from_nbl(moments_rs_img(i_dir, j)%matrix, sab_all)
    3526         2568 :             CALL dbcsr_set(moments_rs_img(i_dir, j)%matrix, 0.0_dp)
    3527              :          END DO
    3528              :       END DO
    3529              : 
    3530            8 :       CALL get_qs_kind_set(qs_kind_set=qs_kind_set, maxco=ldwork)
    3531           40 :       ALLOCATE (dipab(ldwork, ldwork, 3))
    3532           32 :       ALLOCATE (work(ldwork, ldwork))
    3533              : 
    3534            8 :       CALL neighbor_list_iterator_create(nl_iterator, sab_all)
    3535         1802 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
    3536              :          CALL get_iterator_info(nl_iterator, ikind=ikind, jkind=jkind, &
    3537         1794 :                                 iatom=iatom, jatom=jatom, r=rab, cell=icell)
    3538              : 
    3539         1794 :          basis_set_a => basis_set_list(ikind)%gto_basis_set
    3540         1794 :          IF (.NOT. ASSOCIATED(basis_set_a)) CYCLE
    3541         1794 :          basis_set_b => basis_set_list(jkind)%gto_basis_set
    3542         1794 :          IF (.NOT. ASSOCIATED(basis_set_b)) CYCLE
    3543              :          ASSOCIATE ( &
    3544              :             ! basis ikind
    3545              :             first_sgfa => basis_set_a%first_sgf, &
    3546              :             la_max => basis_set_a%lmax, &
    3547              :             la_min => basis_set_a%lmin, &
    3548              :             npgfa => basis_set_a%npgf, &
    3549              :             nsgfa => basis_set_a%nsgf_set, &
    3550              :             rpgfa => basis_set_a%pgf_radius, &
    3551              :             set_radius_a => basis_set_a%set_radius, &
    3552              :             sphi_a => basis_set_a%sphi, &
    3553              :             zeta => basis_set_a%zet, &
    3554              :             ! basis jkind, &
    3555              :             first_sgfb => basis_set_b%first_sgf, &
    3556              :             lb_max => basis_set_b%lmax, &
    3557              :             lb_min => basis_set_b%lmin, &
    3558              :             npgfb => basis_set_b%npgf, &
    3559              :             nsgfb => basis_set_b%nsgf_set, &
    3560              :             rpgfb => basis_set_b%pgf_radius, &
    3561              :             set_radius_b => basis_set_b%set_radius, &
    3562              :             sphi_b => basis_set_b%sphi, &
    3563              :             zetb => basis_set_b%zet)
    3564              : 
    3565         1794 :             nseta = basis_set_a%nset
    3566         1794 :             nsetb = basis_set_b%nset
    3567              : 
    3568         1794 :             ldsa = SIZE(sphi_a, 1)
    3569         1794 :             ldsb = SIZE(sphi_b, 1)
    3570              : 
    3571         1794 :             NULLIFY (dblock)
    3572              : 
    3573         1794 :             ra = pbc(particle_set(iatom)%r(:), cell)
    3574         7176 :             rb(:) = ra(:) + rab(:)
    3575         7176 :             rac = ra - rc
    3576         7176 :             rbc = rb - rc
    3577         7176 :             dab = norm2(rab)
    3578              : 
    3579         1794 :             ic = cell_to_index(icell(1), icell(2), icell(3))
    3580              : 
    3581         5382 :             DO iset = 1, nseta
    3582              : 
    3583         1794 :                ncoa = npgfa(iset)*ncoset(la_max(iset))
    3584         1794 :                sgfa = first_sgfa(1, iset)
    3585              : 
    3586         5382 :                DO jset = 1, nsetb
    3587              : 
    3588         1794 :                   IF (set_radius_a(iset) + set_radius_b(jset) < dab) CYCLE
    3589              : 
    3590         1794 :                   ncob = npgfb(jset)*ncoset(lb_max(jset))
    3591         1794 :                   sgfb = first_sgfb(1, jset)
    3592              : 
    3593              :                   CALL moment(la_max(iset), npgfa(iset), zeta(:, iset), rpgfa(:, iset), la_min(iset), &
    3594              :                               lb_max(jset), npgfb(jset), zetb(:, jset), rpgfb(:, jset), 1, &
    3595         1794 :                               rac, rbc, dipab)
    3596         8970 :                   DO i_dir = 1, 3
    3597              :                      CALL dbcsr_get_block_p(matrix=moments_rs_img(i_dir, ic)%matrix, &
    3598         5382 :                                             row=iatom, col=jatom, BLOCK=dblock, found=found)
    3599         5382 :                      CPASSERT(found)
    3600              :                      CALL dgemm("N", "N", ncoa, nsgfb(jset), ncob, &
    3601              :                                 1.0_dp, dipab(1, 1, i_dir), ldwork, &
    3602         5382 :                                 sphi_b(1, sgfb), ldsb, 0.0_dp, work(1, 1), ldwork)
    3603              : 
    3604              :                      CALL dgemm("T", "N", nsgfa(iset), nsgfb(jset), ncoa, &
    3605              :                                 1.0_dp, sphi_a(1, sgfa), ldsa, &
    3606        12558 :                                 work(1, 1), ldwork, 1.0_dp, dblock(1, 1), SIZE(dblock, 1))
    3607              :                   END DO
    3608              :                END DO
    3609              :             END DO
    3610              :          END ASSOCIATE
    3611              :       END DO
    3612            8 :       CALL neighbor_list_iterator_release(nl_iterator)
    3613            8 :       CALL kpoint_release(kpoints_all)
    3614            8 :       DEALLOCATE (dipab, work, basis_set_list)
    3615            8 :       CALL timestop(handle)
    3616              : 
    3617           16 :    END SUBROUTINE build_local_moment_matrix_rs_img
    3618              : 
    3619              : ! **************************************************************************************************
    3620              : !> \brief Calculate and print dipole moment elements d_nm(k) for k-point calculations
    3621              : !> \param qs_env ...
    3622              : !> \param nmoments ...
    3623              : !> \param reference ...
    3624              : !> \param ref_point ...
    3625              : !> \param unit_number ...
    3626              : !> \author Shridhar Shanbhag
    3627              : ! **************************************************************************************************
    3628            8 :    SUBROUTINE qs_moment_kpoints(qs_env, nmoments, reference, ref_point, unit_number)
    3629              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    3630              :       INTEGER, INTENT(IN)                                :: nmoments, reference
    3631              :       REAL(dp), DIMENSION(:), INTENT(IN), POINTER        :: ref_point
    3632              :       INTEGER, INTENT(IN)                                :: unit_number
    3633              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'qs_moment_kpoints'
    3634              :       COMPLEX(KIND=dp)                                   :: phase, tmp_max
    3635            8 :       COMPLEX(KIND=dp), DIMENSION(:, :), ALLOCATABLE     :: C_k, H_k, S_k, D_k, CDC, C_dH_C, &
    3636            8 :                                                             C_dS_C, dH_dk_i, dS_dk_i
    3637            8 :       COMPLEX(KIND=dp), DIMENSION(:, :, :), ALLOCATABLE  :: dip, dipole_to_print
    3638              :       COMPLEX(KIND=dp), DIMENSION(:, :, :, :), &
    3639            8 :          ALLOCATABLE                                     :: dipole_to_store
    3640              :       INTEGER                                            :: handle, i_dir, ikp, nkp, nmo, &
    3641              :                                                             n_img_scf, n_img_all, nao, &
    3642              :                                                             num_pe, num_copy, mepos, n, m, mu
    3643            8 :       INTEGER, DIMENSION(:, :), POINTER                  :: index_to_cell_all
    3644            8 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index_all
    3645              :       REAL(KIND=dp), DIMENSION(3)                        :: rcc
    3646              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: hmat
    3647            8 :       REAL(KIND=dp), DIMENSION(:), ALLOCATABLE           :: eigenvals
    3648            8 :       REAL(KIND=dp), DIMENSION(:, :), ALLOCATABLE        :: bc, xkp
    3649            8 :       REAL(KIND=dp), DIMENSION(:, :), ALLOCATABLE        :: bc_to_print
    3650            8 :       REAL(KIND=dp), DIMENSION(:, :, :), ALLOCATABLE     :: bc_to_store
    3651              :       REAL(KIND=dp), DIMENSION(:, :, :, :), &
    3652            8 :          ALLOCATABLE                                     :: D_rs, H_rs, S_rs
    3653              :       TYPE(cell_type), POINTER                           :: cell
    3654            8 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: moments_rs_img, matrix_ks_kp, &
    3655            8 :                                                             matrix_s_kp
    3656              :       TYPE(dft_control_type), POINTER                    :: dft_control
    3657              :       TYPE(kpoint_type), POINTER                         :: kpoints_all, kpoints_scf
    3658            8 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
    3659              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    3660              :       CHARACTER(LEN=default_string_length), &
    3661            8 :          DIMENSION(:), POINTER                           :: special_pnts
    3662              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    3663            8 :          POINTER                                         :: sab_all
    3664              : 
    3665            8 :       CALL timeset(routineN, handle)
    3666              : 
    3667            8 :       IF (nmoments > 1) CPABORT("KPOINT quadrupole and higher moments not implemented.")
    3668              : 
    3669              :       CALL get_qs_env(qs_env, &
    3670              :                       matrix_ks_kp=matrix_ks_kp, &
    3671              :                       matrix_s_kp=matrix_s_kp, &
    3672              :                       sab_all=sab_all, &
    3673              :                       cell=cell, &
    3674              :                       kpoints=kpoints_scf, &
    3675              :                       para_env=para_env, &
    3676              :                       dft_control=dft_control, &
    3677            8 :                       mos=mos)
    3678              : 
    3679            8 :       CPASSERT(SIZE(matrix_ks_kp, 1) == 1)!  only for closed shell at present
    3680            8 :       CALL get_mo_set(mo_set=mos(1), nao=nao)
    3681              :       ! for now, and for clarity
    3682            8 :       nmo = nao
    3683              : 
    3684              :       ! create kpoint environment kpoints_all which contains all neighbor cells R
    3685              :       ! without considering any lattice symmetry
    3686            8 :       n_img_scf = dft_control%nimages
    3687            8 :       NULLIFY (kpoints_all)
    3688            8 :       CALL kpoint_create(kpoints_all)
    3689            8 :       CALL kpoint_init_cell_index(kpoints_all, sab_all, para_env, dft_control)!changes nimages
    3690            8 :       dft_control%nimages = n_img_scf
    3691              : 
    3692            8 :       CALL get_kpoint_info(kpoints_all, cell_to_index=cell_to_index_all, index_to_cell=index_to_cell_all)
    3693            8 :       n_img_all = SIZE(index_to_cell_all, 2)
    3694              : 
    3695            8 :       CALL get_xkp_for_dipole_calc(qs_env, xkp, special_pnts)
    3696            8 :       nkp = SIZE(xkp, 2)
    3697              : 
    3698            8 :       NULLIFY (moments_rs_img)
    3699            8 :       CALL dbcsr_allocate_matrix_set(moments_rs_img, 3, n_img_all)
    3700            8 :       CALL get_reference_point(rcc, qs_env=qs_env, reference=reference, ref_point=ref_point)
    3701              :       ! D_μ,ν = <φ_μ|r|φ_ν>
    3702            8 :       CALL build_local_moment_matrix_rs_img(qs_env, moments_rs_img, rcc=rcc)
    3703              : 
    3704       203216 :       ALLOCATE (S_rs(1, nao, nao, n_img_all), H_rs(1, nao, nao, n_img_all), source=0.0_dp)
    3705       196144 :       ALLOCATE (D_rs(3, nao, nao, n_img_all), source=0.0_dp)
    3706              : 
    3707              :       ! Convert real-space dbcsr matrices into arrays
    3708            8 :       CALL replicate_rs_matrices(matrix_s_kp, kpoints_scf, S_rs, cell_to_index_all)
    3709            8 :       CALL replicate_rs_matrices(matrix_ks_kp, kpoints_scf, H_rs, cell_to_index_all)
    3710            8 :       CALL replicate_rs_matrices(moments_rs_img, kpoints_all, D_rs, cell_to_index_all)
    3711              : 
    3712            8 :       IF (unit_number > 0) WRITE (unit_number, FMT="(/,T2,A)") &
    3713            4 :          '!-----------------------------------------------------------------------------!'
    3714            8 :       IF (unit_number > 0) WRITE (unit_number, "(T22,A)") "Periodic Dipole Matrix Elements"
    3715              : 
    3716            8 :       mepos = para_env%mepos
    3717            8 :       num_pe = para_env%num_pe
    3718            8 :       num_copy = CEILING(REAL(nkp)/num_pe)
    3719            8 :       CALL get_cell(cell=cell, h=hmat)
    3720         1968 :       ALLOCATE (dS_dk_i(nao, nao), C_dS_C(nao, nao), dH_dk_i(nao, nao), C_dH_C(nao, nao), source=z_zero)
    3721         3216 :       ALLOCATE (CDC(nao, nao), dip(3, nao, nao), S_k(nao, nao), H_k(nao, nao), source=z_zero)
    3722        11760 :       ALLOCATE (C_k(nao, nao), D_k(nao, nao), dipole_to_store(num_copy, 3, nao, nao), source=z_zero)
    3723         2344 :       ALLOCATE (eigenvals(nao), bc(3, nao), bc_to_store(num_copy, 3, nao), source=0.0_dp)
    3724              : 
    3725              : !$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(ikp, S_k, H_k, eigenvals, C_k, &
    3726              : !$OMP dS_dk_i, dH_dk_i, D_k, dip, bc, C_dS_C, C_dH_C, CDC, tmp_max, phase) &
    3727              : !$OMP SHARED(num_pe, mepos,dipole_to_store, bc_to_store, nmo, nao,&
    3728            8 : !$OMP nkp, xkp, S_rs, H_rs, D_rs, index_to_cell_all, hmat, unit_number)
    3729              :       DO ikp = 1, nkp
    3730              :          IF (mod(ikp - 1, num_pe) /= mepos) CYCLE
    3731              : 
    3732              :          ! S^R -> S(k), H^R -> H(k)
    3733              :          CALL rs_to_kp(S_rs(1, :, :, :), S_k, index_to_cell_all, xkp(:, ikp))
    3734              :          CALL rs_to_kp(H_rs(1, :, :, :), H_k, index_to_cell_all, xkp(:, ikp))
    3735              : 
    3736              :          ! Diagonalize H(k)C(k) = S(k)C(k)ε(k)
    3737              :          CALL geeig_right(H_k, S_k, eigenvals, C_k)
    3738              : 
    3739              :          ! To have a smooth complex phase of C(k) as function of k, for every n, we force
    3740              :          ! the largest C_μ,n(k) to be real.
    3741              :          ! This is important to have a continuous dipole moment d_nm(k) as a function of k
    3742              :          DO n = 1, nmo
    3743              :             tmp_max = C_k(1, n)
    3744              :             DO mu = 1, nao
    3745              :                IF (ABS(C_k(mu, n)) < ABS(tmp_max)) CYCLE
    3746              :                tmp_max = C_k(mu, n)
    3747              :             END DO
    3748              :             phase = tmp_max/ABS(tmp_max)
    3749              :             C_k(:, n) = C_k(:, n)/phase
    3750              :          END DO
    3751              : 
    3752              :          DO i_dir = 1, 3 ! d^x, d^y, d^z
    3753              : 
    3754              :             ! ∇ S(k) = Σ_R iR S^R e^(ikR), ∇ H(k) = Σ_R iR H^R e^(ikR)
    3755              :             CALL rs_to_kp(S_rs(1, :, :, :), dS_dk_i, index_to_cell_all, xkp(:, ikp), i_dir, hmat)
    3756              :             CALL rs_to_kp(H_rs(1, :, :, :), dH_dk_i, index_to_cell_all, xkp(:, ikp), i_dir, hmat)
    3757              : 
    3758              :             ! Σ_R D^R e^(ikR) = D(k), D_μ,ν = <φ_μ|r|φ_ν>
    3759              :             CALL rs_to_kp(D_rs(i_dir, :, :, :), D_k(:, :), index_to_cell_all, xkp(:, ikp))
    3760              : 
    3761              :             ! Basis transform to Kohn-Sham basis: (C^H) ∇ S C, (C^H) ∇ H C, (C^H) D C
    3762              :             CALL gemm_square(C_k, 'C', dS_dk_i, 'N', C_k, 'N', C_dS_C)
    3763              :             CALL gemm_square(C_k, 'C', dH_dk_i, 'N', C_k, 'N', C_dH_C)
    3764              :             CALL gemm_square(C_k, 'C', D_k, 'N', C_k, 'N', CDC)
    3765              : 
    3766              :             ! Compute the dipole
    3767              :             ! d_nm (k) = - i/(ε(n)-ε(m)) [ (C^H)(dH(k)/dk)C ]_nm
    3768              :             !            + i ε(n)/(ε(n)-ε(m)) [ (C^H)(dS(k)/dk)C ]_nm + [ (C^H)D(k)C ]_nm
    3769              :             DO n = 1, nmo
    3770              :                DO m = 1, nmo
    3771              :                   IF (n == m) CYCLE ! diagonal elements would need to be computed from
    3772              :                   ! a numerical k-derivative which is not implemented
    3773              :                   dip(i_dir, n, m) = -gaussi*C_dH_C(n, m)/(eigenvals(n) - eigenvals(m)) &
    3774              :                                      + gaussi*eigenvals(n)*C_dS_C(n, m)/(eigenvals(n) - eigenvals(m)) &
    3775              :                                      + CDC(n, m)
    3776              :                END DO
    3777              :             END DO
    3778              :          END DO
    3779              :          ! Compute the Berry curvature from the dipoles
    3780              :          ! Ω^γ_n = Σ_m 2*Im[d^α_nm (d^β_mn)*], where, α, β, γ belong to {x, y, z}
    3781              :          bc = 0
    3782              :          DO i_dir = 1, 3
    3783              :             DO n = 1, nmo
    3784              :                DO m = 1, nmo
    3785              :                   IF (n == m) CYCLE
    3786              :                   bc(i_dir, n) = bc(i_dir, n) &
    3787              :                                  + 2*AIMAG(dip(1 + MOD(i_dir, 3), n, m)*dip(1 + MOD(i_dir + 1, 3), m, n))
    3788              :                END DO
    3789              :             END DO
    3790              :          END DO
    3791              :          ! Store the dipoles and berry curvature for each MPI rank
    3792              :          dipole_to_store(CEILING(REAL(ikp)/num_pe), :, :, :) = dip(:, :, :)
    3793              :          bc_to_store(CEILING(REAL(ikp)/num_pe), :, :) = bc(:, :)
    3794              : 
    3795              :       END DO
    3796              : !$OMP END PARALLEL DO
    3797              : 
    3798         1752 :       ALLOCATE (dipole_to_print(3, nao, nao), source=z_zero)
    3799          248 :       ALLOCATE (bc_to_print(3, nao), source=0.0_dp)
    3800          260 :       DO ikp = 1, nkp
    3801        24444 :          dipole_to_print = 0.0_dp
    3802         4860 :          bc_to_print = 0.0_dp
    3803          252 :          IF (mod(ikp - 1, num_pe) == mepos) THEN
    3804        12222 :             dipole_to_print(:, :, :) = dipole_to_store(CEILING(REAL(ikp)/num_pe), :, :, :)
    3805         2430 :             bc_to_print(:, :) = bc_to_store(CEILING(REAL(ikp)/num_pe), :, :)
    3806              :          END IF
    3807          252 :          CALL para_env%sum(dipole_to_print)
    3808          252 :          CALL para_env%sum(bc_to_print)
    3809          260 :          IF (unit_number > 0) THEN
    3810          126 :             IF (special_pnts(ikp) /= "") WRITE (unit_number, "(/,2X,A,A)") &
    3811            1 :                "Special point: ", ADJUSTL(TRIM(special_pnts(ikp)))
    3812              :             WRITE (unit_number, "(/,1X,A,I3,1X,3(A,1F12.6))") &
    3813          126 :                "Kpoint:", ikp, ", kx:", xkp(1, ikp), ", ky:", xkp(2, ikp), ", kz:", xkp(3, ikp)
    3814              :             WRITE (unit_number, "(2X,A)") " kp  n  m  Re(dx_nm)  Im(dx_nm) &
    3815          126 :             & Re(dy_nm)  Im(dy_nm)  Re(dz_nm)  Im(dz_nm)"
    3816          702 :             DO n = 1, nao
    3817         3582 :                DO m = 1, nao
    3818         2880 :                   IF (n == m) CYCLE
    3819         3456 :                   WRITE (unit_number, "(1X,I4,2I3,6(G11.3))") ikp, n, m, dipole_to_print(1:3, n, m)
    3820              :                END DO
    3821              :             END DO
    3822          126 :             WRITE (unit_number, "(/,1X,A)") "Berry Curvature"
    3823          126 :             WRITE (unit_number, "(2X,A)") "  kp   n      YZ          ZX          XY"
    3824          702 :             DO n = 1, nao
    3825              :                WRITE (unit_number, "(2X,2I4,3(1X,G11.3))") &
    3826          702 :                   ikp, n, bc_to_print(1, n), bc_to_print(2, n), bc_to_print(3, n)
    3827              :             END DO
    3828              :          END IF
    3829              :       END DO
    3830            8 :       DEALLOCATE (dipole_to_print, bc_to_print, eigenvals, bc, dS_dk_i, dH_dk_i, D_k)
    3831            8 :       DEALLOCATE (C_dS_C, C_dH_C, CDC, dip, S_k, H_k, C_k, S_rs, H_rs, D_rs, xkp, special_pnts)
    3832            8 :       CALL dbcsr_deallocate_matrix_set(moments_rs_img)
    3833            8 :       CALL kpoint_release(kpoints_all)
    3834              : 
    3835            8 :       CALL timestop(handle)
    3836              : 
    3837           24 :    END SUBROUTINE qs_moment_kpoints
    3838              : 
    3839              : END MODULE qs_moments
        

Generated by: LCOV version 2.0-1