LCOV - code coverage report
Current view: top level - src - qs_quadratic_pseudospectrum.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 90.1 % 273 246
Test Date: 2026-10-15 00:55:44 Functions: 100.0 % 1 1

            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 Finite or periodic quadratic pseudospectrum analysis after SCF.
      10              : !> \author Thomas D. Kuehne, tkuehne@cp2k.org
      11              : ! **************************************************************************************************
      12              : MODULE qs_quadratic_pseudospectrum
      13              :    USE bibliography,                    ONLY: Bairnsfather2026,&
      14              :                                               Cerjan2023
      15              :    USE cell_types,                      ONLY: cell_transform_input_cartesian,&
      16              :                                               cell_transform_input_reciprocal,&
      17              :                                               cell_type,&
      18              :                                               use_perd_none
      19              :    USE cp_control_types,                ONLY: dft_control_type
      20              :    USE cp_dbcsr_api,                    ONLY: dbcsr_get_info,&
      21              :                                               dbcsr_p_type
      22              :    USE cp_dbcsr_operations,             ONLY: dbcsr_deallocate_matrix_set
      23              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      24              :                                               cp_logger_get_default_io_unit,&
      25              :                                               cp_logger_type
      26              :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      27              :                                               cp_print_key_unit_nr
      28              :    USE ieee_arithmetic,                 ONLY: ieee_is_finite
      29              :    USE input_constants,                 ONLY: do_method_gapw,&
      30              :                                               do_method_gpw
      31              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      32              :                                               section_vals_type,&
      33              :                                               section_vals_val_get
      34              :    USE kinds,                           ONLY: dp
      35              :    USE mathconstants,                   ONLY: twopi
      36              :    USE message_passing,                 ONLY: mp_para_env_type
      37              :    USE qs_ao_translations,              ONLY: ao_translation_matrices
      38              :    USE qs_environment_types,            ONLY: get_qs_env,&
      39              :                                               qs_environment_type
      40              :    USE qs_finite_ao,                    ONLY: finite_ao_positions,&
      41              :                                               finite_ao_soc
      42              :    USE qs_localizer_torus,              ONLY: localizer_torus_operators,&
      43              :                                               torus_translation_operators
      44              :    USE quadratic_pseudospectrum,        ONLY: quadratic_dense,&
      45              :                                               quadratic_result_type
      46              :    USE reference_manager,               ONLY: cite_reference
      47              :    USE spectral_localizer_dbcsr,        ONLY: localizer_ao_operators,&
      48              :                                               localizer_dbcsr_check,&
      49              :                                               localizer_dbcsr_dense,&
      50              :                                               localizer_dbcsr_release,&
      51              :                                               localizer_matrix_type
      52              : #include "./base/base_uses.f90"
      53              : 
      54              :    IMPLICIT NONE
      55              :    PRIVATE
      56              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_quadratic_pseudospectrum'
      57              :    PUBLIC :: qs_scf_post_quadratic
      58              : CONTAINS
      59              : ! **************************************************************************************************
      60              : !> \brief Evaluate scans of quadratic gaps and localized joint approximate eigenstates.
      61              : !> \param qs_env Converged Quickstep environment
      62              : ! **************************************************************************************************
      63        14147 :    SUBROUTINE qs_scf_post_quadratic(qs_env)
      64              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      65              : 
      66              :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_scf_post_quadratic'
      67              : 
      68              :       CHARACTER(len=256)                                 :: matrix_error
      69        14147 :       COMPLEX(dp), ALLOCATABLE                           :: complex_shift(:), dense_metric(:, :), &
      70        14147 :                                                             dense_operators(:, :, :), &
      71        14147 :                                                             temporary(:, :)
      72              :       INTEGER :: ao, axis, cell_periodic, formulation, handle, i, ie, ik, ip, iw, j, max_ao, &
      73              :          max_iter, max_space, n, nao, ndim, nobs, npositions, nstates, nt, output_unit, periodic, &
      74              :          spin, status
      75        14147 :       INTEGER, ALLOCATABLE                               :: directions(:)
      76        14147 :       INTEGER, POINTER                                   :: grid(:)
      77              :       LOGICAL :: active, do_kpoints, do_soc, explicit_grid, explicit_value, periodic_analysis, &
      78              :          torus_analysis, translation_analysis, valid
      79        14147 :       LOGICAL, ALLOCATABLE                               :: unitary(:)
      80              :       REAL(dp)                                           :: eps_eigen, eps_metric, &
      81              :                                                             hermiticity_error, &
      82              :                                                             max_hermiticity_error, query(3)
      83        14147 :       REAL(dp), ALLOCATABLE                              :: angles(:), radii(:), shift(:), &
      84        14147 :                                                             translations(:, :), weights(:)
      85        14147 :       REAL(dp), POINTER                                  :: energies(:), kappas(:), point(:)
      86              :       TYPE(cell_type), POINTER                           :: cell
      87              :       TYPE(cp_logger_type), POINTER                      :: logger
      88        14147 :       TYPE(dbcsr_p_type), POINTER                        :: cosines(:), images_h(:, :), &
      89        14147 :                                                             images_s(:, :), matrix_ks(:), &
      90        14147 :                                                             matrix_s(:), positions(:), sines(:), &
      91        14147 :                                                             soc(:, :)
      92              :       TYPE(dft_control_type), POINTER                    :: dft_control
      93              :       TYPE(localizer_matrix_type)                        :: metric
      94        14147 :       TYPE(localizer_matrix_type), ALLOCATABLE           :: operators(:)
      95              :       TYPE(mp_para_env_type), POINTER                    :: para_env
      96        14147 :       TYPE(quadratic_result_type)                        :: result
      97              :       TYPE(section_vals_type), POINTER                   :: input, section
      98              : 
      99        14147 :       CALL timeset(routineN, handle)
     100        14147 :       CALL get_qs_env(qs_env, input=input)
     101        14147 :       section => section_vals_get_subs_vals(input, 'PROPERTIES%QUADRATIC_PSEUDOSPECTRUM')
     102        14147 :       CALL section_vals_val_get(section, '_SECTION_PARAMETERS_', l_val=active)
     103        14147 :       IF (.NOT. active) THEN
     104        14131 :          CALL timestop(handle)
     105        14131 :          RETURN
     106              :       END IF
     107           16 :       IF (.NOT. qs_env%scf_convergence_available .OR. .NOT. qs_env%scf_converged) THEN
     108            0 :          CPABORT('QUADRATIC_PSEUDOSPECTRUM requires converged SCF.')
     109              :       END IF
     110              :       CALL get_qs_env(qs_env, matrix_s_kp=images_s, matrix_ks_kp=images_h, para_env=para_env, &
     111           16 :                       cell=cell, dft_control=dft_control, do_kpoints=do_kpoints)
     112           16 :       matrix_s => images_s(:, 1)
     113           16 :       matrix_ks => images_h(:, 1)
     114           16 :       SELECT CASE (dft_control%qs_control%method_id)
     115              :       CASE (do_method_gpw, do_method_gapw)
     116              :       CASE DEFAULT
     117           16 :          CPABORT('QUADRATIC_PSEUDOSPECTRUM supports GPW/GAPW only.')
     118              :       END SELECT
     119           16 :       CALL section_vals_val_get(section, 'FORMULATION', i_val=formulation)
     120           16 :       periodic_analysis = formulation == 1
     121           16 :       translation_analysis = formulation == 2
     122           34 :       torus_analysis = periodic_analysis .OR. (translation_analysis .AND. ANY(cell%perd /= 0))
     123           16 :       CALL section_vals_val_get(section, 'MP_GRID', i_vals=grid, explicit=explicit_grid)
     124           64 :       IF (ANY(grid < 1)) CPABORT('Quadratic MP_GRID must be positive.')
     125           16 :       IF (.NOT. torus_analysis .AND. explicit_grid) THEN
     126            0 :          CPABORT('Quadratic MP_GRID requires a periodic property analysis.')
     127              :       END IF
     128           64 :       IF (ANY(grid /= 1 .AND. cell%perd == 0)) THEN
     129            0 :          CPABORT('Quadratic MP_GRID must be one in open directions.')
     130              :       END IF
     131           16 :       CALL section_vals_val_get(input, 'DFT%POISSON%PERIODIC', i_val=periodic)
     132           16 :       IF (torus_analysis) THEN
     133           10 :          CALL section_vals_val_get(input, 'SUBSYS%CELL%PERIODIC', i_val=cell_periodic)
     134           40 :          IF (cell_periodic /= periodic .OR. COUNT(cell%perd /= 0) == 0) THEN
     135            0 :             CPABORT('Quadratic torus needs matching, nonempty CELL/POISSON PERIODIC.')
     136              :          END IF
     137           40 :          ndim = COUNT(cell%perd /= 0)
     138           30 :          ALLOCATE (directions(ndim))
     139           40 :          directions(:) = PACK([1, 2, 3], cell%perd /= 0)
     140           20 :          IF (periodic_analysis) THEN
     141            4 :             nobs = 1 + 2*ndim
     142           16 :             ALLOCATE (radii(ndim), angles(ndim))
     143           14 :             DO i = 1, ndim
     144           10 :                axis = directions(i)
     145           44 :                radii(i) = REAL(grid(axis), dp)/(twopi*SQRT(SUM(cell%h_inv(axis, :)**2)))
     146              :             END DO
     147              :          END IF
     148              :       ELSE
     149           24 :          IF (periodic /= use_perd_none .OR. ANY(cell%perd /= 0) .OR. do_kpoints) THEN
     150            0 :             CPABORT('Finite quadratic analysis requires PERIODIC NONE without KPOINTS.')
     151              :          END IF
     152              :          nobs = 4
     153              :       END IF
     154           16 :       IF (translation_analysis) THEN
     155            8 :          CALL section_vals_val_get(section, 'TRANSLATION_VECTOR', n_rep_val=nt)
     156            8 :          IF (nt < 1) THEN
     157            0 :             CPABORT('Quadratic TRANSLATION requires at least one TRANSLATION_VECTOR.')
     158              :          END IF
     159            8 :          nobs = 1 + nt
     160           56 :          ALLOCATE (translations(3, nt), complex_shift(nobs), unitary(nobs))
     161           26 :          unitary = .TRUE.
     162            8 :          unitary(1) = .FALSE.
     163           18 :          DO i = 1, nt
     164           10 :             CALL section_vals_val_get(section, 'TRANSLATION_VECTOR', i_rep_val=i, r_vals=point)
     165           40 :             IF (.NOT. ALL(ieee_is_finite(point))) THEN
     166            0 :                CPABORT('Quadratic TRANSLATION_VECTOR must be finite.')
     167              :             END IF
     168           40 :             translations(:, i) = point
     169           18 :             CALL cell_transform_input_cartesian(cell, translations(:, i))
     170              :          END DO
     171            8 :          CALL section_vals_val_get(section, 'POSITION', explicit=explicit_value)
     172            8 :          IF (explicit_value) THEN
     173            0 :             CPABORT('Quadratic TRANSLATION uses WAVE_VECTOR, not POSITION.')
     174              :          END IF
     175            8 :          CALL section_vals_val_get(section, 'KAPPA', explicit=explicit_value)
     176           24 :          IF (explicit_value) THEN
     177            0 :             CPABORT('Quadratic TRANSLATION uses TRANSLATION_SCALE, not KAPPA.')
     178              :          END IF
     179              :       ELSE
     180            8 :          CALL section_vals_val_get(section, 'TRANSLATION_VECTOR', explicit=explicit_value)
     181            8 :          IF (explicit_value) THEN
     182            0 :             CPABORT('TRANSLATION_VECTOR requires quadratic FORMULATION TRANSLATION.')
     183              :          END IF
     184            8 :          CALL section_vals_val_get(section, 'WAVE_VECTOR', explicit=explicit_value)
     185            8 :          IF (explicit_value) THEN
     186            0 :             CPABORT('WAVE_VECTOR requires quadratic FORMULATION TRANSLATION.')
     187              :          END IF
     188            8 :          CALL section_vals_val_get(section, 'TRANSLATION_SCALE', explicit=explicit_value)
     189            8 :          IF (explicit_value) THEN
     190            0 :             CPABORT('TRANSLATION_SCALE requires quadratic FORMULATION TRANSLATION.')
     191              :          END IF
     192              :       END IF
     193          154 :       ALLOCATE (operators(nobs), shift(nobs), weights(nobs))
     194           16 :       CALL section_vals_val_get(section, 'SPIN_CHANNEL', i_val=spin)
     195           16 :       IF (spin < 1 .OR. spin > SIZE(matrix_ks)) THEN
     196            0 :          CPABORT('Quadratic SPIN_CHANNEL is unavailable.')
     197              :       END IF
     198           16 :       CALL section_vals_val_get(section, 'SOC', l_val=do_soc)
     199           16 :       IF (do_soc .AND. spin /= 1) CPABORT('Quadratic SOC requires SPIN_CHANNEL 1.')
     200           16 :       CALL dbcsr_get_info(matrix_s(1)%matrix, nfullrows_total=nao)
     201           16 :       CALL section_vals_val_get(section, 'MAX_AO', i_val=max_ao)
     202           16 :       IF (nao > max_ao .OR. max_ao < 1) CPABORT('QUADRATIC_PSEUDOSPECTRUM exceeds MAX_AO.')
     203           64 :       DO axis = 1, 3
     204           48 :          IF (grid(axis) > max_ao/nao) CPABORT('Quadratic full AO torus exceeds MAX_AO.')
     205           64 :          nao = nao*grid(axis)
     206              :       END DO
     207           16 :       n = nao
     208           16 :       IF (do_soc) n = 2*nao
     209           16 :       CALL section_vals_val_get(section, 'NSTATES', i_val=nstates)
     210           16 :       max_space = n
     211           16 :       max_iter = 1
     212           16 :       CALL section_vals_val_get(section, 'EPS_EIGEN', r_val=eps_eigen)
     213           16 :       CALL section_vals_val_get(section, 'EPS_METRIC', r_val=eps_metric)
     214           16 :       CALL section_vals_val_get(section, 'ENERGY', r_vals=energies)
     215           16 :       CALL section_vals_val_get(section, 'KAPPA', r_vals=kappas)
     216           16 :       CALL section_vals_val_get(section, 'POSITION', n_rep_val=npositions)
     217           16 :       IF (translation_analysis) THEN
     218            8 :          CALL section_vals_val_get(section, 'TRANSLATION_SCALE', r_vals=kappas)
     219            8 :          CALL section_vals_val_get(section, 'WAVE_VECTOR', n_rep_val=npositions)
     220              :       END IF
     221           16 :       IF (nstates < 1 .OR. nstates > n .OR. max_iter < 1) THEN
     222            0 :          CPABORT('Invalid quadratic state/iteration limits.')
     223              :       END IF
     224          116 :       IF (.NOT. ALL(ieee_is_finite([energies, kappas, eps_eigen, eps_metric]))) THEN
     225            0 :          CPABORT('Quadratic analysis requires finite parameters.')
     226              :       END IF
     227           32 :       IF (ANY(kappas <= 0.0_dp) .OR. eps_eigen <= 0.0_dp .OR. eps_metric <= 0.0_dp .OR. eps_metric >= 1.0_dp) THEN
     228            0 :          CPABORT('Invalid quadratic scales or tolerances.')
     229              :       END IF
     230           16 :       CALL cite_reference(Cerjan2023)
     231           16 :       IF (translation_analysis) CALL cite_reference(Bairnsfather2026)
     232           16 :       NULLIFY (positions, soc)
     233           16 :       IF (periodic_analysis) THEN
     234            4 :          CALL localizer_torus_operators(qs_env, grid, directions, do_soc, matrix_ks, matrix_s, cosines, sines, soc)
     235           32 :          ALLOCATE (positions(2*ndim))
     236           14 :          DO i = 1, ndim
     237           10 :             positions(2*i - 1)%matrix => cosines(i)%matrix
     238           14 :             positions(2*i)%matrix => sines(directions(i))%matrix
     239              :          END DO
     240           12 :       ELSE IF (translation_analysis) THEN
     241            8 :          IF (torus_analysis) THEN
     242            6 :             CALL torus_translation_operators(qs_env, grid, translations, do_soc, matrix_ks, matrix_s, positions, soc)
     243              :          ELSE
     244            2 :             CALL ao_translation_matrices(qs_env, translations, positions)
     245              :          END IF
     246              :       ELSE
     247            4 :          CALL finite_ao_positions(qs_env, positions)
     248              :       END IF
     249           16 :       IF (do_soc .AND. .NOT. torus_analysis) THEN
     250            2 :          CALL finite_ao_soc(qs_env, soc)
     251              :       END IF
     252           16 :       IF (do_soc) THEN
     253            4 :          CALL localizer_ao_operators(matrix_ks(spin)%matrix, matrix_s(1)%matrix, positions, operators, metric, soc)
     254            4 :          CALL dbcsr_deallocate_matrix_set(soc)
     255              :       ELSE
     256           12 :          CALL localizer_ao_operators(matrix_ks(spin)%matrix, matrix_s(1)%matrix, positions, operators, metric)
     257              :       END IF
     258           16 :       IF (periodic_analysis) THEN
     259            4 :          DEALLOCATE (positions)
     260            4 :          CALL dbcsr_deallocate_matrix_set(cosines)
     261            4 :          CALL dbcsr_deallocate_matrix_set(sines)
     262              :       ELSE
     263           12 :          CALL dbcsr_deallocate_matrix_set(positions)
     264              :       END IF
     265           16 :       IF (torus_analysis) THEN
     266           10 :          CALL dbcsr_deallocate_matrix_set(matrix_ks)
     267           10 :          CALL dbcsr_deallocate_matrix_set(matrix_s)
     268              :       END IF
     269           16 :       CALL localizer_dbcsr_check(metric, para_env, 1.e-10_dp, valid, max_hermiticity_error)
     270           16 :       IF (.NOT. valid) CPABORT('Quadratic AO metric is nonfinite or not Hermitian.')
     271           74 :       DO i = 1, nobs
     272           58 :          IF (translation_analysis .AND. i > 1) CYCLE
     273           48 :          CALL localizer_dbcsr_check(operators(i), para_env, 1.e-10_dp, valid, hermiticity_error)
     274           48 :          max_hermiticity_error = MAX(max_hermiticity_error, hermiticity_error)
     275           64 :          IF (.NOT. valid) THEN
     276            0 :             WRITE (matrix_error, '(A,I0,A,ES12.4,A)') 'Quadratic AO operator ', i, &
     277            0 :                ' is nonfinite or not Hermitian (relative error ', hermiticity_error, &
     278            0 :                '). Check QS%EPS_PPNL/EPS_PGF_ORB and integration thresholds; no symmetrization is applied.'
     279            0 :             CPABORT(TRIM(matrix_error))
     280              :          END IF
     281              :       END DO
     282           80 :       ALLOCATE (dense_operators(n, n, nobs))
     283           16 :       CALL localizer_dbcsr_dense(metric, para_env, dense_metric)
     284           74 :       DO i = 1, nobs
     285           58 :          CALL localizer_dbcsr_dense(operators(i), para_env, temporary)
     286        45034 :          dense_operators(:, :, i) = temporary
     287           74 :          DEALLOCATE (temporary)
     288              :       END DO
     289           16 :       logger => cp_get_default_logger()
     290           16 :       output_unit = cp_logger_get_default_io_unit(logger)
     291           16 :       iw = cp_print_key_unit_nr(logger, section, 'STATES', extension='.states')
     292           16 :       IF (iw > 0) WRITE (iw, '(A)') '# Quadratic eigenstates: S-normalized AO coefficients, spin-major for SOC'
     293           31 :       IF (iw > 0 .AND. torus_analysis) WRITE (iw, '(A,3I8)') '# Cell-major AO torus within each spin block; grid ', grid
     294           16 :       IF (output_unit > 0) THEN
     295            8 :          WRITE (output_unit, '(/,T2,A,I0)') 'QUADRATIC_PSEUDOSPECTRUM| AO/spinor dimension: ', n
     296            8 :          WRITE (output_unit, '(T2,A,ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Relative Hermiticity error: ', max_hermiticity_error
     297            8 :          WRITE (output_unit, '(T2,A)') 'QUADRATIC_PSEUDOSPECTRUM| Dense finite-basis reference'
     298            8 :          WRITE (output_unit, '(T2,A)') 'QUADRATIC_PSEUDOSPECTRUM| Joint approximate states, not a topology index.'
     299            8 :          IF (translation_analysis) THEN
     300            4 :             WRITE (output_unit, '(T2,A)') 'QUADRATIC_PSEUDOSPECTRUM| Continuum translations U(a) psi(r) = psi(r+a).'
     301            4 :             WRITE (output_unit, '(T2,A)') 'QUADRATIC_PSEUDOSPECTRUM| Full translation norms include loss outside the AO span.'
     302            4 :             WRITE (output_unit, '(T2,A)') 'QUADRATIC_PSEUDOSPECTRUM| Energy residual still uses the projected AO Hamiltonian.'
     303            9 :             DO i = 1, nt
     304            5 :                WRITE (output_unit, '(T2,A,I0,A,3ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Translation ', i, &
     305           14 :                   ' internal [bohr]: ', translations(:, i)
     306              :             END DO
     307              :          END IF
     308            8 :          IF (torus_analysis) THEN
     309           20 :             WRITE (output_unit, '(T2,A,3I6)') 'QUADRATIC_PSEUDOSPECTRUM| Full analysis mesh: ', grid
     310            5 :             WRITE (output_unit, '(T2,A,3I4)') 'QUADRATIC_PSEUDOSPECTRUM| Periodic lattice directions: ', directions
     311            5 :             IF (translation_analysis) THEN
     312            3 :                WRITE (output_unit, '(T2,A)') 'QUADRATIC_PSEUDOSPECTRUM| Periodized translations on the full AO torus.'
     313              :             ELSE
     314            2 :                WRITE (output_unit, '(T2,A)') 'QUADRATIC_PSEUDOSPECTRUM| Torus chord metric; open directions are not localized.'
     315              :             END IF
     316              :          END IF
     317              :       END IF
     318           36 :       DO ip = 1, npositions
     319           20 :          IF (translation_analysis) THEN
     320           10 :             CALL section_vals_val_get(section, 'WAVE_VECTOR', i_rep_val=ip, r_vals=point)
     321              :          ELSE
     322           10 :             CALL section_vals_val_get(section, 'POSITION', i_rep_val=ip, r_vals=point)
     323              :          END IF
     324           80 :          IF (.NOT. ALL(ieee_is_finite(point))) THEN
     325            0 :             CPABORT('Quadratic POSITION or WAVE_VECTOR must be finite.')
     326              :          END IF
     327           20 :          IF (translation_analysis) THEN
     328           40 :             query = point
     329           10 :             CALL cell_transform_input_reciprocal(cell, query)
     330           24 :             DO i = 1, nt
     331           66 :                complex_shift(i + 1) = EXP(CMPLX(0.0_dp, DOT_PRODUCT(query, translations(:, i)), dp))
     332              :             END DO
     333           10 :          ELSE IF (periodic_analysis) THEN
     334           16 :             query = point
     335            4 :             CALL cell_transform_input_cartesian(cell, query)
     336           14 :             DO i = 1, ndim
     337           10 :                axis = directions(i)
     338           40 :                angles(i) = twopi*MODULO(DOT_PRODUCT(cell%h_inv(axis, :), query)/REAL(grid(axis), dp), 1.0_dp)
     339           10 :                shift(2*i) = COS(angles(i))
     340           14 :                shift(2*i + 1) = SIN(angles(i))
     341              :             END DO
     342              :          ELSE
     343           24 :             shift(2:) = point
     344              :          END IF
     345           56 :          DO ik = 1, SIZE(kappas)
     346           64 :             DO ie = 1, SIZE(energies)
     347           24 :                shift(1) = energies(ie)
     348          112 :                weights = kappas(ik)
     349           24 :                weights(1) = 1.0_dp
     350           24 :                IF (periodic_analysis) THEN
     351           14 :                   DO i = 1, ndim
     352           34 :                      weights(2*i:2*i + 1) = kappas(ik)*radii(i)
     353              :                   END DO
     354              :                END IF
     355           24 :                IF (para_env%is_source()) THEN
     356           12 :                   IF (translation_analysis) THEN
     357            5 :                      complex_shift(1) = energies(ie)
     358              :                      CALL quadratic_dense(dense_operators, dense_metric, complex_shift, weights, nstates, .FALSE., max_space, &
     359            5 :                                           max_iter, eps_eigen, eps_metric, RESULT, status, unitary)
     360              :                   ELSE
     361              :                      CALL quadratic_dense(dense_operators, dense_metric, shift, weights, nstates, .FALSE., max_space, &
     362            7 :                                           max_iter, eps_eigen, eps_metric, RESULT, status)
     363              :                   END IF
     364              :                END IF
     365           24 :                CALL para_env%bcast(status, para_env%source)
     366           24 :                IF (status /= 0) THEN
     367            0 :                   IF (status == 1) THEN
     368            0 :                      IF (output_unit > 0) THEN
     369              :                         WRITE (output_unit, '(T2,A,I0,A,ES23.14)') &
     370            0 :                            'QUADRATIC_PSEUDOSPECTRUM| Unconverged after ', result%iterations, &
     371            0 :                            ' iterations; maximum residual: ', MAXVAL(result%residuals)
     372              :                      END IF
     373            0 :                      CPABORT('Quadratic eigensolver unconverged.')
     374              :                   END IF
     375            0 :                   CPABORT('Quadratic analysis failed numerical checks.')
     376              :                END IF
     377           24 :                IF (output_unit > 0) THEN
     378           12 :                   IF (translation_analysis) THEN
     379           20 :                      WRITE (output_unit, '(T2,A,3ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Wave vector [bohr^-1]: ', point
     380            5 :                      WRITE (output_unit, '(T2,A,ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Translation scale [hartree]: ', kappas(ik)
     381              :                   ELSE
     382           28 :                      WRITE (output_unit, '(T2,A,3ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Position [bohr]: ', point
     383            7 :                      WRITE (output_unit, '(T2,A,ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Kappa [hartree/bohr]: ', kappas(ik)
     384              :                   END IF
     385           12 :                   WRITE (output_unit, '(T2,A,ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Energy [hartree]: ', energies(ie)
     386           12 :                   WRITE (output_unit, '(T2,A,I0)') 'QUADRATIC_PSEUDOSPECTRUM| Ritz iterations: ', result%iterations
     387           41 :                   DO j = 1, nstates
     388           29 :                      WRITE (output_unit, '(T2,A,I0)') 'QUADRATIC_PSEUDOSPECTRUM| State: ', j
     389           29 :                      WRITE (output_unit, '(T2,A,ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Gap [hartree]: ', &
     390           58 :                         SQRT(result%eigenvalues(j))
     391           29 :                      WRITE (output_unit, '(T2,A,ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Energy residual [hartree]: ', &
     392           58 :                         result%errors(1, j)
     393           29 :                      IF (translation_analysis) THEN
     394           30 :                         DO i = 2, nobs
     395           17 :                            WRITE (output_unit, '(T2,A,I0,A,3ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Translation residual ', i - 1, &
     396           34 :                               ' full/projected/leakage: ', result%errors(i, j), result%projected_errors(i, j), result%leakage(i, j)
     397           17 :                           WRITE (output_unit, '(T2,A,I0,A,2ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Translation expectation ', i - 1, &
     398           47 :                               ' real/imag: ', result%complex_means(i, j)
     399              :                         END DO
     400           16 :                      ELSE IF (periodic_analysis) THEN
     401           14 :                         DO i = 1, ndim
     402           10 :                            WRITE (output_unit, '(T2,A,I1,A,ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Chord residual axis ', &
     403           40 :                               directions(i), ' [bohr]: ', radii(i)*SQRT(SUM(result%errors(2*i:2*i + 1, j)**2))
     404           10 :                            WRITE (output_unit, '(T2,A,I1,A,2ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Mean cos/sin axis ', &
     405           24 :                               directions(i), ': ', result%means(2*i:2*i + 1, j)
     406              :                         END DO
     407              :                      ELSE
     408           12 :                         WRITE (output_unit, '(T2,A,3ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Position residuals [bohr]: ', &
     409           24 :                            result%errors(2:4, j)
     410              :                      END IF
     411           29 :                      WRITE (output_unit, '(T2,A,ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Eigenpair residual [hartree^2]: ', &
     412           58 :                         result%residuals(j)
     413           29 :                      WRITE (output_unit, '(T2,A,ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Mean energy [hartree]: ', result%means(1, j)
     414           41 :                      IF (.NOT. periodic_analysis .AND. .NOT. translation_analysis) THEN
     415           12 :                         WRITE (output_unit, '(T2,A,3ES23.14)') 'QUADRATIC_PSEUDOSPECTRUM| Mean position [bohr]: ', &
     416           24 :                            result%means(2:4, j)
     417              :                      END IF
     418              :                   END DO
     419              :                END IF
     420           44 :                IF (iw > 0) THEN
     421           12 :                   IF (translation_analysis) THEN
     422           20 :                      WRITE (iw, '(A,3I8,A,5ES24.15)') '# Query ', ip, ie, ik, ' E/kx/ky/kz/scale ', energies(ie), point, kappas(ik)
     423              :                   ELSE
     424           28 :                      WRITE (iw, '(A,3I8,A,5ES24.15)') '# Query ', ip, ie, ik, ' E/x/y/z/kappa ', energies(ie), point, kappas(ik)
     425              :                   END IF
     426           41 :                   DO j = 1, nstates
     427           29 :                      WRITE (iw, '(A,I8,A,ES24.15)') '# State ', j, ' lambda [hartree^2] ', result%eigenvalues(j)
     428          579 :                      DO ao = 1, n
     429          567 :                         WRITE (iw, '(I10,2ES25.16)') ao, REAL(result%states(ao, j), dp), AIMAG(result%states(ao, j))
     430              :                      END DO
     431              :                   END DO
     432              :                END IF
     433              :             END DO
     434              :          END DO
     435              :       END DO
     436           16 :       CALL cp_print_key_finished_output(iw, logger, section, 'STATES')
     437           74 :       DO i = 1, nobs
     438           74 :          CALL localizer_dbcsr_release(operators(i))
     439              :       END DO
     440           16 :       CALL localizer_dbcsr_release(metric)
     441           16 :       CALL timestop(handle)
     442        42569 :    END SUBROUTINE qs_scf_post_quadratic
     443              : END MODULE qs_quadratic_pseudospectrum
        

Generated by: LCOV version 2.0-1