LCOV - code coverage report
Current view: top level - src - qs_spectral_localizer.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 82.9 % 287 238
Test Date: 2026-10-15 00:55:44 Functions: 100.0 % 2 2

            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 Post-SCF finite-system spectral localizers and analytic AO position export.
      10              : !> \author Thomas D. Kuehne, tkuehne@cp2k.org
      11              : ! **************************************************************************************************
      12              : MODULE qs_spectral_localizer
      13              :    USE bibliography,                    ONLY: Dixon2023,&
      14              :                                               Doll2025,&
      15              :                                               Loring2015,&
      16              :                                               Wong2026
      17              :    USE cell_types,                      ONLY: cell_type,&
      18              :                                               use_perd_none,&
      19              :                                               use_perd_xy,&
      20              :                                               use_perd_xyz,&
      21              :                                               use_perd_xz,&
      22              :                                               use_perd_yz
      23              :    USE cp_control_types,                ONLY: dft_control_type
      24              :    USE cp_dbcsr_api,                    ONLY: dbcsr_create,&
      25              :                                               dbcsr_get_info,&
      26              :                                               dbcsr_p_type,&
      27              :                                               dbcsr_set
      28              :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_alloc_block_from_nbl
      29              :    USE cp_dbcsr_operations,             ONLY: dbcsr_deallocate_matrix_set
      30              :    USE cp_dbcsr_output,                 ONLY: cp_dbcsr_write_sparse_matrix
      31              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      32              :                                               cp_logger_get_default_io_unit,&
      33              :                                               cp_logger_type
      34              :    USE cp_output_handling,              ONLY: cp_p_file,&
      35              :                                               cp_print_key_finished_output,&
      36              :                                               cp_print_key_should_output,&
      37              :                                               cp_print_key_unit_nr
      38              :    USE ieee_arithmetic,                 ONLY: ieee_is_finite
      39              :    USE input_constants,                 ONLY: do_method_gapw,&
      40              :                                               do_method_gpw
      41              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      42              :                                               section_vals_type,&
      43              :                                               section_vals_val_get
      44              :    USE kinds,                           ONLY: dp
      45              :    USE mathconstants,                   ONLY: twopi
      46              :    USE message_passing,                 ONLY: mp_para_env_type
      47              :    USE qs_environment_types,            ONLY: get_qs_env,&
      48              :                                               qs_environment_type
      49              :    USE qs_finite_ao,                    ONLY: finite_ao_positions,&
      50              :                                               finite_ao_soc
      51              :    USE qs_localizer_torus,              ONLY: localizer_torus_operators
      52              :    USE qs_moments,                      ONLY: build_berry_moment_matrix
      53              :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type
      54              :    USE reference_manager,               ONLY: cite_reference
      55              :    USE spectral_localizer,              ONLY: localizer_3d_matrix_evaluate,&
      56              :                                               localizer_matrix_evaluate
      57              :    USE spectral_localizer_bloch,        ONLY: localizer_flatten_bloch
      58              :    USE spectral_localizer_dbcsr,        ONLY: localizer_ao_operators,&
      59              :                                               localizer_dbcsr_3d_build,&
      60              :                                               localizer_dbcsr_build,&
      61              :                                               localizer_dbcsr_dense,&
      62              :                                               localizer_dbcsr_release,&
      63              :                                               localizer_matrix_type
      64              :    USE spectral_localizer_flatten,      ONLY: localizer_flatten_checked
      65              : #include "./base/base_uses.f90"
      66              : 
      67              :    IMPLICIT NONE
      68              :    PRIVATE
      69              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_spectral_localizer'
      70              :    PUBLIC :: qs_scf_post_localizer
      71              : 
      72              : CONTAINS
      73              : 
      74              : ! **************************************************************************************************
      75              : !> \brief Export finite AO positions and optionally evaluate localizers after SCF.
      76              : !> \param qs_env Converged Quickstep environment
      77              : ! **************************************************************************************************
      78        14147 :    SUBROUTINE qs_scf_post_localizer(qs_env)
      79              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      80              : 
      81              :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_scf_post_localizer'
      82              :       CHARACTER(len=1), PARAMETER                        :: axes(3) = ['X', 'Y', 'Z']
      83              :       INTEGER, PARAMETER :: plane_periodicity(3) = [use_perd_xy, use_perd_xz, use_perd_yz]
      84              : 
      85        14147 :       COMPLEX(KIND=dp), ALLOCATABLE                      :: local_dense(:, :), metric_dense(:, :)
      86              :       INTEGER :: after, axis, directions(3), flatten_handle, formulation, handle, ie, ik, &
      87              :          invariant, ip, iw, max_ao, n, nao, ndim, nposition, output_unit, plane, poisson_periodic, &
      88              :          spin_channel, status, topology
      89        14147 :       INTEGER, POINTER                                   :: grid(:)
      90              :       LOGICAL :: active, aii, do_kpoints, do_soc, explicit_scale, flatten, omit_headers, &
      91              :          periodic_localizer, print_position, print_soc, time_reversal, torus
      92              :       REAL(dp) :: build_energy, electronic_gap(2), eps_electronic_gap, eps_flattening, &
      93              :          flatten_residuals(4), flatten_scale, local_point(3), physical_ratio
      94              :       REAL(KIND=dp)                                      :: eps_gap, eps_metric, gap, &
      95              :                                                             matrix_tolerance, metric_ratio
      96        28294 :       REAL(KIND=dp), POINTER                             :: energies(:), kappas(:), point(:)
      97              :       TYPE(cell_type), POINTER                           :: cell
      98              :       TYPE(cp_logger_type), POINTER                      :: logger
      99        14147 :       TYPE(dbcsr_p_type), POINTER                        :: cosines(:), image_matrices(:, :), &
     100        14147 :                                                             matrix_ks(:), matrix_s(:), &
     101        14147 :                                                             positions(:), soc_matrices(:, :)
     102              :       TYPE(dft_control_type), POINTER                    :: dft_control
     103        28294 :       TYPE(localizer_matrix_type)                        :: localizer, metric, physical_h(1), &
     104              :                                                             physical_metric
     105              :       TYPE(localizer_matrix_type), POINTER               :: flat_hamiltonian
     106              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     107        14147 :       TYPE(neighbor_list_set_p_type), POINTER            :: sab_orb(:)
     108              :       TYPE(section_vals_type), POINTER                   :: input, section
     109              : 
     110        14147 :       CALL timeset(routineN, handle)
     111        14147 :       NULLIFY (input, section, cell, dft_control, para_env, sab_orb, matrix_ks, matrix_s, &
     112        14147 :                positions, soc_matrices, energies, kappas, point, cosines, flat_hamiltonian)
     113        14147 :       CALL get_qs_env(qs_env, input=input)
     114        14147 :       section => section_vals_get_subs_vals(input, 'PROPERTIES%SPECTRAL_LOCALIZER')
     115        14147 :       CALL section_vals_val_get(section, '_SECTION_PARAMETERS_', l_val=active)
     116        14147 :       logger => cp_get_default_logger()
     117        14147 :       output_unit = cp_logger_get_default_io_unit(logger)
     118              :       print_position = BTEST(cp_print_key_should_output(logger%iter_info, input, &
     119        14147 :                                                         'DFT%PRINT%AO_MATRICES/POSITION'), cp_p_file)
     120              :       print_soc = BTEST(cp_print_key_should_output(logger%iter_info, input, &
     121        14147 :                                                    'DFT%PRINT%AO_MATRICES/SOC'), cp_p_file)
     122        14147 :       IF (.NOT. active .AND. .NOT. print_position .AND. .NOT. print_soc) THEN
     123        14119 :          CALL timestop(handle)
     124        14119 :          RETURN
     125              :       END IF
     126              :       CALL get_qs_env(qs_env, cell=cell, do_kpoints=do_kpoints, dft_control=dft_control, &
     127           28 :                       matrix_s_kp=image_matrices, para_env=para_env, sab_orb=sab_orb)
     128           28 :       matrix_s => image_matrices(:, 1)
     129           28 :       CALL section_vals_val_get(section, 'FORMULATION', i_val=formulation)
     130           28 :       periodic_localizer = active .AND. formulation == 1
     131           72 :       IF ((print_position .OR. print_soc) .AND. (ANY(cell%perd /= 0) .OR. do_kpoints)) THEN
     132            0 :          CPABORT('AO_MATRICES POSITION/SOC requires finite systems without KPOINTS.')
     133              :       END IF
     134           28 :       IF (do_kpoints .AND. .NOT. periodic_localizer) THEN
     135            0 :          CPABORT('Explicit KPOINTS require FORMULATION PERIODIC for localizers.')
     136              :       END IF
     137           72 :       IF (.NOT. periodic_localizer .AND. ANY(cell%perd /= 0)) THEN
     138            0 :          CPABORT('AO position/localizer requires PERIODIC NONE without KPOINTS.')
     139              :       END IF
     140           28 :       CALL section_vals_val_get(section, 'DIMENSION', i_val=ndim)
     141           28 :       IF (ndim /= 2 .AND. ndim /= 3) CPABORT('SPECTRAL_LOCALIZER DIMENSION must be 2 or 3.')
     142           28 :       CALL section_vals_val_get(section, 'PLANE', i_val=plane, explicit=explicit_scale)
     143           28 :       IF (active .AND. ndim == 3 .AND. explicit_scale) THEN
     144            0 :          CPABORT('PLANE is only valid for DIMENSION 2.')
     145              :       END IF
     146           28 :       CALL section_vals_val_get(section, 'MP_GRID', i_vals=grid, explicit=explicit_scale)
     147          112 :       IF (ANY(grid < 1)) CPABORT('SPECTRAL_LOCALIZER MP_GRID must be positive.')
     148           28 :       IF (.NOT. periodic_localizer .AND. explicit_scale) THEN
     149            0 :          CPABORT('SPECTRAL_LOCALIZER MP_GRID requires FORMULATION PERIODIC.')
     150              :       END IF
     151          112 :       IF (ANY(grid /= 1 .AND. cell%perd == 0)) THEN
     152            0 :          CPABORT('Localizer MP_GRID must be one in nonperiodic directions.')
     153              :       END IF
     154           76 :       torus = periodic_localizer .AND. (do_kpoints .OR. ANY(grid /= 1))
     155           28 :       directions = [1, 2, 3]
     156           28 :       IF (ndim == 2) THEN
     157              :          SELECT CASE (plane)
     158              :          CASE (1)
     159           42 :             directions(:2) = [1, 2]
     160              :          CASE (2)
     161           18 :             directions(:2) = [1, 3]
     162              :          CASE (3)
     163           26 :             directions(:2) = [2, 3]
     164              :          END SELECT
     165              :       END IF
     166           28 :       CALL section_vals_val_get(input, 'DFT%POISSON%PERIODIC', i_val=poisson_periodic)
     167           28 :       IF (periodic_localizer) THEN
     168           14 :          IF (ndim == 3) THEN
     169           16 :             IF (ANY(cell%perd == 0) .OR. poisson_periodic /= use_perd_xyz) THEN
     170            0 :                CPABORT('PERIODIC DIMENSION 3 requires CELL and POISSON PERIODIC XYZ.')
     171              :             END IF
     172              :          ELSE
     173           60 :             IF (COUNT(cell%perd /= 0) /= 2 .OR. ANY(cell%perd(directions(:2)) == 0)) THEN
     174            0 :                CPABORT('PERIODIC localizer requires two periodic CELL axes matching PLANE.')
     175              :             END IF
     176           10 :             IF (poisson_periodic /= plane_periodicity(plane)) THEN
     177            0 :                CPABORT('PERIODIC localizer requires matching CELL and POISSON periodicity.')
     178              :             END IF
     179              :          END IF
     180           14 :          CALL section_vals_val_get(section, 'KAPPA', explicit=explicit_scale)
     181           14 :          IF (explicit_scale) CPABORT('Use ETA, not KAPPA, for FORMULATION PERIODIC.')
     182           14 :       ELSE IF (active .AND. poisson_periodic /= use_perd_none) THEN
     183            0 :          CPABORT('SPECTRAL_LOCALIZER requires POISSON PERIODIC NONE.')
     184              :       END IF
     185           28 :       IF (active .AND. .NOT. periodic_localizer) THEN
     186           14 :          CALL section_vals_val_get(section, 'ETA', explicit=explicit_scale)
     187           14 :          IF (explicit_scale) CPABORT('Use KAPPA, not ETA, for FORMULATION FINITE.')
     188              :       END IF
     189           28 :       SELECT CASE (dft_control%qs_control%method_id)
     190              :       CASE (do_method_gpw, do_method_gapw)
     191              :       CASE DEFAULT
     192           28 :          CPABORT('AO position/localizer currently supports GPW and GAPW only.')
     193              :       END SELECT
     194           28 :       IF (active) THEN
     195           28 :          IF (.NOT. qs_env%scf_convergence_available .OR. .NOT. qs_env%scf_converged) THEN
     196            0 :             CPABORT('SPECTRAL_LOCALIZER requires a converged SCF calculation.')
     197              :          END IF
     198           28 :          CALL cite_reference(Dixon2023)
     199           28 :          IF (periodic_localizer) CALL cite_reference(Doll2025)
     200           28 :          CALL dbcsr_get_info(matrix_s(1)%matrix, nfullrows_total=nao)
     201           28 :          CALL section_vals_val_get(section, 'MAX_AO', i_val=max_ao)
     202           28 :          IF (max_ao < 1 .OR. nao > max_ao) THEN
     203            0 :             CPABORT('SPECTRAL_LOCALIZER exceeds the MAX_AO limit.')
     204              :          END IF
     205          112 :          DO axis = 1, 3
     206           84 :             IF (grid(axis) > max_ao/nao) THEN
     207            0 :                CPABORT('SPECTRAL_LOCALIZER torus exceeds the MAX_AO limit.')
     208              :             END IF
     209          112 :             nao = nao*grid(axis)
     210              :          END DO
     211              :       END IF
     212              : 
     213           28 :       IF (periodic_localizer .AND. .NOT. torus) THEN
     214            2 :          CALL periodic_ao_moments(qs_env, directions(:ndim), cosines, positions)
     215           26 :       ELSE IF (.NOT. periodic_localizer .AND. (active .OR. print_position)) THEN
     216           14 :          CALL finite_ao_positions(qs_env, positions)
     217              :       END IF
     218           28 :       IF (print_position) THEN
     219           10 :          CALL section_vals_val_get(input, 'DFT%PRINT%AO_MATRICES%NDIGITS', i_val=after)
     220           10 :          CALL section_vals_val_get(input, 'DFT%PRINT%AO_MATRICES%OMIT_HEADERS', l_val=omit_headers)
     221           10 :          after = MIN(MAX(after, 1), 16)
     222           40 :          DO axis = 1, 3
     223              :             iw = cp_print_key_unit_nr(logger, input, 'DFT%PRINT%AO_MATRICES/POSITION', &
     224           30 :                                       extension='.Log', middle_name=axes(axis))
     225           30 :             IF (iw > 0 .AND. .NOT. omit_headers) THEN
     226           15 :                WRITE (iw, '(A)') 'AO POSITION '//axes(axis)//' [bohr]; coordinate origin; covariant AO matrix'
     227              :             END IF
     228              :             CALL cp_dbcsr_write_sparse_matrix(positions(axis)%matrix, 4, after, qs_env, para_env, &
     229           30 :                                               output_unit=iw, omit_headers=omit_headers)
     230           40 :             CALL cp_print_key_finished_output(iw, logger, input, 'DFT%PRINT%AO_MATRICES/POSITION')
     231              :          END DO
     232              :       END IF
     233           28 :       IF (print_soc) THEN
     234            0 :          CALL finite_ao_soc(qs_env, soc_matrices)
     235            0 :          CALL section_vals_val_get(input, 'DFT%PRINT%AO_MATRICES%NDIGITS', i_val=after)
     236            0 :          CALL section_vals_val_get(input, 'DFT%PRINT%AO_MATRICES%OMIT_HEADERS', l_val=omit_headers)
     237            0 :          after = MIN(MAX(after, 1), 16)
     238            0 :          DO axis = 1, 3
     239              :             iw = cp_print_key_unit_nr(logger, input, 'DFT%PRINT%AO_MATRICES/SOC', &
     240            0 :                                       extension='.Log', middle_name='SOC_'//axes(axis))
     241            0 :             IF (iw > 0 .AND. .NOT. omit_headers) THEN
     242            0 :                WRITE (iw, '(A)') 'AO SOC '//axes(axis)//' [hartree]; real antisymmetric component; multiply by i'
     243              :             END IF
     244              :             CALL cp_dbcsr_write_sparse_matrix(soc_matrices(axis, 1)%matrix, 4, after, qs_env, para_env, &
     245            0 :                                               output_unit=iw, omit_headers=omit_headers)
     246            0 :             CALL cp_print_key_finished_output(iw, logger, input, 'DFT%PRINT%AO_MATRICES/SOC')
     247              :          END DO
     248              :       END IF
     249           28 :       IF (.NOT. active) THEN
     250            0 :          IF (ASSOCIATED(positions)) CALL dbcsr_deallocate_matrix_set(positions)
     251            0 :          IF (ASSOCIATED(soc_matrices)) CALL dbcsr_deallocate_matrix_set(soc_matrices)
     252            0 :          CALL timestop(handle)
     253            0 :          RETURN
     254              :       END IF
     255              : 
     256           28 :       CALL section_vals_val_get(section, 'INVARIANT', i_val=topology)
     257           28 :       aii = topology == 1
     258           28 :       IF (ndim == 3 .AND. .NOT. aii) CPABORT('DIMENSION 3 requires INVARIANT Z2.')
     259           28 :       IF (aii .AND. ndim == 2) CALL cite_reference(Wong2026)
     260           28 :       IF (ndim == 3) CALL cite_reference(Loring2015)
     261           28 :       CALL section_vals_val_get(section, 'SOC', l_val=do_soc)
     262           28 :       CALL section_vals_val_get(section, 'TIME_REVERSAL', l_val=time_reversal)
     263           28 :       CALL section_vals_val_get(section, 'SPIN_CHANNEL', i_val=spin_channel)
     264           28 :       IF (aii .AND. (.NOT. do_soc .OR. .NOT. time_reversal)) THEN
     265            0 :          CPABORT('SPECTRAL_LOCALIZER INVARIANT Z2 requires SOC T and TIME_REVERSAL T.')
     266              :       END IF
     267           28 :       CALL get_qs_env(qs_env, matrix_ks_kp=image_matrices)
     268           28 :       matrix_ks => image_matrices(:, 1)
     269           28 :       IF (spin_channel < 1 .OR. spin_channel > SIZE(matrix_ks)) THEN
     270            0 :          CPABORT('SPECTRAL_LOCALIZER SPIN_CHANNEL is unavailable.')
     271              :       END IF
     272           28 :       IF (do_soc .AND. (SIZE(matrix_ks) /= 1 .OR. spin_channel /= 1)) THEN
     273            0 :          CPABORT('SPECTRAL_LOCALIZER SOC requires a restricted SCF and SPIN_CHANNEL 1.')
     274              :       END IF
     275           28 :       CALL section_vals_val_get(section, 'ENERGY', r_vals=energies)
     276           28 :       IF (periodic_localizer) THEN
     277           14 :          CALL section_vals_val_get(section, 'ETA', r_vals=kappas)
     278              :       ELSE
     279           14 :          CALL section_vals_val_get(section, 'KAPPA', r_vals=kappas)
     280              :       END IF
     281          100 :       IF (.NOT. ALL(ieee_is_finite(energies)) .OR. .NOT. ALL(ieee_is_finite(kappas))) THEN
     282            0 :          CPABORT('SPECTRAL_LOCALIZER requires finite ENERGY and KAPPA/ETA.')
     283              :       END IF
     284           64 :       IF (ANY(kappas <= 0.0_dp)) THEN
     285            0 :          CPABORT('SPECTRAL_LOCALIZER requires positive KAPPA/ETA.')
     286              :       END IF
     287           28 :       CALL section_vals_val_get(section, 'EPS_GAP', r_val=eps_gap)
     288           28 :       CALL section_vals_val_get(section, 'EPS_METRIC', r_val=eps_metric)
     289           28 :       CALL section_vals_val_get(section, 'MATRIX_TOLERANCE', r_val=matrix_tolerance)
     290          112 :       IF (.NOT. ALL(ieee_is_finite([eps_gap, eps_metric, matrix_tolerance]))) THEN
     291            0 :          CPABORT('SPECTRAL_LOCALIZER requires finite numerical tolerances.')
     292              :       END IF
     293              :       IF (eps_gap < 0.0_dp .OR. eps_metric <= 0.0_dp .OR. eps_metric >= 1.0_dp .OR. &
     294           28 :           matrix_tolerance <= 0.0_dp .OR. matrix_tolerance >= 1.0_dp) THEN
     295            0 :          CPABORT('SPECTRAL_LOCALIZER: invalid EPS_GAP, EPS_METRIC or MATRIX_TOLERANCE.')
     296              :       END IF
     297           28 :       CALL section_vals_val_get(section, 'SPECTRAL_FLATTENING', l_val=flatten)
     298           28 :       CALL section_vals_val_get(section, 'FLATTENING_SCALE', r_val=flatten_scale)
     299           28 :       CALL section_vals_val_get(section, 'EPS_FLATTENING', r_val=eps_flattening)
     300           28 :       CALL section_vals_val_get(section, 'EPS_ELECTRONIC_GAP', r_val=eps_electronic_gap)
     301           28 :       IF (flatten) THEN
     302           24 :          IF (.NOT. ALL(ieee_is_finite([flatten_scale, eps_flattening, eps_electronic_gap]))) THEN
     303            0 :             CPABORT('SPECTRAL_FLATTENING requires finite scales and tolerances.')
     304              :          END IF
     305            6 :          IF (flatten_scale <= 0.0_dp .OR. eps_flattening <= 0.0_dp .OR. eps_flattening >= 1.0_dp .OR. &
     306              :              eps_electronic_gap < 0.0_dp) THEN
     307            0 :             CPABORT('SPECTRAL_FLATTENING: invalid scale or tolerance.')
     308              :          END IF
     309              :       END IF
     310           28 :       CALL section_vals_val_get(section, 'POSITION', n_rep_val=nposition)
     311           28 :       n = nao
     312           28 :       IF (do_soc) n = 2*nao
     313           28 :       IF (torus) THEN
     314           12 :          NULLIFY (matrix_ks, matrix_s)
     315              :          CALL localizer_torus_operators(qs_env, grid, directions(:ndim), do_soc, matrix_ks, matrix_s, &
     316           12 :                                         cosines, positions, soc_matrices)
     317           16 :       ELSE IF (do_soc) THEN
     318            6 :          IF (.NOT. ASSOCIATED(soc_matrices)) CALL finite_ao_soc(qs_env, soc_matrices)
     319              :       END IF
     320           28 :       IF (output_unit > 0) THEN
     321           14 :          IF (periodic_localizer) THEN
     322            7 :             WRITE (output_unit, '(/,T2,A)') 'SPECTRAL_LOCALIZER| Periodic Born-von-Karman DBCSR localizer'
     323           28 :             WRITE (output_unit, '(T2,A,3I6)') 'SPECTRAL_LOCALIZER| Full analysis mesh: ', grid
     324            7 :             WRITE (output_unit, '(T2,A)') 'SPECTRAL_LOCALIZER| Analytic cos(G.r)/sin(G.r); no finite-coordinate substitution.'
     325            7 :             WRITE (output_unit, '(T2,A)') 'SPECTRAL_LOCALIZER| Finite AO torus diagnostic; converge basis, supercell and ETA.'
     326              :          ELSE
     327            7 :             WRITE (output_unit, '(/,T2,A)') 'SPECTRAL_LOCALIZER| Finite-system DBCSR localizer'
     328              :          END IF
     329           14 :          IF (ndim == 3) THEN
     330            3 :             WRITE (output_unit, '(T2,A)') 'SPECTRAL_LOCALIZER| LAPACK real LU/QR sign; independent generalized chiral gap.'
     331              :          ELSE
     332           11 :             WRITE (output_unit, '(T2,A)') 'SPECTRAL_LOCALIZER| LAPACK LDL inertia with eigenvalue validation.'
     333              :          END IF
     334           25 :          WRITE (output_unit, '(T2,A,I0)') 'SPECTRAL_LOCALIZER| Localizer dimension: ', MERGE(4*n, 2*n, ndim == 3)
     335           14 :          IF (ndim == 3) THEN
     336            3 :             WRITE (output_unit, '(T2,A)') 'SPECTRAL_LOCALIZER| Three-dimensional AII; chiral determinant sign.'
     337              :          ELSE
     338           33 :             WRITE (output_unit, '(T2,A,2A)') 'SPECTRAL_LOCALIZER| Oriented plane: ', axes(directions(:2))
     339              :          END IF
     340           14 :          IF (.NOT. periodic_localizer) THEN
     341            7 :             WRITE (output_unit, '(T2,A)') 'SPECTRAL_LOCALIZER| Check basis, volume and KAPPA convergence.'
     342              :          END IF
     343           14 :          IF (.NOT. do_soc) WRITE (output_unit, '(T2,A)') &
     344            5 :             'SPECTRAL_LOCALIZER| Real scalar Hamiltonian: no nonzero class A Chern index is expected.'
     345              :       END IF
     346           28 :       IF (flatten) THEN
     347            6 :          ALLOCATE (flat_hamiltonian)
     348            6 :          IF (do_soc) THEN
     349              :             CALL localizer_ao_operators(matrix_ks(spin_channel)%matrix, matrix_s(1)%matrix, positions(:0), &
     350            4 :                                         physical_h, physical_metric, soc_matrices)
     351              :          ELSE
     352              :             CALL localizer_ao_operators(matrix_ks(spin_channel)%matrix, matrix_s(1)%matrix, positions(:0), &
     353            2 :                                         physical_h, physical_metric)
     354              :          END IF
     355            6 :          IF (output_unit > 0) THEN
     356            3 :             WRITE (output_unit, '(T2,A,ES23.14)') 'SPECTRAL_LOCALIZER| Flattening scale [hartree]: ', flatten_scale
     357            3 :             WRITE (output_unit, '(T2,A)') 'SPECTRAL_LOCALIZER| Gaps and indices refer to the flattened Hamiltonian.'
     358            3 :             IF (periodic_localizer) THEN
     359            2 :                WRITE (output_unit, '(T2,A)') 'SPECTRAL_LOCALIZER| Flattening in complete primitive Bloch blocks.'
     360              :                WRITE (output_unit, '(T2,A)') &
     361            2 :                   'SPECTRAL_LOCALIZER| Residuals: translation, metric orthonormality, eigenproblem, Hermiticity.'
     362              :             END IF
     363              :          END IF
     364              :       END IF
     365           64 :       DO ie = 1, SIZE(energies)
     366           36 :          build_energy = energies(ie)
     367           36 :          IF (flatten) THEN
     368            8 :             CALL timeset('localizer_spectral_flattening', flatten_handle)
     369            8 :             IF (periodic_localizer) THEN
     370              :                CALL localizer_flatten_bloch(physical_h(1), physical_metric, grid, MERGE(2, 1, do_soc), &
     371              :                                             energies(ie), flatten_scale, eps_flattening, eps_metric, eps_electronic_gap, &
     372              :                                             para_env, flat_hamiltonian, electronic_gap(1), physical_ratio, &
     373            4 :                                             flatten_residuals, status)
     374            4 :                electronic_gap(2) = electronic_gap(1)
     375              :             ELSE
     376              :                CALL localizer_flatten_checked(physical_h(1), physical_metric, energies(ie), flatten_scale, eps_flattening, &
     377              :                                               eps_metric, eps_electronic_gap, para_env, flat_hamiltonian, &
     378            4 :                                               electronic_gap, physical_ratio, flatten_residuals, status)
     379              :             END IF
     380            8 :             CALL timestop(flatten_handle)
     381            8 :             IF (output_unit > 0) THEN
     382            4 :                WRITE (output_unit, '(T2,A,ES23.14)') 'SPECTRAL_LOCALIZER| Flattening query [hartree]: ', energies(ie)
     383              :                WRITE (output_unit, '(T2,A,2ES23.14)') &
     384            4 :                   'SPECTRAL_LOCALIZER| Original electronic gap bracket [hartree]: ', electronic_gap
     385            4 :                WRITE (output_unit, '(T2,A,ES23.14)') 'SPECTRAL_LOCALIZER| Original metric ratio bound: ', physical_ratio
     386            4 :                WRITE (output_unit, '(T2,A,4ES14.5)') 'SPECTRAL_LOCALIZER| Flattening residuals: ', flatten_residuals
     387              :             END IF
     388            0 :             SELECT CASE (status)
     389              :             CASE (0)
     390              :             CASE (1)
     391            0 :                CPABORT('SPECTRAL_FLATTENING: electronic gap unresolved; no index.')
     392              :             CASE (-2)
     393            0 :                CPABORT('SPECTRAL_FLATTENING: invalid original AO metric.')
     394              :             CASE (-6)
     395            0 :                CPABORT('SPECTRAL_FLATTENING: sign iteration or structure failed.')
     396              :             CASE (-7)
     397            0 :                CPABORT('SPECTRAL_FLATTENING: broken torus translations.')
     398              :             CASE DEFAULT
     399            8 :                CPABORT('SPECTRAL_FLATTENING: input or gap factorization failed.')
     400              :             END SELECT
     401            8 :             build_energy = 0.0_dp
     402              :          END IF
     403           88 :          DO ip = 1, nposition
     404           52 :             CALL section_vals_val_get(section, 'POSITION', i_rep_val=ip, r_vals=point)
     405          208 :             IF (.NOT. ALL(ieee_is_finite(point))) THEN
     406            0 :                CPABORT('SPECTRAL_LOCALIZER requires finite POSITION.')
     407              :             END IF
     408          162 :             local_point(:ndim) = point(directions(:ndim))
     409           52 :             IF (periodic_localizer) THEN
     410           46 :                DO axis = 1, ndim
     411              :                   local_point(axis) = twopi*DOT_PRODUCT(cell%h_inv(directions(axis), :), point)/ &
     412          142 :                                       REAL(grid(directions(axis)), dp)
     413              :                END DO
     414              :             END IF
     415          172 :             DO ik = 1, SIZE(kappas)
     416           84 :                IF (ndim == 3) THEN
     417              :                   CALL localizer_dbcsr_3d_build(matrix_ks(spin_channel)%matrix, matrix_s(1)%matrix, positions, &
     418              :                                                 local_point, build_energy, kappas(ik), localizer, metric, soc_matrices, &
     419            6 :                                                 shifted_hamiltonian=flat_hamiltonian, periodic_cosines=cosines)
     420           78 :                ELSE IF (do_soc) THEN
     421              :                   CALL localizer_dbcsr_build(matrix_ks(spin_channel)%matrix, matrix_s(1)%matrix, &
     422              :                                              positions(directions(1))%matrix, positions(directions(2))%matrix, &
     423              :                                              local_point(:2), build_energy, kappas(ik), localizer, metric, soc_matrices, cosines, &
     424           12 :                                              shifted_hamiltonian=flat_hamiltonian)
     425              :                ELSE
     426              :                   CALL localizer_dbcsr_build(matrix_ks(spin_channel)%matrix, matrix_s(1)%matrix, &
     427              :                                              positions(directions(1))%matrix, positions(directions(2))%matrix, &
     428              :                                              local_point(:2), build_energy, kappas(ik), localizer, metric, &
     429           66 :                                              periodic_cosines=cosines, shifted_hamiltonian=flat_hamiltonian)
     430              :                END IF
     431           84 :                CALL localizer_dbcsr_dense(localizer, para_env, local_dense)
     432           84 :                CALL localizer_dbcsr_dense(metric, para_env, metric_dense)
     433           84 :                IF (para_env%is_source()) THEN
     434           42 :                   IF (ndim == 3) THEN
     435              :                      CALL localizer_3d_matrix_evaluate(local_dense, metric_dense(:n, :n), &
     436              :                                                        matrix_tolerance, eps_metric, eps_gap, invariant, gap, &
     437            3 :                                                        metric_ratio, status)
     438              :                   ELSE
     439              :                      CALL localizer_matrix_evaluate(local_dense, metric_dense(:n, :n), aii, &
     440           39 :                                                     matrix_tolerance, eps_metric, eps_gap, invariant, gap, metric_ratio, status)
     441              :                   END IF
     442           42 :                   IF (status < 0 .AND. output_unit > 0 .AND. ndim == 2) THEN
     443              :                      WRITE (output_unit, '(T2,A,I0,2ES14.5)') &
     444            0 :                         'SPECTRAL_LOCALIZER| Failure status and L/B Hermiticity residuals: ', status, &
     445            0 :                         MAXVAL(ABS(local_dense - CONJG(TRANSPOSE(local_dense)))), &
     446            0 :                         MAXVAL(ABS(metric_dense - CONJG(TRANSPOSE(metric_dense))))
     447              :                   END IF
     448              :                END IF
     449           84 :                DEALLOCATE (local_dense, metric_dense)
     450           84 :                CALL localizer_dbcsr_release(localizer)
     451           84 :                CALL localizer_dbcsr_release(metric)
     452           84 :                CALL para_env%bcast(status, para_env%source)
     453           84 :                IF (status < 0 .OR. status > 1) THEN
     454            0 :                   SELECT CASE (status)
     455              :                   CASE (-2)
     456            0 :                      CPABORT('SPECTRAL_LOCALIZER: invalid AO metric; check basis/EPS_METRIC.')
     457              :                   CASE (-3)
     458            0 :                      CPABORT('SPECTRAL_LOCALIZER: broken physical TR/AII structure.')
     459              :                   CASE DEFAULT
     460            0 :                      CPABORT('SPECTRAL_LOCALIZER: invalid data or factorization failure.')
     461              :                   END SELECT
     462              :                END IF
     463           84 :                CALL para_env%bcast(invariant, para_env%source)
     464           84 :                CALL para_env%bcast(gap, para_env%source)
     465           84 :                CALL para_env%bcast(metric_ratio, para_env%source)
     466          136 :                IF (output_unit > 0) THEN
     467          168 :                   WRITE (output_unit, '(T2,A,3ES23.14)') 'SPECTRAL_LOCALIZER| Position [bohr]: ', point
     468           42 :                   WRITE (output_unit, '(T2,A,ES23.14)') 'SPECTRAL_LOCALIZER| Energy [hartree]: ', energies(ie)
     469           42 :                   IF (periodic_localizer) THEN
     470            7 :                      WRITE (output_unit, '(T2,A,ES23.14)') 'SPECTRAL_LOCALIZER| Eta [hartree]: ', kappas(ik)
     471              :                   ELSE
     472           35 :                      WRITE (output_unit, '(T2,A,ES23.14)') 'SPECTRAL_LOCALIZER| Kappa [hartree/bohr]: ', kappas(ik)
     473              :                   END IF
     474           42 :                   WRITE (output_unit, '(T2,A,ES23.14)') 'SPECTRAL_LOCALIZER| Metric ratio: ', metric_ratio
     475           42 :                   WRITE (output_unit, '(T2,A,ES23.14)') 'SPECTRAL_LOCALIZER| Gap [hartree]: ', gap
     476           42 :                   IF (status == 1) THEN
     477            8 :                      WRITE (output_unit, '(T2,A)') 'SPECTRAL_LOCALIZER| UNRESOLVED: gap or factorization below accuracy; no index.'
     478           34 :                   ELSE IF (aii) THEN
     479            9 :                      WRITE (output_unit, '(T2,A,I0)') 'SPECTRAL_LOCALIZER| Z2 index: ', invariant
     480              :                   ELSE
     481           25 :                      WRITE (output_unit, '(T2,A,I0)') 'SPECTRAL_LOCALIZER| Chern index: ', invariant
     482              :                   END IF
     483              :                END IF
     484              :             END DO
     485              :          END DO
     486           64 :          IF (flatten) CALL localizer_dbcsr_release(flat_hamiltonian)
     487              :       END DO
     488           28 :       IF (flatten) THEN
     489            6 :          CALL localizer_dbcsr_release(physical_h(1))
     490            6 :          CALL localizer_dbcsr_release(physical_metric)
     491            6 :          DEALLOCATE (flat_hamiltonian)
     492              :       END IF
     493           28 :       CALL dbcsr_deallocate_matrix_set(positions)
     494           28 :       IF (ASSOCIATED(cosines)) CALL dbcsr_deallocate_matrix_set(cosines)
     495           28 :       IF (ASSOCIATED(soc_matrices)) CALL dbcsr_deallocate_matrix_set(soc_matrices)
     496           28 :       IF (torus) THEN
     497           12 :          CALL dbcsr_deallocate_matrix_set(matrix_ks)
     498           12 :          CALL dbcsr_deallocate_matrix_set(matrix_s)
     499              :       END IF
     500           28 :       CALL timestop(handle)
     501        42749 :    END SUBROUTINE qs_scf_post_localizer
     502              : 
     503              : ! **************************************************************************************************
     504              : !> \brief Analytic torus coordinates in the reciprocal frame of a Gamma supercell.
     505              : !> \param qs_env Quickstep environment
     506              : !> \param directions Two or three periodic lattice directions
     507              : !> \param cosines Newly allocated cosine matrices, indexed by oriented direction
     508              : !> \param sines Newly allocated sine matrices, indexed by lattice direction
     509              : ! **************************************************************************************************
     510            2 :    SUBROUTINE periodic_ao_moments(qs_env, directions, cosines, sines)
     511              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     512              :       INTEGER, INTENT(IN)                                :: directions(:)
     513              :       TYPE(dbcsr_p_type), POINTER                        :: cosines(:), sines(:)
     514              : 
     515              :       INTEGER                                            :: j
     516              :       TYPE(cell_type), POINTER                           :: cell
     517            2 :       TYPE(dbcsr_p_type), POINTER                        :: matrix_s(:)
     518            2 :       TYPE(neighbor_list_set_p_type), POINTER            :: sab_orb(:)
     519              : 
     520            2 :       CALL get_qs_env(qs_env, cell=cell, matrix_s=matrix_s, sab_orb=sab_orb)
     521           16 :       ALLOCATE (cosines(SIZE(directions)), sines(3))
     522            8 :       DO j = 1, 3
     523            6 :          ALLOCATE (sines(j)%matrix)
     524            6 :          CALL dbcsr_create(sines(j)%matrix, template=matrix_s(1)%matrix, name='TORUS SIN')
     525            6 :          CALL cp_dbcsr_alloc_block_from_nbl(sines(j)%matrix, sab_orb)
     526            8 :          CALL dbcsr_set(sines(j)%matrix, 0.0_dp)
     527              :       END DO
     528            6 :       DO j = 1, SIZE(directions)
     529            4 :          ALLOCATE (cosines(j)%matrix)
     530            4 :          CALL dbcsr_create(cosines(j)%matrix, template=matrix_s(1)%matrix, name='TORUS COS')
     531            4 :          CALL cp_dbcsr_alloc_block_from_nbl(cosines(j)%matrix, sab_orb)
     532            4 :          CALL dbcsr_set(cosines(j)%matrix, 0.0_dp)
     533              :          CALL build_berry_moment_matrix(qs_env, cosines(j)%matrix, sines(directions(j))%matrix, &
     534           18 :                                         twopi*cell%h_inv(directions(j), :))
     535              :       END DO
     536            2 :    END SUBROUTINE periodic_ao_moments
     537              : 
     538              : END MODULE qs_spectral_localizer
        

Generated by: LCOV version 2.0-1