LCOV - code coverage report
Current view: top level - src - qs_loc_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:06f838d) Lines: 54.3 % 597 324
Test Date: 2026-06-05 07:04:50 Functions: 58.3 % 12 7

            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 Driver for the localization that should be general
      10              : !>      for all the methods available and all the definition of the
      11              : !>      spread functional
      12              : !>      Write centers, spread and cubes only if required and for the
      13              : !>      selected states
      14              : !>      The localized functions are copied in the standard mos array
      15              : !>      for the next use
      16              : !> \par History
      17              : !>      01.2008 Teodoro Laino [tlaino] - University of Zurich
      18              : !>        - Merging the two localization codes and updating to new structures
      19              : !> \author MI (04.2005)
      20              : ! **************************************************************************************************
      21              : MODULE qs_loc_methods
      22              :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      23              :                                               deallocate_atomic_kind_set,&
      24              :                                               set_atomic_kind
      25              :    USE cell_types,                      ONLY: cell_type,&
      26              :                                               pbc
      27              :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      28              :                                               cp_cfm_get_element,&
      29              :                                               cp_cfm_get_info,&
      30              :                                               cp_cfm_p_type,&
      31              :                                               cp_cfm_release,&
      32              :                                               cp_cfm_to_fm,&
      33              :                                               cp_cfm_type,&
      34              :                                               cp_fm_to_cfm
      35              :    USE cp_control_types,                ONLY: dft_control_type
      36              :    USE cp_dbcsr_api,                    ONLY: dbcsr_copy,&
      37              :                                               dbcsr_deallocate_matrix,&
      38              :                                               dbcsr_p_type,&
      39              :                                               dbcsr_set
      40              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      41              :                                               cp_dbcsr_sm_fm_multiply
      42              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_rot_cols,&
      43              :                                               cp_fm_rot_rows,&
      44              :                                               cp_fm_schur_product
      45              :    USE cp_fm_pool_types,                ONLY: cp_fm_pool_p_type,&
      46              :                                               fm_pool_create_fm
      47              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      48              :                                               cp_fm_struct_release,&
      49              :                                               cp_fm_struct_type
      50              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      51              :                                               cp_fm_get_element,&
      52              :                                               cp_fm_get_info,&
      53              :                                               cp_fm_maxabsval,&
      54              :                                               cp_fm_release,&
      55              :                                               cp_fm_set_all,&
      56              :                                               cp_fm_to_fm,&
      57              :                                               cp_fm_type
      58              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      59              :                                               cp_logger_type,&
      60              :                                               cp_to_string
      61              :    USE cp_output_handling,              ONLY: cp_iter_string,&
      62              :                                               cp_p_file,&
      63              :                                               cp_print_key_finished_output,&
      64              :                                               cp_print_key_should_output,&
      65              :                                               cp_print_key_unit_nr
      66              :    USE cp_realspace_grid_cube,          ONLY: cp_pw_to_cube
      67              :    USE cp_units,                        ONLY: cp_unit_from_cp2k
      68              :    USE input_constants,                 ONLY: &
      69              :         do_loc_crazy, do_loc_cs, do_loc_direct, do_loc_gapo, do_loc_jacobi, do_loc_l1_norm_sd, &
      70              :         do_loc_none, do_loc_scdm, dump_dcd, dump_dcd_aligned_cell, dump_xmol
      71              :    USE input_section_types,             ONLY: section_get_ival,&
      72              :                                               section_get_ivals,&
      73              :                                               section_vals_get_subs_vals,&
      74              :                                               section_vals_type,&
      75              :                                               section_vals_val_get
      76              :    USE kinds,                           ONLY: default_path_length,&
      77              :                                               default_string_length,&
      78              :                                               dp,&
      79              :                                               sp
      80              :    USE machine,                         ONLY: m_flush
      81              :    USE mathconstants,                   ONLY: pi,&
      82              :                                               twopi
      83              :    USE message_passing,                 ONLY: mp_para_env_type
      84              :    USE molecule_types,                  ONLY: molecule_type
      85              :    USE motion_utils,                    ONLY: get_output_format
      86              :    USE orbital_pointers,                ONLY: ncoset
      87              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      88              :    USE particle_list_types,             ONLY: particle_list_type
      89              :    USE particle_methods,                ONLY: get_particle_set,&
      90              :                                               write_particle_coordinates
      91              :    USE particle_types,                  ONLY: allocate_particle_set,&
      92              :                                               deallocate_particle_set,&
      93              :                                               particle_type
      94              :    USE physcon,                         ONLY: angstrom
      95              :    USE pw_env_types,                    ONLY: pw_env_get,&
      96              :                                               pw_env_type
      97              :    USE pw_pool_types,                   ONLY: pw_pool_type
      98              :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      99              :                                               pw_r3d_rs_type
     100              :    USE qs_collocate_density,            ONLY: calculate_wavefunction
     101              :    USE qs_environment_types,            ONLY: get_qs_env,&
     102              :                                               qs_environment_type
     103              :    USE qs_kind_types,                   ONLY: qs_kind_type
     104              :    USE qs_loc_types,                    ONLY: get_qs_loc_env,&
     105              :                                               qs_loc_env_type
     106              :    USE qs_localization_methods,         ONLY: &
     107              :         approx_l1_norm_sd, cardoso_souloumiac, cardoso_souloumiac_pipek, crazy_rotations, &
     108              :         direct_mini, jacobi_cg_edf_ls, jacobi_rotations, rotate_orbitals, scdm_qrfact, zij_matrix
     109              :    USE qs_matrix_pools,                 ONLY: mpools_get
     110              :    USE qs_moments,                      ONLY: build_local_moment_matrix
     111              :    USE qs_subsys_types,                 ONLY: qs_subsys_get,&
     112              :                                               qs_subsys_type
     113              :    USE string_utilities,                ONLY: xstring
     114              : #include "./base/base_uses.f90"
     115              : 
     116              :    IMPLICIT NONE
     117              : 
     118              :    PRIVATE
     119              : 
     120              : ! *** Global parameters ***
     121              : 
     122              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_loc_methods'
     123              : 
     124              : ! *** Public ***
     125              :    PUBLIC :: qs_print_cubes, centers_spreads_berry, centers_second_moments_loc, &
     126              :              centers_second_moments_berry, jacobi_rotation_pipek, optimize_loc_berry, &
     127              :              optimize_loc_pipek
     128              : 
     129              : CONTAINS
     130              : 
     131              : ! **************************************************************************************************
     132              : !> \brief Calculate and optimize the spread functional as calculated from
     133              : !>       the selected mos  and by the definition using the berry phase
     134              : !>       as given by silvestrelli et al
     135              : !>       If required the centers and the spreads for each mos selected
     136              : !>       are calculated from z_ij and printed to file.
     137              : !>       The centers files is appended if already exists
     138              : !> \param method indicates localization algorithm
     139              : !> \param qs_loc_env new environment for the localization calculations
     140              : !> \param vectors selected mos to be localized
     141              : !> \param op_sm_set sparse matrices containing the integrals of the kind <mi e{iGr} nu>
     142              : !> \param zij_fm_set set of full matrix of size nmoloc x nmoloc, will contain the z_ij numbers
     143              : !>                    as defined by Silvestrelli et al
     144              : !> \param para_env ...
     145              : !> \param cell ...
     146              : !> \param weights ...
     147              : !> \param ispin ...
     148              : !> \param print_loc_section ...
     149              : !> \param restricted ...
     150              : !> \param nextra ...
     151              : !> \param nmo ...
     152              : !> \param vectors_2 ...
     153              : !> \param guess_mos ...
     154              : !> \par History
     155              : !>      04.2005 created [MI]
     156              : !> \author MI
     157              : !> \note
     158              : !>       This definition need the use of complex numbers, therefore the
     159              : !>       optimization routines are specific for this case
     160              : !>       The file for the centers and the spreads have a xyz format
     161              : ! **************************************************************************************************
     162          500 :    SUBROUTINE optimize_loc_berry(method, qs_loc_env, vectors, op_sm_set, &
     163          500 :                                  zij_fm_set, para_env, cell, weights, ispin, print_loc_section, &
     164              :                                  restricted, nextra, nmo, vectors_2, guess_mos)
     165              : 
     166              :       INTEGER, INTENT(IN)                                :: method
     167              :       TYPE(qs_loc_env_type), POINTER                     :: qs_loc_env
     168              :       TYPE(cp_fm_type), INTENT(IN)                       :: vectors
     169              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: op_sm_set
     170              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN)      :: zij_fm_set
     171              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     172              :       TYPE(cell_type), POINTER                           :: cell
     173              :       REAL(dp), DIMENSION(:)                             :: weights
     174              :       INTEGER, INTENT(IN)                                :: ispin
     175              :       TYPE(section_vals_type), POINTER                   :: print_loc_section
     176              :       INTEGER                                            :: restricted
     177              :       INTEGER, INTENT(IN), OPTIONAL                      :: nextra, nmo
     178              :       TYPE(cp_fm_type), INTENT(IN), OPTIONAL             :: vectors_2, guess_mos
     179              : 
     180              :       CHARACTER(len=*), PARAMETER :: routineN = 'optimize_loc_berry'
     181              : 
     182              :       INTEGER                                            :: handle, idim1, idim2, max_iter, nao, &
     183              :                                                             nmoloc, out_each, output_unit, sweeps
     184              :       LOGICAL                                            :: converged, crazy_use_diag, &
     185              :                                                             do_jacobi_refinement, my_do_mixed
     186              :       REAL(dp)                                           :: crazy_scale, eps_localization, &
     187              :                                                             max_crazy_angle, start_time, &
     188              :                                                             target_time
     189          500 :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:, :)    :: my_zij_cfm_set
     190              :       TYPE(cp_cfm_type), POINTER                         :: complex_vectors
     191              :       TYPE(cp_logger_type), POINTER                      :: logger
     192              : 
     193          500 :       NULLIFY (complex_vectors)
     194              : 
     195          500 :       CALL timeset(routineN, handle)
     196          500 :       logger => cp_get_default_logger()
     197              :       output_unit = cp_print_key_unit_nr(logger, print_loc_section, "PROGRAM_RUN_INFO", &
     198          500 :                                          extension=".locInfo")
     199              : 
     200              :       ! get rows and cols of the input
     201          500 :       CALL cp_fm_get_info(vectors, nrow_global=nao, ncol_global=nmoloc)
     202              : 
     203          500 :       CALL zij_matrix(vectors, op_sm_set, zij_fm_set)
     204              : 
     205          500 :       max_iter = qs_loc_env%localized_wfn_control%max_iter
     206          500 :       max_crazy_angle = qs_loc_env%localized_wfn_control%max_crazy_angle
     207          500 :       crazy_use_diag = qs_loc_env%localized_wfn_control%crazy_use_diag
     208          500 :       crazy_scale = qs_loc_env%localized_wfn_control%crazy_scale
     209          500 :       eps_localization = qs_loc_env%localized_wfn_control%eps_localization
     210          500 :       out_each = qs_loc_env%localized_wfn_control%out_each
     211          500 :       target_time = qs_loc_env%target_time
     212          500 :       start_time = qs_loc_env%start_time
     213          500 :       do_jacobi_refinement = qs_loc_env%localized_wfn_control%jacobi_refinement
     214          500 :       my_do_mixed = qs_loc_env%localized_wfn_control%do_mixed
     215              : 
     216              :       CALL centers_spreads_berry(qs_loc_env, nmoloc, cell, weights, &
     217          500 :                                  ispin, print_loc_section, zij=zij_fm_set, only_initial_out=.TRUE.)
     218              : 
     219          500 :       sweeps = 0
     220              : 
     221          822 :       SELECT CASE (method)
     222              :       CASE (do_loc_jacobi)
     223              :          CALL jacobi_rotations(weights, zij_fm_set, vectors, para_env, max_iter=max_iter, &
     224              :                                eps_localization=eps_localization, sweeps=sweeps, &
     225              :                                out_each=out_each, target_time=target_time, start_time=start_time, &
     226          322 :                                restricted=restricted)
     227              :       CASE (do_loc_gapo)
     228            2 :          IF (my_do_mixed) THEN
     229            2 :             IF (nextra > 0) THEN
     230            2 :                IF (PRESENT(guess_mos)) THEN
     231              :                   CALL jacobi_cg_edf_ls(para_env, weights, zij_fm_set, vectors, max_iter, &
     232              :                                         eps_localization, sweeps, out_each, nextra, &
     233              :                                         qs_loc_env%localized_wfn_control%do_cg_po, &
     234            2 :                                         nmo=nmo, vectors_2=vectors_2, mos_guess=guess_mos)
     235              :                ELSE
     236              :                   CALL jacobi_cg_edf_ls(para_env, weights, zij_fm_set, vectors, max_iter, &
     237              :                                         eps_localization, sweeps, out_each, nextra, &
     238              :                                         qs_loc_env%localized_wfn_control%do_cg_po, &
     239            0 :                                         nmo=nmo, vectors_2=vectors_2)
     240              :                END IF
     241              :             ELSE
     242              :                CALL jacobi_cg_edf_ls(para_env, weights, zij_fm_set, vectors, max_iter, &
     243              :                                      eps_localization, sweeps, out_each, 0, &
     244            0 :                                      qs_loc_env%localized_wfn_control%do_cg_po)
     245              :             END IF
     246              :          ELSE
     247            0 :             CPABORT("GAPO works only with STATES MIXED")
     248              :          END IF
     249              :       CASE (do_loc_scdm)
     250              :          ! Decomposition
     251            2 :          CALL scdm_qrfact(vectors)
     252              :          ! Calculation of Zij
     253            2 :          CALL zij_matrix(vectors, op_sm_set, zij_fm_set)
     254            2 :          IF (do_jacobi_refinement) THEN
     255              :             ! Intermediate spread and centers
     256              :             CALL centers_spreads_berry(qs_loc_env, nmoloc, cell, weights, &
     257            0 :                                        ispin, print_loc_section, zij=zij_fm_set, only_initial_out=.TRUE.)
     258              :             CALL jacobi_rotations(weights, zij_fm_set, vectors, para_env, max_iter=max_iter, &
     259              :                                   eps_localization=eps_localization, sweeps=sweeps, &
     260              :                                   out_each=out_each, target_time=target_time, start_time=start_time, &
     261            0 :                                   restricted=restricted)
     262              :          END IF
     263              :       CASE (do_loc_crazy)
     264              :          CALL crazy_rotations(weights, zij_fm_set, vectors, max_iter=max_iter, max_crazy_angle=max_crazy_angle, &
     265              :                               crazy_scale=crazy_scale, crazy_use_diag=crazy_use_diag, &
     266          136 :                               eps_localization=eps_localization, iterations=sweeps, converged=converged)
     267              :          ! Possibly fallback to jacobi if the crazy rotation fails
     268          136 :          IF (.NOT. converged) THEN
     269           68 :             IF (qs_loc_env%localized_wfn_control%jacobi_fallback) THEN
     270           68 :                IF (output_unit > 0) WRITE (output_unit, "(T4,A,I6,/,T4,A)") &
     271           34 :                   " Crazy Wannier localization not converged after ", sweeps, &
     272           68 :                   " iterations, switching to jacobi rotations"
     273              :                CALL jacobi_rotations(weights, zij_fm_set, vectors, para_env, max_iter=max_iter, &
     274              :                                      eps_localization=eps_localization, sweeps=sweeps, &
     275              :                                      out_each=out_each, target_time=target_time, start_time=start_time, &
     276           68 :                                      restricted=restricted)
     277              :             ELSE
     278            0 :                IF (output_unit > 0) WRITE (output_unit, "(T4,A,I6,/,T4,A)") &
     279            0 :                   " Crazy Wannier localization not converged after ", sweeps, &
     280            0 :                   " iterations, and jacobi_fallback switched off "
     281              :             END IF
     282              :          END IF
     283              :       CASE (do_loc_direct)
     284              :          CALL direct_mini(weights, zij_fm_set, vectors, max_iter=max_iter, &
     285            2 :                           eps_localization=eps_localization, iterations=sweeps)
     286              :       CASE (do_loc_l1_norm_sd)
     287           30 :          IF (.NOT. cell%orthorhombic) THEN
     288            0 :             CPABORT("Non-orthorhombic cell with the selected method NYI")
     289              :          ELSE
     290           30 :             CALL approx_l1_norm_sd(vectors, max_iter, eps_localization, converged, sweeps)
     291              :             ! here we need to set zij for the computation of the centers and spreads
     292           30 :             CALL zij_matrix(vectors, op_sm_set, zij_fm_set)
     293              :          END IF
     294              :       CASE (do_loc_cs)
     295           78 :          ALLOCATE (my_zij_cfm_set(SIZE(zij_fm_set, 1), SIZE(zij_fm_set, 2)))
     296           18 :          DO idim1 = 1, SIZE(zij_fm_set, 1)
     297           54 :             DO idim2 = 1, SIZE(zij_fm_set, 2)
     298           36 :                CALL cp_cfm_create(my_zij_cfm_set(idim1, idim2), zij_fm_set(idim1, idim2)%matrix_struct)
     299           48 :                CALL cp_fm_to_cfm(msourcer=zij_fm_set(idim1, idim2), mtarget=my_zij_cfm_set(idim1, idim2))
     300              :             END DO
     301              :          END DO
     302            6 :          ALLOCATE (complex_vectors)
     303            6 :          CALL cp_cfm_create(complex_vectors, vectors%matrix_struct)
     304            6 :          CALL cp_fm_to_cfm(msourcer=vectors, mtarget=complex_vectors)
     305              : 
     306              :          CALL cardoso_souloumiac(weights, my_zij_cfm_set, max_iter, eps_localization, sweeps, &
     307            6 :                                  out_each, complex_vectors)
     308              : 
     309            6 :          CALL cp_cfm_to_fm(complex_vectors, mtargetr=vectors)
     310            6 :          CALL cp_cfm_release(complex_vectors)
     311            6 :          DEALLOCATE (complex_vectors)
     312           18 :          DO idim1 = 1, SIZE(my_zij_cfm_set, 1)
     313           54 :             DO idim2 = 1, SIZE(my_zij_cfm_set, 2)
     314           48 :                CALL cp_cfm_release(my_zij_cfm_set(idim1, idim2))
     315              :             END DO
     316              :          END DO
     317           12 :          DEALLOCATE (my_zij_cfm_set)
     318              : 
     319              :       CASE (do_loc_none)
     320            0 :          IF (output_unit > 0) THEN
     321            0 :             WRITE (output_unit, '(T4,A,I6,A)') " No MOS localization applied "
     322              :          END IF
     323              :       CASE DEFAULT
     324          500 :          CPABORT("Unknown localization method")
     325              :       END SELECT
     326          500 :       IF (output_unit > 0) THEN
     327          438 :          IF (sweeps <= max_iter) WRITE (output_unit, '(T4,A,I3,A,I6,A)') " Localization  for spin ", ispin, &
     328          376 :             " converged in ", sweeps, " iterations"
     329              :       END IF
     330              : 
     331              :       CALL centers_spreads_berry(qs_loc_env, nmoloc, cell, weights, &
     332          500 :                                  ispin, print_loc_section, zij=zij_fm_set)
     333              : 
     334          500 :       CALL cp_print_key_finished_output(output_unit, logger, print_loc_section, "PROGRAM_RUN_INFO")
     335              : 
     336          500 :       CALL timestop(handle)
     337              : 
     338          500 :    END SUBROUTINE optimize_loc_berry
     339              : 
     340              : ! **************************************************************************************************
     341              : !> \brief ...
     342              : !> \param qs_env ...
     343              : !> \param method ...
     344              : !> \param qs_loc_env ...
     345              : !> \param vectors ...
     346              : !> \param zij_fm_set ...
     347              : !> \param ispin ...
     348              : !> \param print_loc_section ...
     349              : !> \par History
     350              : !>      04.2005 created [MI]
     351              : !> \author MI
     352              : ! **************************************************************************************************
     353            6 :    SUBROUTINE optimize_loc_pipek(qs_env, method, qs_loc_env, vectors, zij_fm_set, &
     354              :                                  ispin, print_loc_section)
     355              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     356              :       INTEGER, INTENT(IN)                                :: method
     357              :       TYPE(qs_loc_env_type), POINTER                     :: qs_loc_env
     358              :       TYPE(cp_fm_type), INTENT(IN)                       :: vectors
     359              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN)      :: zij_fm_set
     360              :       INTEGER, INTENT(IN)                                :: ispin
     361              :       TYPE(section_vals_type), POINTER                   :: print_loc_section
     362              : 
     363              :       CHARACTER(len=*), PARAMETER :: routineN = 'optimize_loc_pipek'
     364              : 
     365              :       INTEGER                                            :: handle, iatom, idim1, idim2, isgf, ldz, &
     366              :                                                             max_iter, nao, natom, ncol, nmoloc, &
     367              :                                                             out_each, output_unit, sweeps
     368              :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: first_sgf, last_sgf, nsgf
     369              :       REAL(dp)                                           :: eps
     370            6 :       TYPE(cp_cfm_type), POINTER                         :: complex_vectors, my_zij_cfm_set(:, :)
     371            6 :       TYPE(cp_fm_pool_p_type), DIMENSION(:), POINTER     :: ao_ao_fm_pools
     372              :       TYPE(cp_fm_type)                                   :: opvec
     373              :       TYPE(cp_fm_type), POINTER                          :: ov_fm
     374              :       TYPE(cp_logger_type), POINTER                      :: logger
     375            6 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     376            6 :       TYPE(molecule_type), DIMENSION(:), POINTER         :: mols
     377            6 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     378            6 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     379              : 
     380            6 :       NULLIFY (mols, ov_fm)
     381              : 
     382            6 :       CALL timeset(routineN, handle)
     383            6 :       logger => cp_get_default_logger()
     384              :       output_unit = cp_print_key_unit_nr(logger, print_loc_section, "PROGRAM_RUN_INFO", &
     385            6 :                                          extension=".locInfo")
     386              : 
     387            6 :       NULLIFY (particle_set)
     388              :       ! get rows and cols of the input
     389            6 :       CALL cp_fm_get_info(vectors, nrow_global=nao, ncol_global=nmoloc)
     390              : 
     391              :       ! replicate the input kind of matrix
     392            6 :       CALL cp_fm_create(opvec, vectors%matrix_struct)
     393            6 :       CALL cp_fm_set_all(opvec, 0.0_dp)
     394              : 
     395              :       CALL get_qs_env(qs_env=qs_env, matrix_s=matrix_s, &
     396            6 :                       particle_set=particle_set, qs_kind_set=qs_kind_set, molecule_set=mols)
     397              : 
     398              :       ! localization options
     399            6 :       max_iter = qs_loc_env%localized_wfn_control%max_iter
     400            6 :       eps = qs_loc_env%localized_wfn_control%eps_localization
     401            6 :       out_each = qs_loc_env%localized_wfn_control%out_each
     402              : 
     403            6 :       natom = SIZE(particle_set, 1)
     404           18 :       ALLOCATE (first_sgf(natom))
     405           12 :       ALLOCATE (last_sgf(natom))
     406           12 :       ALLOCATE (nsgf(natom))
     407              : 
     408              :       !   construction of
     409              :       CALL get_particle_set(particle_set, qs_kind_set, &
     410            6 :                             first_sgf=first_sgf, last_sgf=last_sgf, nsgf=nsgf)
     411              : 
     412              :       !   Copy the overlap sparse matrix in a full matrix
     413            6 :       CALL mpools_get(qs_env%mpools, ao_ao_fm_pools=ao_ao_fm_pools)
     414            6 :       ALLOCATE (ov_fm)
     415            6 :       CALL fm_pool_create_fm(ao_ao_fm_pools(1)%pool, ov_fm, name=" ")
     416            6 :       CALL copy_dbcsr_to_fm(matrix_s(1)%matrix, ov_fm)
     417              : 
     418              :       !   Compute zij here
     419           78 :       DO iatom = 1, natom
     420           72 :          CALL cp_fm_set_all(zij_fm_set(iatom, 1), 0.0_dp)
     421           72 :          CALL cp_fm_get_info(zij_fm_set(iatom, 1), ncol_global=ldz)
     422           72 :          isgf = first_sgf(iatom)
     423           72 :          ncol = nsgf(iatom)
     424              : 
     425              :          ! multiply fmxfm, using only part of the ao : Ct x S
     426              :          CALL parallel_gemm('N', 'N', nao, nmoloc, nao, 1.0_dp, ov_fm, vectors, 0.0_dp, opvec, &
     427           72 :                             a_first_col=1, a_first_row=1, b_first_col=1, b_first_row=1)
     428              : 
     429              :          CALL parallel_gemm('T', 'N', nmoloc, nmoloc, ncol, 0.5_dp, vectors, opvec, &
     430              :                             0.0_dp, zij_fm_set(iatom, 1), &
     431           72 :                             a_first_col=1, a_first_row=isgf, b_first_col=1, b_first_row=isgf)
     432              : 
     433              :          CALL parallel_gemm('N', 'N', nao, nmoloc, ncol, 1.0_dp, ov_fm, vectors, 0.0_dp, opvec, &
     434           72 :                             a_first_col=isgf, a_first_row=1, b_first_col=1, b_first_row=isgf)
     435              : 
     436              :          CALL parallel_gemm('T', 'N', nmoloc, nmoloc, nao, 0.5_dp, vectors, opvec, &
     437              :                             1.0_dp, zij_fm_set(iatom, 1), &
     438          150 :                             a_first_col=1, a_first_row=1, b_first_col=1, b_first_row=1)
     439              : 
     440              :       END DO ! iatom
     441              : 
     442              :       !   And now perform the optimization and rotate the orbitals
     443            6 :       SELECT CASE (method)
     444              :       CASE (do_loc_jacobi)
     445            0 :          CALL jacobi_rotation_pipek(zij_fm_set, vectors, sweeps)
     446              :       CASE (do_loc_gapo)
     447            0 :          CPABORT("GAPO and Pipek not implemented.")
     448              :       CASE (do_loc_crazy)
     449            0 :          CPABORT("Crazy and Pipek not implemented.")
     450              :       CASE (do_loc_l1_norm_sd)
     451            0 :          CPABORT("L1 norm and Pipek not implemented.")
     452              :       CASE (do_loc_direct)
     453            0 :          CPABORT("Direct and Pipek not implemented.")
     454              :       CASE (do_loc_cs)
     455          102 :          ALLOCATE (my_zij_cfm_set(SIZE(zij_fm_set, 1), SIZE(zij_fm_set, 2)))
     456           78 :          DO idim1 = 1, SIZE(zij_fm_set, 1)
     457          150 :             DO idim2 = 1, SIZE(zij_fm_set, 2)
     458           72 :                CALL cp_cfm_create(my_zij_cfm_set(idim1, idim2), zij_fm_set(idim1, idim2)%matrix_struct)
     459          144 :                CALL cp_fm_to_cfm(msourcer=zij_fm_set(idim1, idim2), mtarget=my_zij_cfm_set(idim1, idim2))
     460              :             END DO
     461              :          END DO
     462            6 :          ALLOCATE (complex_vectors)
     463            6 :          CALL cp_cfm_create(complex_vectors, vectors%matrix_struct)
     464            6 :          CALL cp_fm_to_cfm(msourcer=vectors, mtarget=complex_vectors)
     465              : 
     466            6 :          CALL cardoso_souloumiac_pipek(my_zij_cfm_set, complex_vectors, sweeps, max_iter, eps, out_each)
     467              : 
     468            6 :          CALL cp_cfm_to_fm(complex_vectors, mtargetr=vectors)
     469            6 :          CALL cp_cfm_release(complex_vectors)
     470            6 :          DEALLOCATE (complex_vectors)
     471           78 :          DO idim1 = 1, SIZE(my_zij_cfm_set, 1)
     472          150 :             DO idim2 = 1, SIZE(my_zij_cfm_set, 2)
     473          144 :                CALL cp_cfm_release(my_zij_cfm_set(idim1, idim2))
     474              :             END DO
     475              :          END DO
     476           12 :          DEALLOCATE (my_zij_cfm_set)
     477              : 
     478              :       CASE (do_loc_none)
     479            0 :          IF (output_unit > 0) WRITE (output_unit, '(A,I6,A)') " No MOS localization applied "
     480              :       CASE DEFAULT
     481            6 :          CPABORT("Unknown localization method")
     482              :       END SELECT
     483              : 
     484            9 :       IF (output_unit > 0) WRITE (output_unit, '(A,I3,A,I6,A)') " Localization  for spin ", ispin, &
     485            6 :          " converged in ", sweeps, " iterations"
     486              : 
     487              :       CALL centers_spreads_pipek(qs_loc_env, zij_fm_set, particle_set, ispin, &
     488            6 :                                  print_loc_section)
     489              : 
     490            6 :       DEALLOCATE (first_sgf, last_sgf, nsgf)
     491              : 
     492            6 :       CALL cp_fm_release(opvec)
     493            6 :       CALL cp_fm_release(ov_fm)
     494            6 :       DEALLOCATE (ov_fm)
     495            6 :       CALL cp_print_key_finished_output(output_unit, logger, print_loc_section, "PROGRAM_RUN_INFO")
     496              : 
     497            6 :       CALL timestop(handle)
     498              : 
     499           18 :    END SUBROUTINE optimize_loc_pipek
     500              : 
     501              : ! **************************************************************************************************
     502              : !> \brief 2by2 rotation for the pipek operator
     503              : !>       in this case the z_ij numbers are reals
     504              : !> \param zij_fm_set ...
     505              : !> \param vectors ...
     506              : !> \param sweeps ...
     507              : !> \par History
     508              : !>       05-2005 created
     509              : !> \author MI
     510              : ! **************************************************************************************************
     511            0 :    SUBROUTINE jacobi_rotation_pipek(zij_fm_set, vectors, sweeps)
     512              : 
     513              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN)      :: zij_fm_set
     514              :       TYPE(cp_fm_type), INTENT(IN)                       :: vectors
     515              :       INTEGER                                            :: sweeps
     516              : 
     517              :       INTEGER                                            :: iatom, istate, jstate, natom, nstate
     518              :       REAL(KIND=dp)                                      :: aij, bij, ct, mii, mij, mjj, ratio, st, &
     519              :                                                             theta, tolerance
     520              :       TYPE(cp_fm_type)                                   :: rmat
     521              : 
     522            0 :       CALL cp_fm_create(rmat, zij_fm_set(1, 1)%matrix_struct)
     523            0 :       CALL cp_fm_set_all(rmat, 0.0_dp, 1.0_dp)
     524              : 
     525            0 :       CALL cp_fm_get_info(rmat, nrow_global=nstate)
     526            0 :       tolerance = 1.0e10_dp
     527            0 :       sweeps = 0
     528            0 :       natom = SIZE(zij_fm_set, 1)
     529              :       ! do jacobi sweeps until converged
     530            0 :       DO WHILE (tolerance >= 1.0e-4_dp)
     531            0 :          sweeps = sweeps + 1
     532            0 :          DO istate = 1, nstate
     533            0 :             DO jstate = istate + 1, nstate
     534              :                aij = 0.0_dp
     535              :                bij = 0.0_dp
     536            0 :                DO iatom = 1, natom
     537            0 :                   CALL cp_fm_get_element(zij_fm_set(iatom, 1), istate, istate, mii)
     538            0 :                   CALL cp_fm_get_element(zij_fm_set(iatom, 1), istate, jstate, mij)
     539            0 :                   CALL cp_fm_get_element(zij_fm_set(iatom, 1), jstate, jstate, mjj)
     540            0 :                   aij = aij + mij*(mii - mjj)
     541            0 :                   bij = bij + mij*mij - 0.25_dp*(mii - mjj)*(mii - mjj)
     542              :                END DO
     543            0 :                IF (ABS(bij) > 1.E-10_dp) THEN
     544            0 :                   ratio = -aij/bij
     545            0 :                   theta = 0.25_dp*ATAN(ratio)
     546              :                ELSE
     547            0 :                   bij = 0.0_dp
     548              :                   theta = 0.0_dp
     549              :                END IF
     550              :                ! Check max or min
     551              :                ! To minimize the spread
     552            0 :                IF (theta > pi*0.5_dp) THEN
     553            0 :                   theta = theta - pi*0.25_dp
     554            0 :                ELSE IF (theta < -pi*0.5_dp) THEN
     555            0 :                   theta = theta + pi*0.25_dp
     556              :                END IF
     557              : 
     558            0 :                ct = COS(theta)
     559            0 :                st = SIN(theta)
     560              : 
     561            0 :                CALL cp_fm_rot_cols(rmat, istate, jstate, ct, st)
     562              : 
     563            0 :                DO iatom = 1, natom
     564            0 :                   CALL cp_fm_rot_cols(zij_fm_set(iatom, 1), istate, jstate, ct, st)
     565            0 :                   CALL cp_fm_rot_rows(zij_fm_set(iatom, 1), istate, jstate, ct, st)
     566              :                END DO
     567              :             END DO
     568              :          END DO
     569            0 :          CALL check_tolerance_real(zij_fm_set, tolerance)
     570              :       END DO
     571              : 
     572            0 :       CALL rotate_orbitals(rmat, vectors)
     573            0 :       CALL cp_fm_release(rmat)
     574              : 
     575            0 :    END SUBROUTINE jacobi_rotation_pipek
     576              : 
     577              : ! **************************************************************************************************
     578              : !> \brief ...
     579              : !> \param zij_fm_set ...
     580              : !> \param tolerance ...
     581              : !> \par History
     582              : !>      04.2005 created [MI]
     583              : !> \author MI
     584              : ! **************************************************************************************************
     585            0 :    SUBROUTINE check_tolerance_real(zij_fm_set, tolerance)
     586              : 
     587              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN)      :: zij_fm_set
     588              :       REAL(dp), INTENT(OUT)                              :: tolerance
     589              : 
     590              :       INTEGER                                            :: iatom, istate, jstate, natom, &
     591              :                                                             ncol_local, nrow_global, nrow_local
     592            0 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     593              :       REAL(dp)                                           :: grad_ij, zii, zij, zjj
     594            0 :       REAL(dp), DIMENSION(:, :), POINTER                 :: diag
     595              :       TYPE(cp_fm_type)                                   :: force
     596              : 
     597            0 :       CALL cp_fm_create(force, zij_fm_set(1, 1)%matrix_struct)
     598            0 :       CALL cp_fm_set_all(force, 0._dp)
     599              : 
     600            0 :       NULLIFY (diag, col_indices, row_indices)
     601            0 :       natom = SIZE(zij_fm_set, 1)
     602              :       CALL cp_fm_get_info(zij_fm_set(1, 1), nrow_local=nrow_local, &
     603              :                           ncol_local=ncol_local, nrow_global=nrow_global, &
     604            0 :                           row_indices=row_indices, col_indices=col_indices)
     605            0 :       ALLOCATE (diag(nrow_global, natom))
     606              : 
     607            0 :       DO iatom = 1, natom
     608            0 :          DO istate = 1, nrow_global
     609            0 :             CALL cp_fm_get_element(zij_fm_set(iatom, 1), istate, istate, diag(istate, iatom))
     610              :          END DO
     611              :       END DO
     612              : 
     613            0 :       DO istate = 1, nrow_local
     614            0 :          DO jstate = 1, ncol_local
     615              :             grad_ij = 0.0_dp
     616            0 :             DO iatom = 1, natom
     617            0 :                zii = diag(row_indices(istate), iatom)
     618            0 :                zjj = diag(col_indices(jstate), iatom)
     619            0 :                zij = zij_fm_set(iatom, 1)%local_data(istate, jstate)
     620            0 :                grad_ij = grad_ij + 4.0_dp*zij*(zjj - zii)
     621              :             END DO
     622            0 :             force%local_data(istate, jstate) = grad_ij
     623              :          END DO
     624              :       END DO
     625              : 
     626            0 :       DEALLOCATE (diag)
     627              : 
     628            0 :       CALL cp_fm_maxabsval(force, tolerance)
     629            0 :       CALL cp_fm_release(force)
     630              : 
     631            0 :    END SUBROUTINE check_tolerance_real
     632              : ! **************************************************************************************************
     633              : !> \brief ...
     634              : !> \param qs_loc_env ...
     635              : !> \param nmoloc ...
     636              : !> \param cell ...
     637              : !> \param weights ...
     638              : !> \param ispin ...
     639              : !> \param print_loc_section ...
     640              : !> \param zij ...
     641              : !> \param c_zij ...
     642              : !> \param only_initial_out ...
     643              : !> \par History
     644              : !>      04.2005 created [MI]
     645              : !> \author MI
     646              : ! **************************************************************************************************
     647         1112 :    SUBROUTINE centers_spreads_berry(qs_loc_env, nmoloc, cell, weights, ispin, &
     648         1112 :                                     print_loc_section, zij, c_zij, only_initial_out)
     649              :       TYPE(qs_loc_env_type), POINTER                     :: qs_loc_env
     650              :       INTEGER, INTENT(IN)                                :: nmoloc
     651              :       TYPE(cell_type), POINTER                           :: cell
     652              :       REAL(dp), DIMENSION(:)                             :: weights
     653              :       INTEGER, INTENT(IN)                                :: ispin
     654              :       TYPE(section_vals_type), POINTER                   :: print_loc_section
     655              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN), &
     656              :          OPTIONAL                                        :: zij
     657              :       TYPE(cp_cfm_p_type), INTENT(INOUT), OPTIONAL       :: c_zij(:, :)
     658              :       LOGICAL, INTENT(IN), OPTIONAL                      :: only_initial_out
     659              : 
     660              :       CHARACTER(len=default_path_length)                 :: file_tmp, iter
     661              :       COMPLEX(KIND=dp)                                   :: z
     662              :       INTEGER                                            :: idir, istate, jdir, nstates, &
     663              :                                                             output_unit, unit_out_s
     664              :       LOGICAL                                            :: my_only_init, zij_is_complex
     665              :       REAL(dp)                                           :: avg_spread_ii, spread_i, spread_ii, &
     666              :                                                             sum_spread_i, sum_spread_ii
     667              :       REAL(dp), DIMENSION(3)                             :: c, c2, cpbc
     668         1112 :       REAL(dp), DIMENSION(:, :), POINTER                 :: centers
     669              :       REAL(KIND=dp)                                      :: imagpart, realpart
     670              :       TYPE(cp_logger_type), POINTER                      :: logger
     671              :       TYPE(section_vals_type), POINTER                   :: print_key
     672              : 
     673         1112 :       NULLIFY (centers, logger, print_key)
     674         2224 :       logger => cp_get_default_logger()
     675         1112 :       my_only_init = .FALSE.
     676         1112 :       IF (PRESENT(only_initial_out)) my_only_init = only_initial_out
     677         1112 :       IF (PRESENT(zij)) THEN
     678         1112 :          zij_is_complex = .FALSE.
     679         1112 :          CPASSERT(.NOT. PRESENT(c_zij))
     680         1112 :          CALL cp_fm_get_info(zij(1, 1), nrow_global=nstates)
     681              :       ELSE
     682            0 :          zij_is_complex = .TRUE.
     683            0 :          CPASSERT(PRESENT(c_zij))
     684            0 :          CALL cp_cfm_get_info(c_zij(1, 1)%matrix, nrow_global=nstates)
     685              :       END IF
     686              : 
     687         1112 :       file_tmp = TRIM(qs_loc_env%tag_mo)//"_spreads_s"//TRIM(ADJUSTL(cp_to_string(ispin)))
     688              :       output_unit = cp_print_key_unit_nr(logger, print_loc_section, "PROGRAM_RUN_INFO", &
     689         1112 :                                          extension=".locInfo")
     690              :       unit_out_s = cp_print_key_unit_nr(logger, print_loc_section, "WANNIER_SPREADS", &
     691         1112 :                                         middle_name=file_tmp, extension=".data")
     692         1112 :       iter = cp_iter_string(logger%iter_info)
     693         1112 :       IF (unit_out_s > 0 .AND. .NOT. my_only_init) WRITE (unit_out_s, '(i6,/,A)') nmoloc, TRIM(iter)
     694              : 
     695         1112 :       CPASSERT(nstates >= nmoloc)
     696              : 
     697         1112 :       centers => qs_loc_env%localized_wfn_control%centers_set(ispin)%array
     698         1112 :       CPASSERT(ASSOCIATED(centers))
     699         1112 :       CPASSERT(SIZE(centers, 2) == nmoloc)
     700         1112 :       sum_spread_i = 0.0_dp
     701         1112 :       sum_spread_ii = 0.0_dp
     702         1112 :       avg_spread_ii = 0.0_dp
     703         9078 :       DO istate = 1, nmoloc
     704         7966 :          c = 0.0_dp
     705              :          c2 = 0.0_dp
     706         7966 :          spread_i = 0.0_dp
     707         7966 :          spread_ii = 0.0_dp
     708         7966 :          IF (.NOT. zij_is_complex) THEN
     709        32416 :             DO jdir = 1, SIZE(zij, 2)
     710        24450 :                CALL cp_fm_get_element(zij(1, jdir), istate, istate, realpart)
     711        24450 :                CALL cp_fm_get_element(zij(2, jdir), istate, istate, imagpart)
     712        24450 :                z = CMPLX(realpart, imagpart, dp)
     713              :                spread_i = spread_i - weights(jdir)* &
     714        24450 :                           LOG(realpart*realpart + imagpart*imagpart)/twopi/twopi
     715              :                spread_ii = spread_ii + weights(jdir)* &
     716        24450 :                            (1.0_dp - (realpart*realpart + imagpart*imagpart))/twopi/twopi
     717        32416 :                IF (jdir < 4) THEN
     718        95592 :                   DO idir = 1, 3
     719              :                      c(idir) = c(idir) + &
     720        95592 :                                (cell%hmat(idir, jdir)/twopi)*AIMAG(LOG(z))
     721              :                   END DO
     722              :                END IF
     723              :             END DO
     724              :          ELSE
     725            0 :             DO jdir = 1, SIZE(c_zij, 2)
     726            0 :                CALL cp_cfm_get_element(c_zij(1, jdir)%matrix, istate, istate, z)
     727            0 :                realpart = REAL(z, dp)
     728            0 :                imagpart = AIMAG(z)
     729              :                spread_i = spread_i - weights(jdir)* &
     730            0 :                           LOG(realpart*realpart + imagpart*imagpart)/twopi/twopi
     731              :                spread_ii = spread_ii + weights(jdir)* &
     732            0 :                            (1.0_dp - (realpart*realpart + imagpart*imagpart))/twopi/twopi
     733            0 :                IF (jdir < 4) THEN
     734            0 :                   DO idir = 1, 3
     735              :                      c(idir) = c(idir) + &
     736            0 :                                (cell%hmat(idir, jdir)/twopi)*AIMAG(LOG(z))
     737              :                   END DO
     738              :                END IF
     739              :             END DO
     740              :          END IF
     741         7966 :          cpbc = pbc(c, cell)
     742        31864 :          centers(1:3, istate) = cpbc(1:3)
     743         7966 :          centers(4, istate) = spread_i
     744         7966 :          centers(5, istate) = spread_ii
     745         7966 :          sum_spread_i = sum_spread_i + centers(4, istate)
     746         7966 :          sum_spread_ii = sum_spread_ii + centers(5, istate)
     747         9134 :          IF (unit_out_s > 0 .AND. .NOT. my_only_init) WRITE (unit_out_s, '(I6,2F16.8)') istate, centers(4:5, istate)
     748              :       END DO
     749         1112 :       avg_spread_ii = sum_spread_ii/REAL(nmoloc, KIND=dp)
     750              : 
     751              :       ! Print of wannier centers
     752         1112 :       print_key => section_vals_get_subs_vals(print_loc_section, "WANNIER_CENTERS")
     753         1112 :       IF (.NOT. my_only_init) CALL print_wannier_centers(qs_loc_env, print_key, centers, logger, ispin)
     754              : 
     755         1112 :       IF (output_unit > 0) THEN
     756          500 :          WRITE (output_unit, '(T4, A, 2x, 2A26,/,T23, A28)') " Spread Functional ", "sum_in -w_i ln(|z_in|^2)", &
     757         1000 :             "sum_in w_i(1-|z_in|^2)", "sum_in w_i(1-|z_in|^2)/n"
     758          500 :          IF (my_only_init) THEN
     759          250 :             WRITE (output_unit, '(T4,A,T38,2F20.10,/,T38,F20.10)') " Initial Spread (Berry) : ", &
     760          500 :                sum_spread_i, sum_spread_ii, avg_spread_ii
     761              :          ELSE
     762          250 :             WRITE (output_unit, '(T4,A,T38,2F20.10,/,T38,F20.10)') " Total Spread (Berry) : ", &
     763          500 :                sum_spread_i, sum_spread_ii, avg_spread_ii
     764              :          END IF
     765              :       END IF
     766              : 
     767         1112 :       IF (unit_out_s > 0 .AND. .NOT. my_only_init) WRITE (unit_out_s, '(A,2F16.10)') " Total ", sum_spread_i, sum_spread_ii
     768              : 
     769         1112 :       CALL cp_print_key_finished_output(unit_out_s, logger, print_loc_section, "WANNIER_SPREADS")
     770         1112 :       CALL cp_print_key_finished_output(output_unit, logger, print_loc_section, "PROGRAM_RUN_INFO")
     771              : 
     772         1112 :    END SUBROUTINE centers_spreads_berry
     773              : 
     774              : ! **************************************************************************************************
     775              : !> \brief define and print the centers and spread
     776              : !>       when the pipek operator is used
     777              : !> \param qs_loc_env ...
     778              : !> \param zij_fm_set matrix elements that define the populations on atoms
     779              : !> \param particle_set ...
     780              : !> \param ispin spin 1 or 2
     781              : !> \param print_loc_section ...
     782              : !> \par History
     783              : !>      05.2005 created [MI]
     784              : ! **************************************************************************************************
     785            6 :    SUBROUTINE centers_spreads_pipek(qs_loc_env, zij_fm_set, particle_set, ispin, &
     786              :                                     print_loc_section)
     787              : 
     788              :       TYPE(qs_loc_env_type), POINTER                     :: qs_loc_env
     789              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN)      :: zij_fm_set
     790              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     791              :       INTEGER, INTENT(IN)                                :: ispin
     792              :       TYPE(section_vals_type), POINTER                   :: print_loc_section
     793              : 
     794              :       CHARACTER(len=default_path_length)                 :: file_tmp, iter
     795              :       INTEGER                                            :: iatom, istate, natom, nstate, unit_out_s
     796            6 :       INTEGER, DIMENSION(:), POINTER                     :: atom_of_state
     797              :       REAL(dp)                                           :: r(3)
     798            6 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: Qii, ziimax
     799            6 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: diag
     800            6 :       REAL(dp), DIMENSION(:, :), POINTER                 :: centers
     801              :       TYPE(cp_logger_type), POINTER                      :: logger
     802              :       TYPE(section_vals_type), POINTER                   :: print_key
     803              : 
     804            6 :       NULLIFY (centers, logger, print_key)
     805           12 :       logger => cp_get_default_logger()
     806              : 
     807            6 :       CALL cp_fm_get_info(zij_fm_set(1, 1), nrow_global=nstate)
     808            6 :       natom = SIZE(zij_fm_set, 1)
     809              : 
     810            6 :       centers => qs_loc_env%localized_wfn_control%centers_set(ispin)%array
     811            6 :       CPASSERT(ASSOCIATED(centers))
     812            6 :       CPASSERT(SIZE(centers, 2) == nstate)
     813              : 
     814            6 :       file_tmp = TRIM(qs_loc_env%tag_mo)//"_spreads_s"//TRIM(ADJUSTL(cp_to_string(ispin)))
     815              :       unit_out_s = cp_print_key_unit_nr(logger, print_loc_section, "WANNIER_SPREADS", &
     816            6 :                                         middle_name=file_tmp, extension=".data", log_filename=.FALSE.)
     817            6 :       iter = cp_iter_string(logger%iter_info)
     818            6 :       IF (unit_out_s > 0) WRITE (unit_out_s, '(i6,/,A)') TRIM(iter)
     819              : 
     820           18 :       ALLOCATE (atom_of_state(nstate))
     821          198 :       atom_of_state = 0
     822              : 
     823           24 :       ALLOCATE (diag(nstate, natom))
     824            6 :       diag = 0.0_dp
     825              : 
     826           78 :       DO iatom = 1, natom
     827         2382 :          DO istate = 1, nstate
     828         2376 :             CALL cp_fm_get_element(zij_fm_set(iatom, 1), istate, istate, diag(istate, iatom))
     829              :          END DO
     830              :       END DO
     831              : 
     832           24 :       ALLOCATE (Qii(nstate), ziimax(nstate))
     833            6 :       ziimax = 0.0_dp
     834            6 :       Qii = 0.0_dp
     835              : 
     836           78 :       DO iatom = 1, natom
     837         2382 :          DO istate = 1, nstate
     838         2304 :             Qii(istate) = Qii(istate) + diag(istate, iatom)*diag(istate, iatom)
     839         2376 :             IF (ABS(diag(istate, iatom)) > ziimax(istate)) THEN
     840          706 :                ziimax(istate) = ABS(diag(istate, iatom))
     841          706 :                atom_of_state(istate) = iatom
     842              :             END IF
     843              :          END DO
     844              :       END DO
     845              : 
     846          198 :       DO istate = 1, nstate
     847          192 :          iatom = atom_of_state(istate)
     848          768 :          r(1:3) = particle_set(iatom)%r(1:3)
     849          768 :          centers(1:3, istate) = r(1:3)
     850          192 :          centers(4, istate) = 1.0_dp/Qii(istate)
     851          198 :          IF (unit_out_s > 0) WRITE (unit_out_s, '(I6,F16.8)') istate, angstrom*centers(4, istate)
     852              :       END DO
     853              : 
     854              :       ! Print the wannier centers
     855            6 :       print_key => section_vals_get_subs_vals(print_loc_section, "WANNIER_CENTERS")
     856            6 :       CALL print_wannier_centers(qs_loc_env, print_key, centers, logger, ispin)
     857              : 
     858            6 :       CALL cp_print_key_finished_output(unit_out_s, logger, print_loc_section, "WANNIER_SPREADS")
     859              : 
     860            6 :       DEALLOCATE (Qii, ziimax, atom_of_state, diag)
     861              : 
     862            6 :    END SUBROUTINE centers_spreads_pipek
     863              : 
     864              : ! **************************************************************************************************
     865              : !> \brief write the cube files for a set of selected states
     866              : !> \param qs_env ...
     867              : !> \param mo_coeff set mos from which the states to be printed are extracted
     868              : !> \param nstates number of states to be printed
     869              : !> \param state_list list of the indexes of the states to be printed
     870              : !> \param centers centers and spread, all=0 if they hva not been calculated
     871              : !> \param print_key ...
     872              : !> \param root initial part of the cube file names
     873              : !> \param ispin ...
     874              : !> \param idir ...
     875              : !> \param state0 ...
     876              : !> \param file_position ...
     877              : !> \par History
     878              : !>      08.2005 created [MI]
     879              : !> \author MI
     880              : !> \note
     881              : !>      This routine should not be in this module
     882              : ! **************************************************************************************************
     883           12 :    SUBROUTINE qs_print_cubes(qs_env, mo_coeff, nstates, state_list, centers, &
     884              :                              print_key, root, ispin, idir, state0, file_position)
     885              : 
     886              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     887              :       TYPE(cp_fm_type), INTENT(IN)                       :: mo_coeff
     888              :       INTEGER, INTENT(IN)                                :: nstates
     889              :       INTEGER, DIMENSION(:), POINTER                     :: state_list
     890              :       REAL(dp), DIMENSION(:, :), POINTER                 :: centers
     891              :       TYPE(section_vals_type), POINTER                   :: print_key
     892              :       CHARACTER(LEN=*)                                   :: root
     893              :       INTEGER, INTENT(IN), OPTIONAL                      :: ispin, idir
     894              :       INTEGER, OPTIONAL                                  :: state0
     895              :       CHARACTER(LEN=default_string_length), OPTIONAL     :: file_position
     896              : 
     897              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_print_cubes'
     898              :       CHARACTER, DIMENSION(3), PARAMETER                 :: labels = ['x', 'y', 'z']
     899              : 
     900              :       CHARACTER                                          :: label
     901              :       CHARACTER(LEN=default_path_length)                 :: file_tmp, filename, my_pos
     902              :       CHARACTER(LEN=default_string_length)               :: title
     903              :       INTEGER                                            :: handle, ia, ie, istate, ivector, &
     904              :                                                             my_ispin, my_state0, unit_out_c
     905              :       LOGICAL                                            :: add_idir, add_spin, mpi_io
     906           12 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     907              :       TYPE(cell_type), POINTER                           :: cell
     908              :       TYPE(cp_logger_type), POINTER                      :: logger
     909              :       TYPE(dft_control_type), POINTER                    :: dft_control
     910              :       TYPE(particle_list_type), POINTER                  :: particles
     911           12 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     912              :       TYPE(pw_c1d_gs_type)                               :: wf_g
     913              :       TYPE(pw_env_type), POINTER                         :: pw_env
     914              :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
     915              :       TYPE(pw_r3d_rs_type)                               :: wf_r
     916           12 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     917              :       TYPE(qs_subsys_type), POINTER                      :: subsys
     918              : 
     919           12 :       CALL timeset(routineN, handle)
     920           12 :       logger => cp_get_default_logger()
     921              : 
     922           12 :       CALL get_qs_env(qs_env=qs_env, pw_env=pw_env, subsys=subsys)
     923           12 :       CALL qs_subsys_get(subsys, particles=particles)
     924              : 
     925           12 :       CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
     926              : 
     927           12 :       CALL auxbas_pw_pool%create_pw(wf_r)
     928           12 :       CALL auxbas_pw_pool%create_pw(wf_g)
     929              : 
     930           12 :       my_state0 = 0
     931           12 :       IF (PRESENT(state0)) my_state0 = state0
     932              : 
     933           12 :       add_spin = .FALSE.
     934           12 :       my_ispin = 1
     935           12 :       IF (PRESENT(ispin)) THEN
     936            8 :          add_spin = .TRUE.
     937            8 :          my_ispin = ispin
     938              :       END IF
     939           12 :       add_idir = .FALSE.
     940           12 :       IF (PRESENT(idir)) THEN
     941            0 :          add_idir = .TRUE.
     942            0 :          label = labels(idir)
     943              :       END IF
     944              : 
     945           12 :       my_pos = "REWIND"
     946           12 :       IF (PRESENT(file_position)) THEN
     947           12 :          my_pos = file_position
     948              :       END IF
     949              : 
     950           62 :       DO istate = 1, nstates
     951           50 :          ivector = state_list(istate) - my_state0
     952              :          CALL get_qs_env(qs_env=qs_env, atomic_kind_set=atomic_kind_set, qs_kind_set=qs_kind_set, cell=cell, &
     953           50 :                          dft_control=dft_control, particle_set=particle_set, pw_env=pw_env)
     954              : 
     955              :          CALL calculate_wavefunction(mo_coeff, ivector, wf_r, wf_g, atomic_kind_set, &
     956           50 :                                      qs_kind_set, cell, dft_control, particle_set, pw_env)
     957              : 
     958              :          ! Formatting the middle part of the name
     959           50 :          ivector = state_list(istate)
     960           50 :          CALL xstring(root, ia, ie)
     961           50 :          IF (add_idir) THEN
     962            0 :             filename = root(ia:ie)//"_"//label//"_w"//TRIM(ADJUSTL(cp_to_string(ivector)))
     963              :          ELSE
     964           50 :             filename = root(ia:ie)//"_w"//TRIM(ADJUSTL(cp_to_string(ivector)))
     965              :          END IF
     966           50 :          IF (add_spin) THEN
     967           38 :             file_tmp = filename
     968           38 :             CALL xstring(file_tmp, ia, ie)
     969           38 :             filename = file_tmp(ia:ie)//"_s"//TRIM(ADJUSTL(cp_to_string(ispin)))
     970              :          END IF
     971              : 
     972              :          ! Using the print_key tools to open the file with the proper name
     973           50 :          mpi_io = .TRUE.
     974              :          unit_out_c = cp_print_key_unit_nr(logger, print_key, "", middle_name=filename, &
     975              :                                            extension=".cube", file_position=my_pos, log_filename=.FALSE., &
     976           50 :                                            mpi_io=mpi_io)
     977           50 :          IF (SIZE(centers, 1) == 6) THEN
     978           50 :             WRITE (title, '(A7,I5.5,A2,I1.1,A1,6F10.4)') "WFN ", ivector, "_s", my_ispin, " ", &
     979          400 :                centers(1:3, istate)*angstrom, centers(4:6, istate)*angstrom
     980              :          ELSE
     981            0 :             WRITE (title, '(A7,I5.5,A2,I1.1,A1,3F10.4)') "WFN ", ivector, "_s", my_ispin, " ", &
     982            0 :                centers(1:3, istate)*angstrom
     983              :          END IF
     984              :          CALL cp_pw_to_cube(wf_r, unit_out_c, title, &
     985              :                             particles=particles, &
     986           50 :                             stride=section_get_ivals(print_key, "STRIDE"), mpi_io=mpi_io)
     987           62 :          CALL cp_print_key_finished_output(unit_out_c, logger, print_key, "", mpi_io=mpi_io)
     988              :       END DO
     989              : 
     990           12 :       CALL auxbas_pw_pool%give_back_pw(wf_r)
     991           12 :       CALL auxbas_pw_pool%give_back_pw(wf_g)
     992           12 :       CALL timestop(handle)
     993           12 :    END SUBROUTINE qs_print_cubes
     994              : 
     995              : ! **************************************************************************************************
     996              : !> \brief Prints the electronic density
     997              : !> \param qs_env ...
     998              : !> \param nstates ...
     999              : !> \param state_list ...
    1000              : !> \param centers ...
    1001              : !> \param print_key ...
    1002              : !> \param root ...
    1003              : !> \param mo_coeff ...
    1004              : !> \param complex_mo_coeff ...
    1005              : !> \param ispin ...
    1006              : !> \param file_position ...
    1007              : ! **************************************************************************************************
    1008              : 
    1009            0 :    SUBROUTINE qs_print_density_cubes(qs_env, nstates, state_list, centers, print_key, root, &
    1010              :                                      mo_coeff, complex_mo_coeff, ispin, file_position)
    1011              : 
    1012              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1013              :       INTEGER, INTENT(IN)                                :: nstates
    1014              :       INTEGER, DIMENSION(:), POINTER                     :: state_list
    1015              :       REAL(dp), DIMENSION(:, :), POINTER                 :: centers
    1016              :       TYPE(section_vals_type), POINTER                   :: print_key
    1017              :       CHARACTER(LEN=*)                                   :: root
    1018              :       TYPE(cp_fm_type), OPTIONAL, POINTER                :: mo_coeff
    1019              :       TYPE(cp_cfm_type), OPTIONAL, POINTER               :: complex_mo_coeff
    1020              :       INTEGER, INTENT(IN), OPTIONAL                      :: ispin
    1021              :       CHARACTER(LEN=default_string_length), OPTIONAL     :: file_position
    1022              : 
    1023              :       TYPE(cp_fm_type), POINTER                          :: squaredmat
    1024              : 
    1025            0 :       IF (PRESENT(mo_coeff)) THEN
    1026            0 :          CPASSERT(.NOT. PRESENT(complex_mo_coeff))
    1027            0 :          CALL cp_fm_create(squaredmat, mo_coeff%matrix_struct)
    1028            0 :          squaredmat%local_data = mo_coeff%local_data**2.0
    1029              :       ELSE
    1030            0 :          CPASSERT(PRESENT(complex_mo_coeff))
    1031            0 :          CALL cp_fm_create(squaredmat, complex_mo_coeff%matrix_struct)
    1032              :          squaredmat%local_data = REAL(CONJG(complex_mo_coeff%local_data) &
    1033            0 :                                       *complex_mo_coeff%local_data, dp)
    1034              :       END IF
    1035              :       CALL qs_print_cubes(qs_env, squaredmat, nstates, state_list, centers, print_key, root, &
    1036            0 :                           ispin=ispin, file_position=file_position)
    1037            0 :       CALL cp_fm_release(squaredmat)
    1038              : 
    1039            0 :    END SUBROUTINE qs_print_density_cubes
    1040              : 
    1041              : ! **************************************************************************************************
    1042              : !> \brief Prints wannier centers
    1043              : !> \param qs_loc_env ...
    1044              : !> \param print_key ...
    1045              : !> \param center ...
    1046              : !> \param logger ...
    1047              : !> \param ispin ...
    1048              : ! **************************************************************************************************
    1049          506 :    SUBROUTINE print_wannier_centers(qs_loc_env, print_key, center, logger, ispin)
    1050              :       TYPE(qs_loc_env_type), POINTER                     :: qs_loc_env
    1051              :       TYPE(section_vals_type), POINTER                   :: print_key
    1052              :       REAL(KIND=dp), INTENT(IN)                          :: center(:, :)
    1053              :       TYPE(cp_logger_type), POINTER                      :: logger
    1054              :       INTEGER, INTENT(IN)                                :: ispin
    1055              : 
    1056              :       CHARACTER(default_string_length)                   :: iter, unit_str
    1057              :       CHARACTER(LEN=default_string_length)               :: my_ext, my_form
    1058              :       INTEGER                                            :: iunit, l, nstates
    1059              :       LOGICAL                                            :: first_time, init_traj
    1060              :       REAL(KIND=dp)                                      :: unit_conv
    1061              : 
    1062          506 :       nstates = SIZE(center, 2)
    1063          506 :       my_form = "formatted"
    1064          506 :       my_ext = ".data"
    1065          506 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key, first_time=first_time) &
    1066              :                 , cp_p_file)) THEN
    1067              :          ! Find out if we want to print IONS+CENTERS or ONLY CENTERS..
    1068          140 :          IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key, "/IONS+CENTERS") &
    1069              :                    , cp_p_file)) THEN
    1070           38 :             CALL get_output_format(print_key, my_form=my_form, my_ext=my_ext)
    1071              :          END IF
    1072          140 :          IF (first_time .OR. (.NOT. qs_loc_env%first_time)) THEN
    1073              :             iunit = cp_print_key_unit_nr(logger, print_key, "", extension=my_ext, file_form=my_form, &
    1074              :                                          middle_name=TRIM(qs_loc_env%tag_mo)//"_centers_s"//TRIM(ADJUSTL(cp_to_string(ispin))), &
    1075          140 :                                          log_filename=.FALSE., on_file=.TRUE., is_new_file=init_traj)
    1076          140 :             IF (iunit > 0) THEN
    1077              :                ! Gather units of measure for output (if available)
    1078           70 :                CALL section_vals_val_get(print_key, "UNIT", c_val=unit_str)
    1079           70 :                unit_conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
    1080              : 
    1081           70 :                IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key, "/IONS+CENTERS"), cp_p_file)) THEN
    1082              :                   ! Different possible formats
    1083           19 :                   CALL print_wannier_traj(qs_loc_env, print_key, center, iunit, init_traj, unit_conv)
    1084              :                ELSE
    1085              :                   ! Default print format
    1086           51 :                   iter = cp_iter_string(logger%iter_info)
    1087           51 :                   WRITE (iunit, '(i6,/,a)') nstates, TRIM(iter)
    1088          423 :                   DO l = 1, nstates
    1089         1911 :                      WRITE (iunit, '(A,4F16.8)') "X", unit_conv*center(1:4, l)
    1090              :                   END DO
    1091              :                END IF
    1092              :             END IF
    1093          140 :             CALL cp_print_key_finished_output(iunit, logger, print_key, on_file=.TRUE.)
    1094              :          END IF
    1095              :       END IF
    1096          506 :    END SUBROUTINE print_wannier_centers
    1097              : 
    1098              : ! **************************************************************************************************
    1099              : !> \brief computes spread and centers
    1100              : !> \param qs_loc_env ...
    1101              : !> \param print_key ...
    1102              : !> \param center ...
    1103              : !> \param iunit ...
    1104              : !> \param init_traj ...
    1105              : !> \param unit_conv ...
    1106              : ! **************************************************************************************************
    1107           19 :    SUBROUTINE print_wannier_traj(qs_loc_env, print_key, center, iunit, init_traj, unit_conv)
    1108              :       TYPE(qs_loc_env_type), POINTER                     :: qs_loc_env
    1109              :       TYPE(section_vals_type), POINTER                   :: print_key
    1110              :       REAL(KIND=dp), INTENT(IN)                          :: center(:, :)
    1111              :       INTEGER, INTENT(IN)                                :: iunit
    1112              :       LOGICAL, INTENT(IN)                                :: init_traj
    1113              :       REAL(KIND=dp), INTENT(IN)                          :: unit_conv
    1114              : 
    1115              :       CHARACTER(len=default_string_length)               :: iter, remark1, remark2, title
    1116              :       INTEGER                                            :: i, iskip, natom, ntot, outformat
    1117           19 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    1118              :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
    1119              :       TYPE(cp_logger_type), POINTER                      :: logger
    1120           19 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1121              : 
    1122           19 :       NULLIFY (particle_set, atomic_kind_set, atomic_kind, logger)
    1123           38 :       logger => cp_get_default_logger()
    1124           19 :       natom = SIZE(qs_loc_env%particle_set)
    1125           19 :       ntot = natom + SIZE(center, 2)
    1126           19 :       CALL allocate_particle_set(particle_set, ntot)
    1127           38 :       ALLOCATE (atomic_kind_set(1))
    1128           19 :       atomic_kind => atomic_kind_set(1)
    1129              :       CALL set_atomic_kind(atomic_kind=atomic_kind, kind_number=0, &
    1130           19 :                            name="X", element_symbol="X", mass=0.0_dp)
    1131              :       ! Particles
    1132          283 :       DO i = 1, natom
    1133          264 :          particle_set(i)%atomic_kind => qs_loc_env%particle_set(i)%atomic_kind
    1134         1075 :          particle_set(i)%r = pbc(qs_loc_env%particle_set(i)%r, qs_loc_env%cell)
    1135              :       END DO
    1136              :       ! Wannier Centers
    1137          452 :       DO i = natom + 1, ntot
    1138          433 :          particle_set(i)%atomic_kind => atomic_kind
    1139         1751 :          particle_set(i)%r = pbc(center(1:3, i - natom), qs_loc_env%cell)
    1140              :       END DO
    1141              :       ! Dump the structure
    1142           19 :       CALL section_vals_val_get(print_key, "FORMAT", i_val=outformat)
    1143              : 
    1144              :       ! Header file
    1145            0 :       SELECT CASE (outformat)
    1146              :       CASE (dump_dcd, dump_dcd_aligned_cell)
    1147            0 :          IF (init_traj) THEN
    1148              :             !Lets write the header for the coordinate dcd
    1149              :             ! Note (TL) : even the new DCD format is unfortunately too poor
    1150              :             !             for our capabilities.. for example here the printing
    1151              :             !             of the geometry could be nested inside several iteration
    1152              :             !             levels.. this cannot be exactly reproduced with DCD.
    1153              :             !             Just as a compromise let's pick-up the value of the MD iteration
    1154              :             !             level. In any case this is not any sensible information for the standard.
    1155            0 :             iskip = section_get_ival(print_key, "EACH%MD")
    1156            0 :             WRITE (iunit) "CORD", 0, -1, iskip, &
    1157            0 :                0, 0, 0, 0, 0, 0, REAL(0, KIND=sp), 1, 0, 0, 0, 0, 0, 0, 0, 0, 24
    1158            0 :             remark1 = "REMARK FILETYPE CORD DCD GENERATED BY CP2K"
    1159            0 :             remark2 = "REMARK Support new DCD format with cell information"
    1160            0 :             WRITE (iunit) 2, remark1, remark2
    1161            0 :             WRITE (iunit) ntot
    1162            0 :             CALL m_flush(iunit)
    1163              :          END IF
    1164              :       CASE (dump_xmol)
    1165           19 :          iter = cp_iter_string(logger%iter_info)
    1166           19 :          WRITE (UNIT=title, FMT="(A)") " Particles+Wannier centers. Iteration:"//TRIM(iter)
    1167              :       CASE DEFAULT
    1168           19 :          title = ""
    1169              :       END SELECT
    1170              :       CALL write_particle_coordinates(particle_set, iunit, outformat, "POS", title, qs_loc_env%cell, &
    1171           19 :                                       unit_conv=unit_conv)
    1172           19 :       CALL m_flush(iunit)
    1173           19 :       CALL deallocate_particle_set(particle_set)
    1174           19 :       CALL deallocate_atomic_kind_set(atomic_kind_set)
    1175           38 :    END SUBROUTINE print_wannier_traj
    1176              : 
    1177              : ! **************************************************************************************************
    1178              : !> \brief Compute the second moments of the centers using the local (non-periodic) pos operators
    1179              : !> \param qs_env ...
    1180              : !> \param qs_loc_env ...
    1181              : !> \param print_loc_section ...
    1182              : !> \param ispin ...
    1183              : !> \par History
    1184              : !>      07.2020 created [H. Elgabarty]
    1185              : !> \author Hossam Elgabarty
    1186              : ! **************************************************************************************************
    1187            0 :    SUBROUTINE centers_second_moments_loc(qs_env, qs_loc_env, print_loc_section, ispin)
    1188              : 
    1189              :       ! I might not actually need the qs_env
    1190              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1191              :       TYPE(qs_loc_env_type), POINTER                     :: qs_loc_env
    1192              :       TYPE(section_vals_type), POINTER                   :: print_loc_section
    1193              :       INTEGER, INTENT(IN)                                :: ispin
    1194              : 
    1195              :       INTEGER, PARAMETER                                 :: norder = 2
    1196              :       LOGICAL, PARAMETER :: debug_this_subroutine = .FALSE.
    1197              : 
    1198              :       CHARACTER(len=default_path_length)                 :: file_tmp
    1199              :       INTEGER                                            :: imoment, istate, ncol_global, nm, &
    1200              :                                                             nmoloc, nrow_global, output_unit, &
    1201              :                                                             output_unit_sm
    1202            0 :       REAL(dp), DIMENSION(:, :), POINTER                 :: centers
    1203            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: moment_set
    1204              :       REAL(KIND=dp), DIMENSION(3)                        :: rcc
    1205              :       REAL(KIND=dp), DIMENSION(6)                        :: cov
    1206              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
    1207              :       TYPE(cp_fm_type)                                   :: momv, mvector, omvector
    1208            0 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: moloc_coeff
    1209              :       TYPE(cp_fm_type), POINTER                          :: mo_localized
    1210              :       TYPE(cp_logger_type), POINTER                      :: logger
    1211            0 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s, moments
    1212              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1213              : 
    1214            0 :       logger => cp_get_default_logger()
    1215              : 
    1216              :       output_unit = cp_print_key_unit_nr(logger, print_loc_section, "PROGRAM_RUN_INFO", &
    1217            0 :                                          extension=".locInfo")
    1218              : 
    1219            0 :       IF (output_unit > 0) THEN
    1220              :          WRITE (output_unit, '(/,T2,A)') &
    1221            0 :             '!-----------------------------------------------------------------------------!'
    1222            0 :          WRITE (output_unit, '(T12,A)') "Computing second moments of Wannier functions..."
    1223              :          WRITE (output_unit, '(T2,A)') &
    1224            0 :             '!-----------------------------------------------------------------------------!'
    1225              :       END IF
    1226              : 
    1227            0 :       file_tmp = "_r_loc_cov_matrix_"//TRIM(ADJUSTL(cp_to_string(ispin)))
    1228              :       output_unit_sm = cp_print_key_unit_nr(logger, print_loc_section, "WANNIER_SPREADS", &
    1229            0 :                                             middle_name=file_tmp, extension=".data")
    1230              : 
    1231            0 :       CALL get_qs_loc_env(qs_loc_env=qs_loc_env, moloc_coeff=moloc_coeff)
    1232            0 :       centers => qs_loc_env%localized_wfn_control%centers_set(ispin)%array
    1233              : 
    1234            0 :       CALL get_qs_env(qs_env, matrix_s=matrix_s)
    1235              : 
    1236            0 :       nm = ncoset(norder) - 1
    1237              : 
    1238              :       !CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set, cell=cell)
    1239              :       !particle_set => qs_loc_env%particle_set
    1240            0 :       para_env => qs_loc_env%para_env
    1241              : 
    1242            0 :       CALL cp_fm_get_info(moloc_coeff(ispin), ncol_global=nmoloc)
    1243            0 :       ALLOCATE (moment_set(nm, nmoloc))
    1244            0 :       moment_set = 0.0_dp
    1245              : 
    1246            0 :       mo_localized => moloc_coeff(ispin)
    1247              : 
    1248            0 :       DO istate = 1, nmoloc
    1249            0 :          rcc = centers(1:3, istate)
    1250              :          !rcc = 0.0_dp
    1251              : 
    1252            0 :          ALLOCATE (moments(nm))
    1253            0 :          DO imoment = 1, nm
    1254            0 :             ALLOCATE (moments(imoment)%matrix)
    1255            0 :             CALL dbcsr_copy(moments(imoment)%matrix, matrix_s(ispin)%matrix, 'MOM MAT')
    1256            0 :             CALL dbcsr_set(moments(imoment)%matrix, 0.0_dp)
    1257              :          END DO
    1258              :          !
    1259              : 
    1260            0 :          CALL build_local_moment_matrix(qs_env, moments, norder, rcc)
    1261              : 
    1262            0 :          CALL cp_fm_get_info(mo_localized, ncol_global=ncol_global, nrow_global=nrow_global)
    1263              :          CALL cp_fm_struct_create(fm_struct, nrow_global=nrow_global, ncol_global=1, &
    1264              :                                   para_env=mo_localized%matrix_struct%para_env, &
    1265            0 :                                   context=mo_localized%matrix_struct%context)
    1266            0 :          CALL cp_fm_create(mvector, fm_struct, name="mvector")
    1267            0 :          CALL cp_fm_create(omvector, fm_struct, name="omvector")
    1268            0 :          CALL cp_fm_create(momv, fm_struct, name="omvector")
    1269            0 :          CALL cp_fm_struct_release(fm_struct)
    1270              : 
    1271              :          !cp_fm_to_fm_columns(msource, mtarget, ncol, source_start,target_start)
    1272            0 :          CALL cp_fm_to_fm(mo_localized, mvector, 1, istate, 1)
    1273              : 
    1274            0 :          DO imoment = 1, nm
    1275            0 :             CALL cp_dbcsr_sm_fm_multiply(moments(imoment)%matrix, mvector, omvector, 1)
    1276            0 :             CALL cp_fm_schur_product(mvector, omvector, momv)
    1277              :             !moment_set(imoment, istate) = moment_set(imoment, istate) + SUM(momv%local_data)
    1278            0 :             moment_set(imoment, istate) = SUM(momv%local_data)
    1279              :          END DO
    1280              :          !
    1281            0 :          CALL cp_fm_release(mvector)
    1282            0 :          CALL cp_fm_release(omvector)
    1283            0 :          CALL cp_fm_release(momv)
    1284              : 
    1285            0 :          DO imoment = 1, nm
    1286            0 :             CALL dbcsr_deallocate_matrix(moments(imoment)%matrix)
    1287              :          END DO
    1288            0 :          DEALLOCATE (moments)
    1289              :       END DO
    1290              : 
    1291            0 :       CALL para_env%sum(moment_set)
    1292              : 
    1293            0 :       IF (output_unit_sm > 0) THEN
    1294            0 :          WRITE (UNIT=output_unit_sm, FMT='(A,T13,A,I1)') "#", &
    1295            0 :             "SECOND MOMENTS OF WANNIER CENTERS FOR SPIN ", ispin
    1296            0 :          WRITE (UNIT=output_unit_sm, FMT='(A,T29,A2,5(14x,A2))') "#", "XX", "XY", "XZ", "YY", "YZ", "ZZ"
    1297            0 :          DO istate = 1, nmoloc
    1298              :             cov = 0.0_dp
    1299            0 :             cov(1) = moment_set(4, istate) - moment_set(1, istate)*moment_set(1, istate)
    1300            0 :             cov(2) = moment_set(5, istate) - moment_set(1, istate)*moment_set(2, istate)
    1301            0 :             cov(3) = moment_set(6, istate) - moment_set(1, istate)*moment_set(3, istate)
    1302            0 :             cov(4) = moment_set(7, istate) - moment_set(2, istate)*moment_set(2, istate)
    1303            0 :             cov(5) = moment_set(8, istate) - moment_set(2, istate)*moment_set(3, istate)
    1304            0 :             cov(6) = moment_set(9, istate) - moment_set(3, istate)*moment_set(3, istate)
    1305            0 :             WRITE (UNIT=output_unit_sm, FMT='(T4,A,I6,6(T20,6F16.8))') "Center:", istate, cov(1:6)
    1306            0 :             IF (debug_this_subroutine) THEN
    1307              :                WRITE (UNIT=output_unit_sm, FMT='(T4,A,I5,9(T20,9F12.6))') "Center:", istate, moment_set(1:, istate)
    1308              :             END IF
    1309              :          END DO
    1310              :       END IF
    1311            0 :       CALL cp_print_key_finished_output(output_unit_sm, logger, print_loc_section, "WANNIER_SPREADS")
    1312            0 :       CALL cp_print_key_finished_output(output_unit, logger, print_loc_section, "PROGRAM_RUN_INFO")
    1313              : 
    1314            0 :       DEALLOCATE (moment_set)
    1315              : 
    1316            0 :    END SUBROUTINE centers_second_moments_loc
    1317              : 
    1318              : ! **************************************************************************************************
    1319              : !> \brief Compute the second moments of the centers using a periodic quadrupole operator
    1320              : !> \brief c.f. Wheeler et al. PRB 100 245135 2019, and Kang et al. PRB 100 245134 2019
    1321              : !> \brief The calculation is based on a Taylor expansion of the exp(i k_i r_i r_j k_j) operator to
    1322              : !> \brief to first order in the cosine and the sine parts
    1323              : !> \param qs_env ...
    1324              : !> \param qs_loc_env ...
    1325              : !> \param print_loc_section ...
    1326              : !> \param ispin ...
    1327              : !> \par History
    1328              : !>      08.2020 created [H. Elgabarty]
    1329              : !> \author Hossam Elgabarty
    1330              : ! **************************************************************************************************
    1331            0 :    SUBROUTINE centers_second_moments_berry(qs_env, qs_loc_env, print_loc_section, ispin)
    1332              : 
    1333              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1334              :       TYPE(qs_loc_env_type), POINTER                     :: qs_loc_env
    1335              :       TYPE(section_vals_type), POINTER                   :: print_loc_section
    1336              :       INTEGER, INTENT(IN)                                :: ispin
    1337              : 
    1338              :       INTEGER, PARAMETER                                 :: taylor_order = 1
    1339              :       LOGICAL, PARAMETER :: debug_this_subroutine = .FALSE.
    1340              : 
    1341              :       CHARACTER(len=default_path_length)                 :: file_tmp
    1342              :       COMPLEX(KIND=dp)                                   :: z
    1343              :       INTEGER                                            :: icov, imoment, istate, ncol_global, nm, &
    1344              :                                                             nmoloc, norder, nrow_global, &
    1345              :                                                             output_unit, output_unit_sm
    1346            0 :       REAL(dp), DIMENSION(:, :), POINTER                 :: centers
    1347              :       REAL(KIND=dp)                                      :: imagpart, Lx, Ly, Lz, realpart
    1348            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: moment_set
    1349              :       REAL(KIND=dp), DIMENSION(3)                        :: rcc
    1350              :       REAL(KIND=dp), DIMENSION(6)                        :: cov
    1351              :       TYPE(cell_type), POINTER                           :: cell
    1352              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
    1353              :       TYPE(cp_fm_type)                                   :: momv, mvector, omvector
    1354            0 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: moloc_coeff
    1355              :       TYPE(cp_fm_type), POINTER                          :: mo_localized
    1356              :       TYPE(cp_logger_type), POINTER                      :: logger
    1357            0 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s, moments
    1358              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1359              : 
    1360              : ! two pointers, one to each spin channel's coeff. matrix (nao x nmoloc)
    1361              : 
    1362            0 :       logger => cp_get_default_logger()
    1363              : 
    1364              :       output_unit = cp_print_key_unit_nr(logger, print_loc_section, "PROGRAM_RUN_INFO", &
    1365            0 :                                          extension=".locInfo")
    1366              : 
    1367            0 :       IF (output_unit > 0) THEN
    1368              :          WRITE (output_unit, '(/,T2,A)') &
    1369            0 :             '!-----------------------------------------------------------------------------!'
    1370            0 :          WRITE (output_unit, '(T12,A)') "Computing second moments of Wannier functions..."
    1371              :          WRITE (output_unit, '(T2,A)') &
    1372            0 :             '!-----------------------------------------------------------------------------!'
    1373              :       END IF
    1374              : 
    1375            0 :       file_tmp = "_r_berry_cov_matrix_"//TRIM(ADJUSTL(cp_to_string(ispin)))
    1376              :       output_unit_sm = cp_print_key_unit_nr(logger, print_loc_section, "WANNIER_SPREADS", &
    1377            0 :                                             middle_name=file_tmp, extension=".data")
    1378              : 
    1379            0 :       norder = 2*(2*taylor_order + 1)
    1380            0 :       nm = (6 + 11*norder + 6*norder**2 + norder**3)/6 - 1
    1381              : 
    1382            0 :       NULLIFY (cell)
    1383            0 :       CALL get_qs_loc_env(qs_loc_env=qs_loc_env, moloc_coeff=moloc_coeff, cell=cell)
    1384            0 :       Lx = cell%hmat(1, 1)
    1385            0 :       Ly = cell%hmat(2, 2)
    1386            0 :       Lz = cell%hmat(3, 3)
    1387              : 
    1388            0 :       centers => qs_loc_env%localized_wfn_control%centers_set(ispin)%array
    1389              : 
    1390            0 :       para_env => qs_loc_env%para_env
    1391              : 
    1392            0 :       CALL get_qs_env(qs_env, matrix_s=matrix_s)
    1393              : 
    1394            0 :       CALL cp_fm_get_info(moloc_coeff(ispin), ncol_global=nmoloc)
    1395              : 
    1396            0 :       ALLOCATE (moment_set(nm, nmoloc))
    1397            0 :       moment_set = 0.0_dp
    1398              : 
    1399            0 :       mo_localized => moloc_coeff(ispin)
    1400              : 
    1401            0 :       DO istate = 1, nmoloc
    1402            0 :          rcc = centers(1:3, istate)
    1403              :          !rcc = 0.0_dp
    1404              : 
    1405            0 :          ALLOCATE (moments(nm))
    1406            0 :          DO imoment = 1, nm
    1407            0 :             ALLOCATE (moments(imoment)%matrix)
    1408            0 :             CALL dbcsr_copy(moments(imoment)%matrix, matrix_s(ispin)%matrix, 'MOM MAT')
    1409            0 :             CALL dbcsr_set(moments(imoment)%matrix, 0.0_dp)
    1410              :          END DO
    1411              :          !
    1412              : 
    1413            0 :          CALL build_local_moment_matrix(qs_env, moments, norder, rcc)
    1414              : 
    1415            0 :          CALL cp_fm_get_info(mo_localized, ncol_global=ncol_global, nrow_global=nrow_global)
    1416              :          CALL cp_fm_struct_create(fm_struct, nrow_global=nrow_global, ncol_global=1, &
    1417              :                                   para_env=mo_localized%matrix_struct%para_env, &
    1418            0 :                                   context=mo_localized%matrix_struct%context)
    1419            0 :          CALL cp_fm_create(mvector, fm_struct, name="mvector")
    1420            0 :          CALL cp_fm_create(omvector, fm_struct, name="omvector")
    1421            0 :          CALL cp_fm_create(momv, fm_struct, name="omvector")
    1422            0 :          CALL cp_fm_struct_release(fm_struct)
    1423              : 
    1424              :          ! cp_fm_to_fm_columns(msource, mtarget, ncol, source_start,target_start)
    1425            0 :          CALL cp_fm_to_fm(mo_localized, mvector, 1, istate, 1)
    1426              : 
    1427            0 :          DO imoment = 1, nm
    1428            0 :             CALL cp_dbcsr_sm_fm_multiply(moments(imoment)%matrix, mvector, omvector, 1)
    1429            0 :             CALL cp_fm_schur_product(mvector, omvector, momv)
    1430            0 :             moment_set(imoment, istate) = SUM(momv%local_data)
    1431              :          END DO
    1432              :          !
    1433            0 :          CALL cp_fm_release(mvector)
    1434            0 :          CALL cp_fm_release(omvector)
    1435            0 :          CALL cp_fm_release(momv)
    1436              : 
    1437            0 :          DO imoment = 1, nm
    1438            0 :             CALL dbcsr_deallocate_matrix(moments(imoment)%matrix)
    1439              :          END DO
    1440            0 :          DEALLOCATE (moments)
    1441              :       END DO
    1442              : 
    1443            0 :       CALL para_env%sum(moment_set)
    1444              : 
    1445            0 :       IF (output_unit_sm > 0) THEN
    1446            0 :          WRITE (UNIT=output_unit_sm, FMT='(A,T13,A,I1)') "#", &
    1447            0 :             "SECOND MOMENTS OF WANNIER CENTERS FOR SPIN ", ispin
    1448            0 :          WRITE (UNIT=output_unit_sm, FMT='(A,T29,A2,5(14x,A2))') "#", "XX", "XY", "XZ", "YY", "YZ", "ZZ"
    1449            0 :          DO istate = 1, nmoloc
    1450            0 :             cov = 0.0_dp
    1451            0 :             DO icov = 1, 6
    1452            0 :                realpart = 0.0_dp
    1453            0 :                imagpart = 0.0_dp
    1454            0 :                z = CMPLX(realpart, imagpart, dp)
    1455            0 :                SELECT CASE (icov)
    1456              : 
    1457              :                  !! XX
    1458              :                CASE (1)
    1459              :                   realpart = 1.0 - 0.5*twopi*twopi/Lx/Lx/Lx/Lx &
    1460            0 :                      *moment_set(20, istate)
    1461              :                   imagpart = twopi/Lx/Lx*moment_set(4, istate) &
    1462            0 :                              - twopi*twopi*twopi/Lx/Lx/Lx/Lx/Lx/Lx/6.0*moment_set(56, istate)
    1463              : 
    1464              :                   ! third order
    1465              :                   !realpart = realpart + twopi*twopi*twopi*twopi/Lx/Lx/Lx/Lx/Lx/Lx/Lx/Lx/24.0 * moment_set(120, istate)
    1466              :                   !imagpart = imagpart + twopi*twopi*twopi*twopi*twopi/Lx/Lx/Lx/Lx/Lx/Lx/Lx/Lx/Lx/Lx/120 &
    1467              :                   !     * moment_set(220, istate)
    1468              : 
    1469            0 :                   z = CMPLX(realpart, imagpart, dp)
    1470            0 :                   cov(1) = Lx*Lx/twopi*AIMAG(LOG(z)) - Lx*Lx/twopi/twopi*moment_set(1, istate)*moment_set(1, istate)
    1471              : 
    1472              :                  !! XY
    1473              :                CASE (2)
    1474              :                   realpart = 1.0 - 0.5*twopi*twopi/Lx/Ly/Lx/Ly &
    1475            0 :                      *moment_set(23, istate)
    1476              :                   imagpart = twopi/Lx/Ly*moment_set(5, istate) &
    1477            0 :                              - twopi*twopi*twopi/Lx/Lx/Lx/Ly/Ly/Ly/6.0*moment_set(62, istate)
    1478              : 
    1479              :                   ! third order
    1480              :                   !realpart = realpart + twopi*twopi*twopi*twopi/Lx/Lx/Lx/Lx/Ly/Ly/Ly/Ly/24.0 * moment_set(130, istate)
    1481              :                   !imagpart = imagpart + twopi*twopi*twopi*twopi*twopi/Lx/Lx/Lx/Lx/Lx/Ly/Ly/Ly/Ly/Ly/120 &
    1482              :                   !     * moment_set(235, istate)
    1483              : 
    1484            0 :                   z = CMPLX(realpart, imagpart, dp)
    1485            0 :                   cov(2) = Lx*Ly/twopi*AIMAG(LOG(z)) - Lx*Ly/twopi/twopi*moment_set(1, istate)*moment_set(2, istate)
    1486              : 
    1487              :                  !! XZ
    1488              :                CASE (3)
    1489              :                   realpart = 1.0 - 0.5*twopi*twopi/Lx/Lz/Lx/Lz &
    1490            0 :                      *moment_set(25, istate)
    1491              :                   imagpart = twopi/Lx/Lz*moment_set(6, istate) &
    1492            0 :                              - twopi*twopi*twopi/Lx/Lx/Lx/Lz/Lz/Lz/6.0*moment_set(65, istate)
    1493              : 
    1494              :                   ! third order
    1495              :                   !realpart = realpart + twopi*twopi*twopi*twopi/Lx/Lx/Lx/Lx/Lz/Lz/Lz/Lz/24.0 * moment_set(134, istate)
    1496              :                   !imagpart = imagpart + twopi*twopi*twopi*twopi*twopi/Lx/Lx/Lx/Lx/Lx/Ly/Ly/Ly/Ly/Ly/120 &
    1497              :                   !     * moment_set(240, istate)
    1498              : 
    1499            0 :                   z = CMPLX(realpart, imagpart, dp)
    1500            0 :                   cov(3) = Lx*Lz/twopi*AIMAG(LOG(z)) - Lx*Lz/twopi/twopi*moment_set(1, istate)*moment_set(3, istate)
    1501              : 
    1502              :                  !! YY
    1503              :                CASE (4)
    1504              :                   realpart = 1.0 - 0.5*twopi*twopi/Ly/Ly/Ly/Ly &
    1505            0 :                      *moment_set(30, istate)
    1506              :                   imagpart = twopi/Ly/Ly*moment_set(7, istate) &
    1507            0 :                              - twopi*twopi*twopi/Ly/Ly/Ly/Ly/Ly/Ly/6.0*moment_set(77, istate)
    1508              : 
    1509              :                   ! third order
    1510              :                   !realpart = realpart + twopi*twopi*twopi*twopi/Ly/Ly/Ly/Ly/Ly/Ly/Ly/Ly/24.0 * moment_set(156, istate)
    1511              :                   !imagpart = imagpart + twopi*twopi*twopi*twopi*twopi/Ly/Ly/Ly/Ly/Ly/Ly/Ly/Ly/Ly/Ly/120 &
    1512              :                   !     * moment_set(275, istate)
    1513              : 
    1514            0 :                   z = CMPLX(realpart, imagpart, dp)
    1515            0 :                   cov(4) = Ly*Ly/twopi*AIMAG(LOG(z)) - Ly*Ly/twopi/twopi*moment_set(2, istate)*moment_set(2, istate)
    1516              : 
    1517              :                  !! YZ
    1518              :                CASE (5)
    1519              :                   realpart = 1.0 - 0.5*twopi*twopi/Ly/Lz/Ly/Lz &
    1520            0 :                      *moment_set(32, istate)
    1521              :                   imagpart = twopi/Ly/Lz*moment_set(8, istate) &
    1522            0 :                              - twopi*twopi*twopi/Ly/Ly/Ly/Lz/Lz/Lz/6.0*moment_set(80, istate)
    1523              : 
    1524              :                   ! third order
    1525              :                   !realpart = realpart + twopi*twopi*twopi*twopi/Lz/Lz/Lz/Lz/Ly/Ly/Ly/Ly/24.0 * moment_set(160, istate)
    1526              :                   !imagpart = imagpart + twopi*twopi*twopi*twopi*twopi/Lz/Lz/Lz/Lz/Lz/Ly/Ly/Ly/Ly/Ly/120 &
    1527              :                   !     * moment_set(280, istate)
    1528              : 
    1529            0 :                   z = CMPLX(realpart, imagpart, dp)
    1530            0 :                   cov(5) = Ly*Lz/twopi*AIMAG(LOG(z)) - Ly*Lz/twopi/twopi*moment_set(2, istate)*moment_set(3, istate)
    1531              : 
    1532              :                  !! ZZ
    1533              :                CASE (6)
    1534              :                   realpart = 1.0 - 0.5*twopi*twopi/Lz/Lz/Lz/Lz &
    1535            0 :                      *moment_set(34, istate)
    1536              :                   imagpart = twopi/Lz/Lz*moment_set(9, istate) &
    1537            0 :                              - twopi*twopi*twopi/Lz/Lz/Lz/Lz/Lz/Lz/6.0*moment_set(83, istate)
    1538              : 
    1539              :                   ! third order
    1540              :                   !realpart = realpart + twopi*twopi*twopi*twopi/Lz/Lz/Lz/Lz/Lz/Lz/Lz/Lz/24.0 * moment_set(164, istate)
    1541              :                   !imagpart = imagpart + twopi*twopi*twopi*twopi*twopi/Lz/Lz/Lz/Lz/Lz/Lz/Lz/Lz/Lz/Lz/120 &
    1542              :                   !     * moment_set(285, istate)
    1543              : 
    1544            0 :                   z = CMPLX(realpart, imagpart, dp)
    1545            0 :                   cov(6) = Lz*Lz/twopi*AIMAG(LOG(z)) - Lz*Lz/twopi/twopi*moment_set(3, istate)*moment_set(3, istate)
    1546              : 
    1547              :                END SELECT
    1548              :             END DO
    1549            0 :             WRITE (UNIT=output_unit_sm, FMT='(T4,A,I6,6(T20,6F16.8))') "Center:", istate, cov(1:6)
    1550            0 :             IF (debug_this_subroutine) THEN
    1551              :                WRITE (UNIT=output_unit_sm, FMT='(T4,A,I5,9(T20,9F12.6))') "Center:", istate, moment_set(1:, istate)
    1552              :             END IF
    1553              :          END DO
    1554              :       END IF
    1555            0 :       CALL cp_print_key_finished_output(output_unit_sm, logger, print_loc_section, "WANNIER_SPREADS")
    1556            0 :       CALL cp_print_key_finished_output(output_unit, logger, print_loc_section, "PROGRAM_RUN_INFO")
    1557              : 
    1558            0 :       DEALLOCATE (moment_set)
    1559              : 
    1560            0 :    END SUBROUTINE centers_second_moments_berry
    1561              : 
    1562              : END MODULE qs_loc_methods
        

Generated by: LCOV version 2.0-1