LCOV - code coverage report
Current view: top level - src - qs_moments.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:21ef868) Lines: 93.7 % 1884 1765
Test Date: 2026-08-14 07:04:57 Functions: 100.0 % 21 21

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

Generated by: LCOV version 2.0-1