LCOV - code coverage report
Current view: top level - src - qs_moments.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:5064cfc) Lines: 88.0 % 1753 1543
Test Date: 2026-03-04 06:45:10 Functions: 95.0 % 20 19

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

Generated by: LCOV version 2.0-1