LCOV - code coverage report
Current view: top level - src - qs_moments.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:6d276e9) Lines: 93.0 % 1612 1499
Test Date: 2026-09-10 07:29:18 Functions: 100.0 % 18 18

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

Generated by: LCOV version 2.0-1