LCOV - code coverage report
Current view: top level - src - preconditioner.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:92574dc) Lines: 86.3 % 742 640
Test Date: 2026-09-24 01:27:39 Functions: 100.0 % 15 15

            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 computes preconditioners, and implements methods to apply them
      10              : !>      currently used in qs_ot
      11              : !> \par History
      12              : !>      - [UB] 2009-05-13 Adding stable approximate inverse (full and sparse)
      13              : !> \author Joost VandeVondele (09.2002)
      14              : ! **************************************************************************************************
      15              : MODULE preconditioner
      16              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      17              :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      18              :                                               cp_cfm_release,&
      19              :                                               cp_cfm_type,&
      20              :                                               cp_fm_to_cfm
      21              :    USE cp_control_types,                ONLY: dft_control_type
      22              :    USE cp_dbcsr_api,                    ONLY: dbcsr_get_info,&
      23              :                                               dbcsr_p_type,&
      24              :                                               dbcsr_release_p,&
      25              :                                               dbcsr_type
      26              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      27              :                                               cp_dbcsr_sm_fm_multiply
      28              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_uplo_to_full
      29              :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_decompose,&
      30              :                                               cp_fm_cholesky_invert
      31              :    USE cp_fm_diag,                      ONLY: choose_eigv_solver
      32              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      33              :                                               cp_fm_struct_release,&
      34              :                                               cp_fm_struct_type
      35              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      36              :                                               cp_fm_get_info,&
      37              :                                               cp_fm_release,&
      38              :                                               cp_fm_set_all,&
      39              :                                               cp_fm_to_fm,&
      40              :                                               cp_fm_type
      41              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      42              :                                               cp_logger_get_default_io_unit,&
      43              :                                               cp_logger_type
      44              :    USE input_constants,                 ONLY: &
      45              :         cholesky_reduce, ot_lattice_fft_auto, ot_lattice_fft_off, ot_lattice_fft_on, &
      46              :         ot_low_rank_base_lattice_fft, ot_low_rank_base_overlap, ot_precond_fermi_low_rank, &
      47              :         ot_precond_full_all, ot_precond_full_all_covariant, ot_precond_full_kinetic, &
      48              :         ot_precond_full_single, ot_precond_full_single_inverse, ot_precond_none, &
      49              :         ot_precond_s_inverse, ot_precond_solver_default, ot_precond_solver_inv_chol, &
      50              :         ot_precond_solver_update
      51              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      52              :                                               section_vals_type,&
      53              :                                               section_vals_val_get
      54              :    USE kinds,                           ONLY: default_string_length,&
      55              :                                               dp
      56              :    USE lattice_preconditioner_operator, ONLY: &
      57              :         build_lattice_inverse, build_lattice_inverse_from_blocks, build_lattice_local_correction, &
      58              :         lattice_fft_auto_max_cost_ratio, lattice_fft_auto_max_storage_ratio, &
      59              :         lattice_fft_auto_min_cells, lattice_fft_auto_select, lattice_fft_cost_ratio, &
      60              :         lattice_fft_storage_ratio, lattice_grid, lattice_local_cost_ratio, &
      61              :         lattice_local_storage_ratio
      62              :    USE low_rank_preconditioner_model,   ONLY: low_rank_inverse_weight,&
      63              :                                               low_rank_select_rank
      64              :    USE message_passing,                 ONLY: mp_para_env_type
      65              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      66              :    USE preconditioner_apply,            ONLY: apply_preconditioner_cfm_complex,&
      67              :                                               apply_preconditioner_dbcsr,&
      68              :                                               apply_preconditioner_dbcsr_complex,&
      69              :                                               apply_preconditioner_fm
      70              :    USE preconditioner_makes,            ONLY: make_complex_fermi_low_rank,&
      71              :                                               make_complex_full_all,&
      72              :                                               make_complex_full_all_covariant,&
      73              :                                               make_complex_full_kinetic,&
      74              :                                               make_complex_full_s_inverse,&
      75              :                                               make_complex_full_single,&
      76              :                                               make_complex_full_single_inverse,&
      77              :                                               make_preconditioner_matrix
      78              :    USE preconditioner_solvers,          ONLY: solve_preconditioner,&
      79              :                                               transfer_dbcsr_to_fm,&
      80              :                                               transfer_fm_to_dbcsr
      81              :    USE preconditioner_types,            ONLY: destroy_preconditioner,&
      82              :                                               init_preconditioner,&
      83              :                                               preconditioner_p_type,&
      84              :                                               preconditioner_type
      85              :    USE qs_environment_types,            ONLY: get_qs_env,&
      86              :                                               qs_environment_type
      87              :    USE qs_mo_methods,                   ONLY: calculate_subspace_eigenvalues
      88              :    USE qs_mo_types,                     ONLY: deallocate_mo_set,&
      89              :                                               duplicate_mo_set,&
      90              :                                               get_mo_set,&
      91              :                                               mo_set_type,&
      92              :                                               set_mo_set
      93              : #include "./base/base_uses.f90"
      94              : 
      95              :    IMPLICIT NONE
      96              : 
      97              :    PRIVATE
      98              : 
      99              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'preconditioner'
     100              :    REAL(KIND=dp), PARAMETER, PRIVATE    :: fermi_low_rank_gap_factor = 4.0_dp, &
     101              :                                            fermi_low_rank_degeneracy_tolerance = 1.0E-8_dp, &
     102              :                                            fermi_low_rank_min_window = 1.0_dp
     103              : 
     104              :    PUBLIC :: make_preconditioner, make_preconditioner_complex_fermi_low_rank, &
     105              :              make_preconditioner_complex_full_all, &
     106              :              make_preconditioner_complex_full_all_covariant, &
     107              :              make_preconditioner_complex_full_kinetic, &
     108              :              make_preconditioner_complex_full_s_inverse, &
     109              :              make_preconditioner_complex_full_single, &
     110              :              make_preconditioner_complex_full_single_inverse, restart_preconditioner, &
     111              :              dbcsr_pair_to_cfm
     112              :    PUBLIC :: apply_preconditioner, prepare_preconditioner
     113              : 
     114              : ! The public interface for apply preconditioner, the routines can be found in preconditioner_apply.F
     115              :    INTERFACE apply_preconditioner
     116              :       MODULE PROCEDURE apply_preconditioner_cfm_complex
     117              :       MODULE PROCEDURE apply_preconditioner_dbcsr
     118              :       MODULE PROCEDURE apply_preconditioner_dbcsr_complex
     119              :       MODULE PROCEDURE apply_preconditioner_fm
     120              :    END INTERFACE
     121              : 
     122              : ! **************************************************************************************************
     123              : 
     124              : CONTAINS
     125              : 
     126              : ! **************************************************************************************************
     127              : 
     128              : ! **************************************************************************************************
     129              : !> \brief Build the block-circulant inverse of a replicated-cell SPD operator.
     130              : !> \param preconditioner_env ...
     131              : !> \param operator_matrix ...
     132              : !> \param operator_name ...
     133              : !> \param rhs_count number of occupied orbital columns to precondition
     134              : ! **************************************************************************************************
     135           16 :    SUBROUTINE prepare_lattice_operator(preconditioner_env, operator_matrix, operator_name, rhs_count)
     136              : 
     137              :       TYPE(preconditioner_type)                          :: preconditioner_env
     138              :       TYPE(dbcsr_type), POINTER                          :: operator_matrix
     139              :       CHARACTER(LEN=*), INTENT(IN)                       :: operator_name
     140              :       INTEGER, INTENT(IN)                                :: rhs_count
     141              : 
     142              :       INTEGER :: alpha, beta, block_size, col_cell, delta_index, i, info, j, local_info, n, ncell, &
     143              :          ncol_local, nrow_local, output_unit, row_cell
     144           16 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: index_to_cell
     145              :       INTEGER, DIMENSION(3)                              :: delta
     146           16 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     147              :       LOGICAL                                            :: used_fft
     148              :       REAL(KIND=dp)                                      :: denominator, difference, numerator, value
     149           16 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: dense_operator, xkp
     150           16 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: blocks
     151              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     152           16 :          POINTER                                         :: local_data
     153              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     154              :       TYPE(cp_fm_type)                                   :: operator_fm, work
     155              :       TYPE(cp_logger_type), POINTER                      :: logger
     156              : 
     157            0 :       CPASSERT(ASSOCIATED(operator_matrix))
     158           16 :       CPASSERT(preconditioner_env%lattice_fft_mode /= ot_lattice_fft_off)
     159           16 :       preconditioner_env%lattice_fft_active = .FALSE.
     160           16 :       preconditioner_env%lattice_projection_error = 0.0_dp
     161           16 :       preconditioner_env%lattice_corrected_projection_error = 0.0_dp
     162           16 :       preconditioner_env%lattice_cost_ratio = 0.0_dp
     163           16 :       preconditioner_env%lattice_storage_ratio = 0.0_dp
     164              : 
     165           64 :       IF (ANY(preconditioner_env%lattice_dims <= 0)) CPABORT("Lattice dimensions must be positive")
     166              : 
     167           64 :       IF (preconditioner_env%lattice_fft_mode == ot_lattice_fft_auto .AND. &
     168              :           PRODUCT(preconditioner_env%lattice_dims) < lattice_fft_auto_min_cells) THEN
     169            0 :          IF (preconditioner_env%para_env%is_source()) THEN
     170            0 :             logger => cp_get_default_logger()
     171            0 :             output_unit = cp_logger_get_default_io_unit(logger)
     172            0 :             IF (output_unit > 0) THEN
     173              :                WRITE (output_unit, '(T2,A,A,A,I0,A,I0)') &
     174            0 :                   "OT| Lattice FFT AUTO kept the conventional ", TRIM(operator_name), &
     175            0 :                   " solver: ", PRODUCT(preconditioner_env%lattice_dims), &
     176            0 :                   " cells are fewer than ", lattice_fft_auto_min_cells
     177              :             END IF
     178              :          END IF
     179            0 :          RETURN
     180              :       END IF
     181              : 
     182           16 :       NULLIFY (fm_struct)
     183           16 :       CALL dbcsr_get_info(operator_matrix, nfullrows_total=n)
     184           64 :       ncell = PRODUCT(preconditioner_env%lattice_dims)
     185           16 :       IF (MODULO(n, ncell) /= 0) CPABORT("AO dimension does not match replicated cells")
     186           16 :       block_size = n/ncell
     187           16 :       preconditioner_env%lattice_block_size = block_size
     188              :       preconditioner_env%lattice_cost_ratio = lattice_fft_cost_ratio( &
     189              :                                               preconditioner_env%lattice_dims, block_size, rhs_count, &
     190              :                                               preconditioner_env%para_env%num_pe) + &
     191              :                                               lattice_local_cost_ratio( &
     192              :                                               preconditioner_env%lattice_dims, &
     193           16 :                                               preconditioner_env%lattice_local_cells)
     194              :       preconditioner_env%lattice_storage_ratio = lattice_fft_storage_ratio( &
     195              :                                                  preconditioner_env%lattice_dims, 1) + &
     196              :                                                  lattice_local_storage_ratio( &
     197              :                                                  preconditioner_env%lattice_dims, 1, &
     198           16 :                                                  preconditioner_env%lattice_local_cells)
     199           16 :       IF (preconditioner_env%lattice_fft_mode == ot_lattice_fft_auto .AND. &
     200              :           (preconditioner_env%lattice_cost_ratio > lattice_fft_auto_max_cost_ratio .OR. &
     201              :            preconditioner_env%lattice_storage_ratio > lattice_fft_auto_max_storage_ratio)) THEN
     202            2 :          IF (preconditioner_env%para_env%is_source()) THEN
     203            1 :             logger => cp_get_default_logger()
     204            1 :             output_unit = cp_logger_get_default_io_unit(logger)
     205            1 :             IF (output_unit > 0) THEN
     206              :                WRITE (output_unit, '(T2,A,A,A,F8.3,A,F8.3,A)') &
     207            1 :                   "OT| Lattice FFT AUTO kept the conventional ", TRIM(operator_name), &
     208            1 :                   " solver: estimated work ratio ", preconditioner_env%lattice_cost_ratio, &
     209            2 :                   " storage ratio ", preconditioner_env%lattice_storage_ratio, " selected: F"
     210              :             END IF
     211              :          END IF
     212            2 :          RETURN
     213              :       END IF
     214              :       CALL cp_fm_struct_create(fm_struct, nrow_global=n, ncol_global=n, &
     215              :                                context=preconditioner_env%ctxt, &
     216           14 :                                para_env=preconditioner_env%para_env)
     217           14 :       CALL cp_fm_create(operator_fm, fm_struct, name="lattice preconditioner operator")
     218           14 :       CALL cp_fm_struct_release(fm_struct)
     219           14 :       CALL cp_fm_set_all(operator_fm, alpha=0.0_dp, beta=0.0_dp)
     220           14 :       CALL copy_dbcsr_to_fm(operator_matrix, operator_fm)
     221           14 :       CALL cp_fm_create(work, operator_fm%matrix_struct, name="lattice operator work")
     222           14 :       CALL cp_fm_uplo_to_full(operator_fm, work)
     223           14 :       CALL cp_fm_release(work)
     224              :       CALL cp_fm_get_info(operator_fm, nrow_local=nrow_local, ncol_local=ncol_local, &
     225           14 :                           row_indices=row_indices, col_indices=col_indices, local_data=local_data)
     226           70 :       ALLOCATE (blocks(block_size, block_size, ncell), source=0.0_dp)
     227           70 :       ALLOCATE (index_to_cell(3, ncell), xkp(3, ncell))
     228           14 :       CALL lattice_grid(preconditioner_env%lattice_dims, index_to_cell, xkp)
     229           14 :       IF (preconditioner_env%lattice_local_cells > 0) THEN
     230            8 :          ALLOCATE (dense_operator(n, n), source=0.0_dp)
     231              :       END IF
     232           14 :       denominator = 0.0_dp
     233          338 :       DO j = 1, ncol_local
     234         7094 :          DO i = 1, nrow_local
     235         7080 :             IF (row_indices(i) <= col_indices(j)) THEN
     236         3459 :                value = local_data(i, j)
     237         3459 :                row_cell = (row_indices(i) - 1)/block_size + 1
     238         3459 :                col_cell = (col_indices(j) - 1)/block_size + 1
     239         3459 :                alpha = MODULO(row_indices(i) - 1, block_size) + 1
     240         3459 :                beta = MODULO(col_indices(j) - 1, block_size) + 1
     241              :                delta = MODULO(index_to_cell(:, row_cell) - index_to_cell(:, col_cell), &
     242        13836 :                               preconditioner_env%lattice_dims)
     243              :                delta_index = delta(1) + preconditioner_env%lattice_dims(1)*(delta(2) + &
     244         3459 :                                                                             preconditioner_env%lattice_dims(2)*delta(3)) + 1
     245              :                blocks(alpha, beta, delta_index) = blocks(alpha, beta, delta_index) + &
     246         3459 :                                                   value/REAL(ncell, KIND=dp)
     247         3459 :                denominator = denominator + value*value
     248         3459 :                IF (ALLOCATED(dense_operator)) THEN
     249           36 :                   dense_operator(row_indices(i), col_indices(j)) = value
     250              :                END IF
     251         3459 :                IF (row_indices(i) < col_indices(j)) THEN
     252              :                   delta = MODULO(index_to_cell(:, col_cell) - index_to_cell(:, row_cell), &
     253        13188 :                                  preconditioner_env%lattice_dims)
     254              :                   delta_index = delta(1) + preconditioner_env%lattice_dims(1)*(delta(2) + &
     255         3297 :                                                                                preconditioner_env%lattice_dims(2)*delta(3)) + 1
     256              :                   blocks(beta, alpha, delta_index) = blocks(beta, alpha, delta_index) + &
     257         3297 :                                                      value/REAL(ncell, KIND=dp)
     258         3297 :                   denominator = denominator + value*value
     259              :                END IF
     260              :             END IF
     261              :          END DO
     262              :       END DO
     263           14 :       CALL preconditioner_env%para_env%sum(blocks)
     264           14 :       numerator = 0.0_dp
     265          338 :       DO j = 1, ncol_local
     266         7094 :          DO i = 1, nrow_local
     267         7080 :             IF (row_indices(i) <= col_indices(j)) THEN
     268         3459 :                value = local_data(i, j)
     269         3459 :                row_cell = (row_indices(i) - 1)/block_size + 1
     270         3459 :                col_cell = (col_indices(j) - 1)/block_size + 1
     271         3459 :                alpha = MODULO(row_indices(i) - 1, block_size) + 1
     272         3459 :                beta = MODULO(col_indices(j) - 1, block_size) + 1
     273              :                delta = MODULO(index_to_cell(:, row_cell) - index_to_cell(:, col_cell), &
     274        13836 :                               preconditioner_env%lattice_dims)
     275              :                delta_index = delta(1) + preconditioner_env%lattice_dims(1)*(delta(2) + &
     276         3459 :                                                                             preconditioner_env%lattice_dims(2)*delta(3)) + 1
     277         3459 :                difference = value - blocks(alpha, beta, delta_index)
     278         3459 :                numerator = numerator + difference*difference
     279         3459 :                IF (row_indices(i) < col_indices(j)) THEN
     280              :                   delta = MODULO(index_to_cell(:, col_cell) - index_to_cell(:, row_cell), &
     281        13188 :                                  preconditioner_env%lattice_dims)
     282              :                   delta_index = delta(1) + preconditioner_env%lattice_dims(1)*(delta(2) + &
     283         3297 :                                                                                preconditioner_env%lattice_dims(2)*delta(3)) + 1
     284         3297 :                   difference = value - blocks(beta, alpha, delta_index)
     285         3297 :                   numerator = numerator + difference*difference
     286              :                END IF
     287              :             END IF
     288              :          END DO
     289              :       END DO
     290           14 :       CALL preconditioner_env%para_env%sum(numerator)
     291           14 :       CALL preconditioner_env%para_env%sum(denominator)
     292              :       preconditioner_env%lattice_projection_error = &
     293           14 :          SQRT(numerator/MAX(denominator, TINY(denominator)))
     294              :       CALL build_lattice_inverse_from_blocks( &
     295           14 :          blocks, preconditioner_env%lattice_dims, preconditioner_env%lattice_inverse_k, used_fft, info)
     296              :       preconditioner_env%lattice_corrected_projection_error = &
     297           14 :          preconditioner_env%lattice_projection_error
     298           14 :       IF (ALLOCATED(dense_operator)) THEN
     299            2 :          CALL preconditioner_env%para_env%sum(dense_operator)
     300           18 :          DO j = 1, n
     301           74 :             DO i = j + 1, n
     302           72 :                dense_operator(i, j) = dense_operator(j, i)
     303              :             END DO
     304              :          END DO
     305              :          CALL build_lattice_local_correction( &
     306              :             dense_operator, preconditioner_env%lattice_dims, &
     307              :             preconditioner_env%lattice_local_cells, &
     308              :             preconditioner_env%lattice_local_indices, &
     309              :             preconditioner_env%lattice_local_operator, &
     310              :             preconditioner_env%lattice_local_coarse_inverse, &
     311            2 :             preconditioner_env%lattice_corrected_projection_error, local_info)
     312            2 :          IF (local_info /= 0) THEN
     313            0 :             CPABORT("LATTICE_FFT local correction found a non-positive coarse operator")
     314              :          END IF
     315            2 :          DEALLOCATE (dense_operator)
     316              :       END IF
     317           14 :       CALL cp_fm_release(operator_fm)
     318           14 :       DEALLOCATE (blocks, index_to_cell, xkp)
     319           24 :       SELECT CASE (preconditioner_env%lattice_fft_mode)
     320              :       CASE (ot_lattice_fft_on)
     321           10 :          IF (info /= 0) THEN
     322            0 :             CPABORT("LATTICE_FFT found a non-positive Fourier block for "//TRIM(operator_name))
     323              :          END IF
     324           10 :          IF (.NOT. used_fft) THEN
     325            0 :             CPABORT("LATTICE_FFT could not initialize its FFT for "//TRIM(operator_name))
     326              :          END IF
     327           10 :          preconditioner_env%lattice_fft_active = .TRUE.
     328              :       CASE (ot_lattice_fft_auto)
     329              :          preconditioner_env%lattice_fft_active = lattice_fft_auto_select( &
     330              :                                                  preconditioner_env%lattice_dims, &
     331              :                                                  preconditioner_env%lattice_block_size, rhs_count, 1, &
     332              :                                                  preconditioner_env%para_env%num_pe, &
     333            4 :                                                  preconditioner_env%lattice_projection_error, used_fft, info)
     334              :       CASE DEFAULT
     335           14 :          CPABORT("Unknown LATTICE_FFT mode")
     336              :       END SELECT
     337              : 
     338           14 :       IF (.NOT. preconditioner_env%lattice_fft_active .AND. &
     339              :           ALLOCATED(preconditioner_env%lattice_inverse_k)) THEN
     340            2 :          DEALLOCATE (preconditioner_env%lattice_inverse_k)
     341              :       END IF
     342           14 :       IF (preconditioner_env%para_env%is_source()) THEN
     343            7 :          logger => cp_get_default_logger()
     344            7 :          output_unit = cp_logger_get_default_io_unit(logger)
     345            7 :          IF (output_unit > 0) THEN
     346              :             WRITE (output_unit, '(T2,A,A,A,3(I0,1X),A,I0)') &
     347            7 :                "OT| Lattice FFT ", TRIM(operator_name), " cells: ", &
     348           14 :                preconditioner_env%lattice_dims, "AO block: ", preconditioner_env%lattice_block_size
     349              :             WRITE (output_unit, '(T2,A,ES12.4,A,L1)') &
     350            7 :                "OT| Block-circulant projection error: ", &
     351            7 :                preconditioner_env%lattice_projection_error, &
     352           14 :                " selected: ", preconditioner_env%lattice_fft_active
     353            7 :             IF (preconditioner_env%lattice_local_cells > 0) THEN
     354              :                WRITE (output_unit, '(T2,A,I0,A,ES12.4)') &
     355            1 :                   "OT| Balanced local correction cells: ", &
     356            1 :                   preconditioner_env%lattice_local_cells, " residual error: ", &
     357            2 :                   preconditioner_env%lattice_corrected_projection_error
     358              :             END IF
     359              :             WRITE (output_unit, '(T2,A,F8.3,A,F8.3)') &
     360            7 :                "OT| Estimated lattice/dense work ratio: ", &
     361            7 :                preconditioner_env%lattice_cost_ratio, " storage ratio: ", &
     362           14 :                preconditioner_env%lattice_storage_ratio
     363              :          END IF
     364              :       END IF
     365              : 
     366           90 :    END SUBROUTINE prepare_lattice_operator
     367              : 
     368              : ! **************************************************************************************************
     369              : !> \brief Build state-dependent block-circulant inverses for rotation-covariant FULL_ALL.
     370              : !> \param preconditioner_env ...
     371              : !> \param matrix_s overlap matrix
     372              : !> \param operator_name ...
     373              : ! **************************************************************************************************
     374            2 :    SUBROUTINE prepare_lattice_state_operator(preconditioner_env, matrix_s, operator_name)
     375              : 
     376              :       TYPE(preconditioner_type)                          :: preconditioner_env
     377              :       TYPE(dbcsr_type), POINTER                          :: matrix_s
     378              :       CHARACTER(LEN=*), INTENT(IN)                       :: operator_name
     379              : 
     380            2 :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)  :: inverse_k
     381              :       INTEGER                                            :: i, info, istate, j, local_info, &
     382              :                                                             local_rank, n, ncell, ncol_local, &
     383              :                                                             nrow_local, nstate, output_unit
     384            2 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: local_indices
     385            2 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     386              :       LOGICAL                                            :: all_selected, selected, used_fft
     387              :       REAL(KIND=dp)                                      :: corrected_projection_error, &
     388              :                                                             projection_error
     389            2 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: dense_operator, dense_sv, dense_vectors, &
     390            2 :                                                             local_coarse_inverse, local_operator, &
     391            2 :                                                             scaled_sv
     392              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     393            2 :          POINTER                                         :: local_data
     394              :       TYPE(cp_fm_type)                                   :: sv_fm
     395              :       TYPE(cp_logger_type), POINTER                      :: logger
     396              : 
     397            0 :       CPASSERT(ASSOCIATED(matrix_s))
     398            2 :       CPASSERT(ASSOCIATED(preconditioner_env%fm))
     399            2 :       CPASSERT(ASSOCIATED(preconditioner_env%full_evals))
     400            2 :       CPASSERT(ASSOCIATED(preconditioner_env%occ_evals))
     401            2 :       CPASSERT(preconditioner_env%lattice_fft_mode /= ot_lattice_fft_off)
     402              : 
     403            2 :       preconditioner_env%lattice_fft_active = .FALSE.
     404            2 :       preconditioner_env%lattice_projection_error = 0.0_dp
     405            2 :       preconditioner_env%lattice_corrected_projection_error = 0.0_dp
     406            2 :       preconditioner_env%lattice_cost_ratio = 0.0_dp
     407            2 :       preconditioner_env%lattice_storage_ratio = 0.0_dp
     408            2 :       IF (ALLOCATED(preconditioner_env%lattice_state_inverse_k)) THEN
     409            0 :          DEALLOCATE (preconditioner_env%lattice_state_inverse_k)
     410              :       END IF
     411            2 :       IF (ALLOCATED(preconditioner_env%lattice_occ_vectors)) THEN
     412            0 :          DEALLOCATE (preconditioner_env%lattice_occ_vectors)
     413              :       END IF
     414            2 :       IF (ALLOCATED(preconditioner_env%lattice_occ_dual)) THEN
     415            0 :          DEALLOCATE (preconditioner_env%lattice_occ_dual)
     416              :       END IF
     417            2 :       IF (ALLOCATED(preconditioner_env%lattice_local_indices)) THEN
     418            0 :          DEALLOCATE (preconditioner_env%lattice_local_indices)
     419              :       END IF
     420            2 :       IF (ALLOCATED(preconditioner_env%lattice_local_operator)) THEN
     421            0 :          DEALLOCATE (preconditioner_env%lattice_local_operator)
     422              :       END IF
     423            2 :       IF (ALLOCATED(preconditioner_env%lattice_local_coarse_inverse)) THEN
     424            0 :          DEALLOCATE (preconditioner_env%lattice_local_coarse_inverse)
     425              :       END IF
     426            2 :       IF (ALLOCATED(preconditioner_env%lattice_state_local_indices)) THEN
     427            0 :          DEALLOCATE (preconditioner_env%lattice_state_local_indices)
     428              :       END IF
     429            2 :       IF (ALLOCATED(preconditioner_env%lattice_state_local_operator)) THEN
     430            0 :          DEALLOCATE (preconditioner_env%lattice_state_local_operator)
     431              :       END IF
     432            2 :       IF (ALLOCATED(preconditioner_env%lattice_state_local_coarse_inverse)) THEN
     433            0 :          DEALLOCATE (preconditioner_env%lattice_state_local_coarse_inverse)
     434              :       END IF
     435            8 :       IF (ANY(preconditioner_env%lattice_dims <= 0)) CPABORT("Lattice dimensions must be positive")
     436            8 :       IF (preconditioner_env%lattice_fft_mode == ot_lattice_fft_auto .AND. &
     437              :           PRODUCT(preconditioner_env%lattice_dims) < lattice_fft_auto_min_cells) THEN
     438            0 :          IF (preconditioner_env%para_env%is_source()) THEN
     439            0 :             logger => cp_get_default_logger()
     440            0 :             output_unit = cp_logger_get_default_io_unit(logger)
     441            0 :             IF (output_unit > 0) THEN
     442              :                WRITE (output_unit, '(T2,A,A,A,I0,A,I0)') &
     443            0 :                   "OT| Lattice FFT AUTO kept the conventional ", TRIM(operator_name), &
     444            0 :                   " solver: ", PRODUCT(preconditioner_env%lattice_dims), &
     445            0 :                   " cells are fewer than ", lattice_fft_auto_min_cells
     446              :             END IF
     447              :          END IF
     448            0 :          RETURN
     449              :       END IF
     450              : 
     451            2 :       CALL cp_fm_get_info(preconditioner_env%fm, nrow_global=n, ncol_global=j)
     452            2 :       CPASSERT(j == n .AND. SIZE(preconditioner_env%full_evals) == n)
     453            2 :       nstate = SIZE(preconditioner_env%occ_evals)
     454            2 :       CPASSERT(nstate > 0)
     455            8 :       ncell = PRODUCT(preconditioner_env%lattice_dims)
     456            2 :       IF (MODULO(n, ncell) /= 0) CPABORT("AO dimension does not match replicated cells")
     457            2 :       preconditioner_env%lattice_block_size = n/ncell
     458              :       preconditioner_env%lattice_cost_ratio = lattice_fft_cost_ratio( &
     459              :                                               preconditioner_env%lattice_dims, &
     460              :                                               preconditioner_env%lattice_block_size, nstate, &
     461            2 :                                               preconditioner_env%para_env%num_pe)
     462              :       preconditioner_env%lattice_storage_ratio = lattice_fft_storage_ratio( &
     463            2 :                                                  preconditioner_env%lattice_dims, nstate)
     464              :       preconditioner_env%lattice_cost_ratio = preconditioner_env%lattice_cost_ratio + &
     465              :                                               lattice_local_cost_ratio( &
     466              :                                               preconditioner_env%lattice_dims, &
     467            2 :                                               preconditioner_env%lattice_local_cells)
     468              :       preconditioner_env%lattice_storage_ratio = preconditioner_env%lattice_storage_ratio + &
     469              :                                                  lattice_local_storage_ratio( &
     470              :                                                  preconditioner_env%lattice_dims, nstate, &
     471            2 :                                                  preconditioner_env%lattice_local_cells)
     472            2 :       IF (preconditioner_env%lattice_fft_mode == ot_lattice_fft_auto .AND. &
     473              :           (preconditioner_env%lattice_cost_ratio > lattice_fft_auto_max_cost_ratio .OR. &
     474              :            preconditioner_env%lattice_storage_ratio > lattice_fft_auto_max_storage_ratio)) THEN
     475            0 :          IF (preconditioner_env%para_env%is_source()) THEN
     476            0 :             logger => cp_get_default_logger()
     477            0 :             output_unit = cp_logger_get_default_io_unit(logger)
     478            0 :             IF (output_unit > 0) THEN
     479              :                WRITE (output_unit, '(T2,A,A,A,F8.3,A,F8.3,A)') &
     480            0 :                   "OT| Lattice FFT AUTO kept the conventional ", TRIM(operator_name), &
     481            0 :                   " solver: estimated work ratio ", preconditioner_env%lattice_cost_ratio, &
     482            0 :                   " storage ratio ", preconditioner_env%lattice_storage_ratio, " selected: F"
     483              :             END IF
     484              :          END IF
     485            0 :          RETURN
     486              :       END IF
     487            2 :       IF (preconditioner_env%lattice_local_cells > 0) THEN
     488              :          local_rank = preconditioner_env%lattice_local_cells* &
     489            2 :                       preconditioner_env%lattice_block_size
     490            0 :          ALLOCATE (preconditioner_env%lattice_state_local_indices(local_rank, nstate), &
     491            0 :                    preconditioner_env%lattice_state_local_operator(n, local_rank, nstate), &
     492           24 :                    preconditioner_env%lattice_state_local_coarse_inverse(local_rank, local_rank, nstate))
     493              :       END IF
     494            2 :       CALL cp_fm_create(sv_fm, preconditioner_env%fm%matrix_struct, name="lattice FULL_ALL S V")
     495            2 :       CALL cp_dbcsr_sm_fm_multiply(matrix_s, preconditioner_env%fm, sv_fm, n)
     496              :       CALL cp_fm_get_info(sv_fm, nrow_local=nrow_local, ncol_local=ncol_local, &
     497            2 :                           row_indices=row_indices, col_indices=col_indices, local_data=local_data)
     498           14 :       ALLOCATE (dense_sv(n, n), dense_vectors(n, nstate), source=0.0_dp)
     499           10 :       DO j = 1, ncol_local
     500           26 :          DO i = 1, nrow_local
     501           24 :             dense_sv(row_indices(i), col_indices(j)) = local_data(i, j)
     502              :          END DO
     503              :       END DO
     504            2 :       CALL preconditioner_env%para_env%sum(dense_sv)
     505            2 :       CALL cp_fm_release(sv_fm)
     506              : 
     507              :       CALL cp_fm_get_info(preconditioner_env%fm, nrow_local=nrow_local, ncol_local=ncol_local, &
     508            2 :                           row_indices=row_indices, col_indices=col_indices, local_data=local_data)
     509           10 :       DO j = 1, ncol_local
     510            8 :          IF (col_indices(j) > nstate) CYCLE
     511           14 :          DO i = 1, nrow_local
     512           16 :             dense_vectors(row_indices(i), col_indices(j)) = local_data(i, j)
     513              :          END DO
     514              :       END DO
     515            2 :       CALL preconditioner_env%para_env%sum(dense_vectors)
     516            0 :       ALLOCATE (preconditioner_env%lattice_occ_vectors(n, nstate), &
     517           12 :                 preconditioner_env%lattice_occ_dual(n, nstate))
     518           22 :       preconditioner_env%lattice_occ_vectors(:, :) = dense_vectors
     519           22 :       preconditioner_env%lattice_occ_dual(:, :) = dense_sv(:, 1:nstate)
     520              : 
     521           10 :       ALLOCATE (dense_operator(n, n), scaled_sv(n, n))
     522            2 :       all_selected = .TRUE.
     523            6 :       DO istate = 1, nstate
     524           84 :          scaled_sv(:, :) = dense_sv
     525           20 :          DO j = 1, n
     526              :             scaled_sv(:, j) = scaled_sv(:, j)*MAX( &
     527              :                               preconditioner_env%energy_gap, &
     528           84 :                               preconditioner_env%full_evals(j) - preconditioner_env%occ_evals(istate))
     529              :          END DO
     530          596 :          dense_operator(:, :) = MATMUL(scaled_sv, TRANSPOSE(dense_sv))
     531              :          CALL build_lattice_inverse(dense_operator, preconditioner_env%lattice_dims, inverse_k, &
     532            4 :                                     projection_error, used_fft, info)
     533              :          preconditioner_env%lattice_projection_error = &
     534            4 :             MAX(preconditioner_env%lattice_projection_error, projection_error)
     535            4 :          corrected_projection_error = projection_error
     536            4 :          IF (preconditioner_env%lattice_local_cells > 0) THEN
     537              :             CALL build_lattice_local_correction( &
     538              :                dense_operator, preconditioner_env%lattice_dims, &
     539              :                preconditioner_env%lattice_local_cells, local_indices, &
     540            4 :                local_operator, local_coarse_inverse, corrected_projection_error, local_info)
     541            4 :             IF (local_info /= 0) THEN
     542            0 :                CPABORT("LATTICE_FFT local correction found a non-positive coarse operator")
     543              :             END IF
     544           12 :             preconditioner_env%lattice_state_local_indices(:, istate) = local_indices
     545           44 :             preconditioner_env%lattice_state_local_operator(:, :, istate) = local_operator
     546           28 :             preconditioner_env%lattice_state_local_coarse_inverse(:, :, istate) = local_coarse_inverse
     547            4 :             DEALLOCATE (local_coarse_inverse, local_indices, local_operator)
     548              :          END IF
     549              :          preconditioner_env%lattice_corrected_projection_error = &
     550            4 :             MAX(preconditioner_env%lattice_corrected_projection_error, corrected_projection_error)
     551              :          selected = lattice_fft_auto_select(preconditioner_env%lattice_dims, &
     552              :                                             preconditioner_env%lattice_block_size, nstate, nstate, &
     553            4 :                                             preconditioner_env%para_env%num_pe, projection_error, used_fft, info)
     554            4 :          IF (preconditioner_env%lattice_fft_mode == ot_lattice_fft_on) THEN
     555            4 :             IF (info /= 0) THEN
     556            0 :                CPABORT("LATTICE_FFT found a non-positive Fourier block for "//TRIM(operator_name))
     557              :             END IF
     558            4 :             IF (.NOT. used_fft) THEN
     559            0 :                CPABORT("LATTICE_FFT could not initialize its FFT for "//TRIM(operator_name))
     560              :             END IF
     561              :          ELSE
     562            0 :             all_selected = all_selected .AND. selected
     563              :          END IF
     564            4 :          IF (.NOT. ALLOCATED(preconditioner_env%lattice_state_inverse_k)) THEN
     565            0 :             ALLOCATE (preconditioner_env%lattice_state_inverse_k( &
     566           12 :                       SIZE(inverse_k, 1), SIZE(inverse_k, 2), SIZE(inverse_k, 3), nstate))
     567              :          END IF
     568            4 :          IF (info == 0 .AND. used_fft) THEN
     569           60 :             preconditioner_env%lattice_state_inverse_k(:, :, :, istate) = inverse_k
     570              :          END IF
     571            6 :          DEALLOCATE (inverse_k)
     572              :       END DO
     573              : 
     574              :       preconditioner_env%lattice_fft_active = &
     575            2 :          preconditioner_env%lattice_fft_mode == ot_lattice_fft_on .OR. all_selected
     576            2 :       IF (.NOT. preconditioner_env%lattice_fft_active .AND. &
     577              :           ALLOCATED(preconditioner_env%lattice_state_inverse_k)) THEN
     578            0 :          DEALLOCATE (preconditioner_env%lattice_state_inverse_k)
     579              :       END IF
     580            2 :       IF (.NOT. preconditioner_env%lattice_fft_active) THEN
     581            0 :          DEALLOCATE (preconditioner_env%lattice_occ_vectors, &
     582            0 :                      preconditioner_env%lattice_occ_dual)
     583            0 :          IF (ALLOCATED(preconditioner_env%lattice_state_local_indices)) THEN
     584              :             DEALLOCATE (preconditioner_env%lattice_state_local_indices, &
     585            0 :                         preconditioner_env%lattice_state_local_operator, &
     586            0 :                         preconditioner_env%lattice_state_local_coarse_inverse)
     587              :          END IF
     588              :       END IF
     589            2 :       IF (preconditioner_env%para_env%is_source()) THEN
     590            1 :          logger => cp_get_default_logger()
     591            1 :          output_unit = cp_logger_get_default_io_unit(logger)
     592            1 :          IF (output_unit > 0) THEN
     593              :             WRITE (output_unit, '(T2,A,A,A,3(I0,1X),A,I0,A,I0)') &
     594            1 :                "OT| Lattice FFT ", TRIM(operator_name), " cells: ", &
     595            1 :                preconditioner_env%lattice_dims, "AO block: ", &
     596            2 :                preconditioner_env%lattice_block_size, " states: ", nstate
     597              :             WRITE (output_unit, '(T2,A,ES12.4,A,L1)') &
     598            1 :                "OT| Maximum block-circulant projection error: ", &
     599            1 :                preconditioner_env%lattice_projection_error, &
     600            2 :                " selected: ", preconditioner_env%lattice_fft_active
     601            1 :             IF (preconditioner_env%lattice_local_cells > 0) THEN
     602              :                WRITE (output_unit, '(T2,A,I0,A,ES12.4)') &
     603            1 :                   "OT| Balanced local correction cells/state: ", &
     604            1 :                   preconditioner_env%lattice_local_cells, " maximum residual error: ", &
     605            2 :                   preconditioner_env%lattice_corrected_projection_error
     606              :             END IF
     607              :             WRITE (output_unit, '(T2,A,F8.3,A,F8.3)') &
     608            1 :                "OT| Estimated lattice/dense work ratio: ", &
     609            1 :                preconditioner_env%lattice_cost_ratio, " storage ratio: ", &
     610            2 :                preconditioner_env%lattice_storage_ratio
     611              :          END IF
     612              :       END IF
     613              : 
     614            2 :       DEALLOCATE (dense_operator, dense_sv, dense_vectors, scaled_sv)
     615              : 
     616           12 :    END SUBROUTINE prepare_lattice_state_operator
     617              : 
     618              : ! **************************************************************************************************
     619              : !> \brief Build the overlap-inverse base of the bounded low-rank spectral preconditioner.
     620              : !> \param preconditioner_env ...
     621              : !> \param matrix_s ...
     622              : ! **************************************************************************************************
     623            6 :    SUBROUTINE prepare_low_rank_base(preconditioner_env, matrix_s)
     624              : 
     625              :       TYPE(preconditioner_type)                          :: preconditioner_env
     626              :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: matrix_s
     627              : 
     628              :       INTEGER                                            :: info
     629              :       TYPE(cp_fm_type)                                   :: work
     630              : 
     631            0 :       CPASSERT(ASSOCIATED(preconditioner_env%fm))
     632            6 :       CPASSERT(.NOT. ASSOCIATED(preconditioner_env%base_fm))
     633              : 
     634            6 :       IF (preconditioner_env%lattice_fft_mode /= ot_lattice_fft_off) THEN
     635            2 :          IF (.NOT. PRESENT(matrix_s)) THEN
     636            0 :             CPABORT("LATTICE_FFT requires a non-unit overlap metric for FERMI_LOW_RANK")
     637              :          END IF
     638            2 :          CPASSERT(ASSOCIATED(matrix_s))
     639              :          CALL prepare_lattice_operator(preconditioner_env, matrix_s, "FERMI_LOW_RANK overlap", &
     640            2 :                                        SIZE(preconditioner_env%occ_evals))
     641            2 :          IF (preconditioner_env%lattice_fft_active) THEN
     642            2 :             preconditioner_env%low_rank_base = ot_low_rank_base_lattice_fft
     643            2 :             RETURN
     644              :          END IF
     645            0 :          preconditioner_env%low_rank_base = ot_low_rank_base_overlap
     646              :       END IF
     647              : 
     648            4 :       IF (preconditioner_env%low_rank_base /= ot_low_rank_base_overlap) THEN
     649            0 :          CPABORT("Unknown FERMI_LOW_RANK base operator")
     650              :       END IF
     651            4 :       ALLOCATE (preconditioner_env%base_fm)
     652              :       CALL cp_fm_create(preconditioner_env%base_fm, preconditioner_env%fm%matrix_struct, &
     653            4 :                         name="FERMI_LOW_RANK overlap inverse")
     654              : 
     655            4 :       IF (PRESENT(matrix_s)) THEN
     656            4 :          CPASSERT(ASSOCIATED(matrix_s))
     657            4 :          CALL copy_dbcsr_to_fm(matrix_s, preconditioner_env%base_fm)
     658            4 :          CALL cp_fm_cholesky_decompose(preconditioner_env%base_fm, info_out=info)
     659            4 :          IF (info /= 0) CPABORT("FERMI_LOW_RANK requires a positive-definite overlap matrix")
     660            4 :          CALL cp_fm_cholesky_invert(preconditioner_env%base_fm)
     661            4 :          CALL cp_fm_create(work, preconditioner_env%base_fm%matrix_struct, name="low-rank base work")
     662            4 :          CALL cp_fm_uplo_to_full(preconditioner_env%base_fm, work)
     663            4 :          CALL cp_fm_release(work)
     664              :       ELSE
     665            0 :          CALL cp_fm_set_all(preconditioner_env%base_fm, alpha=0.0_dp, beta=1.0_dp)
     666              :       END IF
     667              : 
     668            6 :    END SUBROUTINE prepare_low_rank_base
     669              : 
     670              : ! **************************************************************************************************
     671              : 
     672              : ! creates a preconditioner for the system (H-energy_homo S)
     673              : ! this preconditioner is (must be) symmetric positive definite.
     674              : ! currently uses a atom-block-diagonal form
     675              : ! each block will be  ....
     676              : ! might overwrite matrix_h, matrix_t
     677              : 
     678              : ! **************************************************************************************************
     679              : !> \brief ...
     680              : !> \param preconditioner_env ...
     681              : !> \param precon_type ...
     682              : !> \param solver_type ...
     683              : !> \param matrix_h ...
     684              : !> \param matrix_s ...
     685              : !> \param matrix_t ...
     686              : !> \param mo_set ...
     687              : !> \param energy_gap ...
     688              : !> \param convert_precond_to_dbcsr ...
     689              : !> \param chol_type ...
     690              : !> \par History
     691              : !>      09.2014 removed some unused or unfinished methods
     692              : !>              removed sparse preconditioners and the
     693              : !>              sparse approximate inverse at rev 14341 [Florian Schiffmann]
     694              : ! **************************************************************************************************
     695         9940 :    SUBROUTINE make_preconditioner(preconditioner_env, precon_type, solver_type, matrix_h, matrix_s, &
     696              :                                   matrix_t, mo_set, energy_gap, convert_precond_to_dbcsr, chol_type)
     697              : 
     698              :       TYPE(preconditioner_type)                          :: preconditioner_env
     699              :       INTEGER, INTENT(IN)                                :: precon_type, solver_type
     700              :       TYPE(dbcsr_type), POINTER                          :: matrix_h
     701              :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: matrix_s, matrix_t
     702              :       TYPE(mo_set_type), INTENT(IN)                      :: mo_set
     703              :       REAL(KIND=dp)                                      :: energy_gap
     704              :       LOGICAL, INTENT(IN), OPTIONAL                      :: convert_precond_to_dbcsr
     705              :       INTEGER, INTENT(IN), OPTIONAL                      :: chol_type
     706              : 
     707              :       CHARACTER(len=*), PARAMETER :: routineN = 'make_preconditioner'
     708              : 
     709              :       INTEGER                                            :: handle, k, max_rank, my_solver_type, &
     710              :                                                             nao, nhomo, output_unit
     711              :       LOGICAL                                            :: my_convert_precond_to_dbcsr, &
     712              :                                                             needs_full_spectrum, needs_homo, &
     713              :                                                             use_mo_coeff_b
     714              :       REAL(KIND=dp)                                      :: energy_homo
     715         9940 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvalues_ot
     716              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     717              :       TYPE(cp_fm_type)                                   :: mo_occ
     718              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     719              :       TYPE(cp_logger_type), POINTER                      :: logger
     720              :       TYPE(dbcsr_type), POINTER                          :: mo_coeff_b
     721              : 
     722         9940 :       CALL timeset(routineN, handle)
     723              : 
     724         9940 :       CALL get_mo_set(mo_set=mo_set, mo_coeff=mo_coeff, mo_coeff_b=mo_coeff_b, homo=nhomo)
     725         9940 :       use_mo_coeff_b = mo_set%use_mo_coeff_b
     726         9940 :       CALL cp_fm_get_info(mo_coeff, ncol_global=k, nrow_global=nao)
     727              : 
     728              :       ! Starting some matrix mess, check where to store the result in preconditioner_env, fm or dbcsr_matrix
     729         9940 :       my_convert_precond_to_dbcsr = .FALSE.
     730         9940 :       IF (PRESENT(convert_precond_to_dbcsr)) my_convert_precond_to_dbcsr = convert_precond_to_dbcsr
     731         9940 :       IF (precon_type == ot_precond_fermi_low_rank .AND. &
     732              :           preconditioner_env%low_rank_base == ot_low_rank_base_lattice_fft) THEN
     733              :          ! The FFT base is an operator rather than a stored DBCSR matrix. Keep the
     734              :          ! complementary vectors in their distributed full-matrix representation.
     735            0 :          my_convert_precond_to_dbcsr = .FALSE.
     736              :       END IF
     737              : 
     738              :       ! Thanks to the mess with the matrices we need to make sure in this case that the
     739              :       ! Previous inverse is properly stored as a sparse matrix, fm gets deallocated here
     740              :       ! if it wasn't anyway
     741         9940 :       IF (preconditioner_env%solver == ot_precond_solver_update) THEN
     742            4 :          CALL transfer_fm_to_dbcsr(preconditioner_env%fm, preconditioner_env%dbcsr_matrix, matrix_h)
     743              :       END IF
     744              : 
     745         9940 :       needs_full_spectrum = .FALSE.
     746         9940 :       needs_homo = .FALSE.
     747              : 
     748         3784 :       SELECT CASE (precon_type)
     749              :       CASE (ot_precond_full_all, ot_precond_fermi_low_rank, ot_precond_full_all_covariant)
     750         3784 :          needs_full_spectrum = .TRUE.
     751              :          ! both of them need the coefficients as fm's, more matrix mess
     752         3784 :          IF (use_mo_coeff_b) THEN
     753         3472 :             CALL copy_dbcsr_to_fm(mo_coeff_b, mo_coeff)
     754              :          END IF
     755              :       CASE (ot_precond_full_single)
     756           38 :          needs_homo = .TRUE.
     757              :          ! XXXX to be removed if homo estimate only is implemented
     758           38 :          needs_full_spectrum = .TRUE.
     759              :       CASE (ot_precond_full_kinetic, ot_precond_s_inverse, ot_precond_full_single_inverse)
     760              :          ! these should be happy without an estimate for the homo energy
     761              :          ! preconditioning can  not depend on an absolute eigenvalue, only on eigenvalue differences
     762              :       CASE DEFAULT
     763         9940 :          CPABORT("The preconditioner is unknown ...")
     764              :       END SELECT
     765              : 
     766        29532 :       ALLOCATE (eigenvalues_ot(k))
     767         9940 :       energy_homo = 0.0_dp
     768         9940 :       IF (needs_full_spectrum) THEN
     769              :          ! XXXXXXXXXXXXXXXX do not touch the initial MOs, could be harmful for either
     770              :          !                  the case of non-equivalent MOs but also for the derivate
     771              :          ! we could already have all eigenvalues e.g. full_all and we could skip this
     772              :          ! to be optimised later.
     773              :          ! one flaw is that not all SCF methods (i.e. that go over mo_derivs directly)
     774              :          ! have a 'valid' matrix_h... (we even don't know what evals are in that case)
     775         3822 :          IF (use_mo_coeff_b) THEN
     776              :             CALL calculate_subspace_eigenvalues(mo_coeff_b, matrix_h, &
     777              :                                                 eigenvalues_ot, do_rotation=.FALSE., &
     778              :                                                 para_env=mo_coeff%matrix_struct%para_env, &
     779         3502 :                                                 blacs_env=mo_coeff%matrix_struct%context)
     780              :          ELSE
     781              :             CALL calculate_subspace_eigenvalues(mo_coeff, matrix_h, &
     782          320 :                                                 eigenvalues_ot, do_rotation=.FALSE.)
     783              :          END IF
     784         3822 :          IF (k > 0) THEN
     785         3712 :             CPASSERT(nhomo > 0 .AND. nhomo <= k)
     786         3712 :             energy_homo = eigenvalues_ot(nhomo)
     787              :          END IF
     788              :       ELSE
     789         6118 :          IF (needs_homo) THEN
     790            0 :             CPABORT("Not yet implemented")
     791              :          END IF
     792              :       END IF
     793              : 
     794              :       ! After all bits and pieces of checking and initialization, here comes the
     795              :       ! part where the preconditioner matrix gets created and solved.
     796              :       ! This will give the matrices for later use
     797         9940 :       my_solver_type = solver_type
     798         9940 :       preconditioner_env%in_use = precon_type
     799         9940 :       preconditioner_env%cholesky_use = cholesky_reduce
     800         9940 :       IF (PRESENT(chol_type)) preconditioner_env%cholesky_use = chol_type
     801              :       preconditioner_env%in_use = precon_type
     802         9940 :       preconditioner_env%lattice_fft_active = .FALSE.
     803         9940 :       preconditioner_env%lattice_corrected_projection_error = 0.0_dp
     804         9940 :       IF (ALLOCATED(preconditioner_env%lattice_inverse_k)) THEN
     805            0 :          DEALLOCATE (preconditioner_env%lattice_inverse_k)
     806              :       END IF
     807         9940 :       IF (ALLOCATED(preconditioner_env%lattice_state_inverse_k)) THEN
     808            0 :          DEALLOCATE (preconditioner_env%lattice_state_inverse_k)
     809              :       END IF
     810         9940 :       IF (ALLOCATED(preconditioner_env%lattice_occ_vectors)) THEN
     811            0 :          DEALLOCATE (preconditioner_env%lattice_occ_vectors)
     812              :       END IF
     813         9940 :       IF (ALLOCATED(preconditioner_env%lattice_occ_dual)) THEN
     814            0 :          DEALLOCATE (preconditioner_env%lattice_occ_dual)
     815              :       END IF
     816         9940 :       IF (ALLOCATED(preconditioner_env%lattice_local_indices)) THEN
     817            0 :          DEALLOCATE (preconditioner_env%lattice_local_indices)
     818              :       END IF
     819         9940 :       IF (ALLOCATED(preconditioner_env%lattice_local_operator)) THEN
     820            0 :          DEALLOCATE (preconditioner_env%lattice_local_operator)
     821              :       END IF
     822         9940 :       IF (ALLOCATED(preconditioner_env%lattice_local_coarse_inverse)) THEN
     823            0 :          DEALLOCATE (preconditioner_env%lattice_local_coarse_inverse)
     824              :       END IF
     825         9940 :       IF (ALLOCATED(preconditioner_env%lattice_state_local_indices)) THEN
     826            0 :          DEALLOCATE (preconditioner_env%lattice_state_local_indices)
     827              :       END IF
     828         9940 :       IF (ALLOCATED(preconditioner_env%lattice_state_local_operator)) THEN
     829            0 :          DEALLOCATE (preconditioner_env%lattice_state_local_operator)
     830              :       END IF
     831         9940 :       IF (ALLOCATED(preconditioner_env%lattice_state_local_coarse_inverse)) THEN
     832            0 :          DEALLOCATE (preconditioner_env%lattice_state_local_coarse_inverse)
     833              :       END IF
     834         9940 :       IF (nhomo == k) THEN
     835              :          CALL make_preconditioner_matrix(preconditioner_env, matrix_h, matrix_s, matrix_t, mo_coeff, &
     836         9852 :                                          energy_homo, eigenvalues_ot, energy_gap, my_solver_type)
     837              :       ELSE
     838              :          CALL cp_fm_struct_create(fm_struct, nrow_global=nao, ncol_global=nhomo, &
     839              :                                   context=preconditioner_env%ctxt, &
     840           88 :                                   para_env=preconditioner_env%para_env)
     841           88 :          CALL cp_fm_create(mo_occ, fm_struct)
     842           88 :          CALL cp_fm_to_fm(mo_coeff, mo_occ, nhomo)
     843           88 :          CALL cp_fm_struct_release(fm_struct)
     844              :          !
     845              :          CALL make_preconditioner_matrix(preconditioner_env, matrix_h, matrix_s, matrix_t, mo_occ, &
     846           88 :                                          energy_homo, eigenvalues_ot(1:nhomo), energy_gap, my_solver_type)
     847              :          !
     848           88 :          CALL cp_fm_release(mo_occ)
     849              :       END IF
     850              : 
     851         9940 :       IF (preconditioner_env%lattice_fft_mode /= ot_lattice_fft_off) THEN
     852            8 :          SELECT CASE (precon_type)
     853              :          CASE (ot_precond_full_kinetic)
     854            8 :             CPASSERT(ASSOCIATED(preconditioner_env%sparse_matrix))
     855              :             CALL prepare_lattice_operator(preconditioner_env, preconditioner_env%sparse_matrix, &
     856            8 :                                           "FULL_KINETIC", nhomo)
     857              :          CASE (ot_precond_full_single_inverse)
     858            2 :             CPASSERT(ASSOCIATED(preconditioner_env%sparse_matrix))
     859              :             CALL prepare_lattice_operator(preconditioner_env, preconditioner_env%sparse_matrix, &
     860            2 :                                           "FULL_SINGLE_INVERSE", nhomo)
     861              :          CASE (ot_precond_s_inverse)
     862            4 :             CPASSERT(ASSOCIATED(preconditioner_env%sparse_matrix))
     863              :             CALL prepare_lattice_operator(preconditioner_env, preconditioner_env%sparse_matrix, &
     864            4 :                                           "FULL_S_INVERSE", nhomo)
     865              :          CASE (ot_precond_full_all_covariant)
     866            2 :             CPASSERT(PRESENT(matrix_s))
     867            2 :             CPASSERT(ASSOCIATED(matrix_s))
     868              :             CALL prepare_lattice_state_operator(preconditioner_env, matrix_s, &
     869           20 :                                                 "FULL_ALL_COVARIANT")
     870              :          END SELECT
     871              :       END IF
     872              : 
     873         9940 :       IF (.NOT. preconditioner_env%lattice_fft_active) THEN
     874         9928 :          CALL solve_preconditioner(my_solver_type, preconditioner_env, matrix_s, matrix_h)
     875              :       ELSE
     876           12 :          preconditioner_env%solver = ot_precond_solver_inv_chol
     877              :       END IF
     878              : 
     879         9940 :       IF (precon_type == ot_precond_fermi_low_rank) THEN
     880            6 :          preconditioner_env%spectral_reference = energy_homo
     881              :          preconditioner_env%spectral_window = &
     882            6 :             MAX(fermi_low_rank_min_window, fermi_low_rank_gap_factor*preconditioner_env%energy_gap)
     883            6 :          preconditioner_env%spectral_base_scale = 1.0_dp/preconditioner_env%spectral_window
     884            6 :          max_rank = preconditioner_env%spectral_max_rank
     885            6 :          IF (max_rank == -1) max_rank = SIZE(preconditioner_env%full_evals) - nhomo
     886              :          preconditioner_env%spectral_rank = low_rank_select_rank( &
     887              :                                             preconditioner_env%full_evals, nhomo, max_rank, &
     888            6 :                                             fermi_low_rank_degeneracy_tolerance)
     889            6 :          CALL prepare_low_rank_base(preconditioner_env, matrix_s)
     890            6 :          IF (preconditioner_env%lattice_fft_active) THEN
     891              :             ! With an approximate base, retain only non-negative spectral updates.
     892              :             ! This preserves positive definiteness independently of the projection error.
     893           26 :             DO WHILE (preconditioner_env%spectral_rank > 0)
     894           26 :                IF (low_rank_inverse_weight( &
     895              :                    preconditioner_env%full_evals(nhomo + preconditioner_env%spectral_rank), &
     896              :                    preconditioner_env%spectral_reference, preconditioner_env%energy_gap) >= &
     897              :                    preconditioner_env%spectral_base_scale) EXIT
     898           26 :                preconditioner_env%spectral_rank = preconditioner_env%spectral_rank - 1
     899              :             END DO
     900              :          END IF
     901            6 :          IF (preconditioner_env%para_env%is_source()) THEN
     902            3 :             logger => cp_get_default_logger()
     903            3 :             output_unit = cp_logger_get_default_io_unit(logger)
     904            3 :             IF (output_unit > 0) THEN
     905              :                WRITE (output_unit, '(T2,A,F14.8,A,I0)') &
     906            3 :                   "OT| FERMI_LOW_RANK common reference [hartree]: ", &
     907            3 :                   preconditioner_env%spectral_reference, " retained rank: ", &
     908            6 :                   preconditioner_env%spectral_rank
     909              :             END IF
     910              :          END IF
     911              :       END IF
     912              : 
     913              :       ! Here comes more matrix mess, make sure to output the correct matrix format,
     914              :       ! A bit pointless to convert the cholesky factorized version as it doesn't work in
     915              :       ! dbcsr form and will crash later,...
     916         9940 :       IF (.NOT. preconditioner_env%lattice_fft_active) THEN
     917         9926 :          IF (my_convert_precond_to_dbcsr) THEN
     918         8196 :             CALL transfer_fm_to_dbcsr(preconditioner_env%fm, preconditioner_env%dbcsr_matrix, matrix_h)
     919         8196 :             IF (precon_type == ot_precond_fermi_low_rank .AND. &
     920              :                 preconditioner_env%low_rank_base == ot_low_rank_base_overlap) THEN
     921              :                CALL transfer_fm_to_dbcsr(preconditioner_env%base_fm, &
     922            4 :                                          preconditioner_env%base_dbcsr_matrix, matrix_h)
     923              :             END IF
     924              :          ELSE
     925              :             CALL transfer_dbcsr_to_fm(preconditioner_env%dbcsr_matrix, preconditioner_env%fm, &
     926         1730 :                                       preconditioner_env%para_env, preconditioner_env%ctxt)
     927              :          END IF
     928              :       END IF
     929              : 
     930         9940 :       DEALLOCATE (eigenvalues_ot)
     931              : 
     932         9940 :       CALL timestop(handle)
     933              : 
     934         9940 :    END SUBROUTINE make_preconditioner
     935              : 
     936              : ! **************************************************************************************************
     937              : !> \brief Construct FULL_ALL directly from one complex H(k), S(k), and C(k) channel.
     938              : !> \param preconditioner_env preconditioner storage
     939              : !> \param matrix_c_re real part of the active OT reference orbitals
     940              : !> \param matrix_c_im imaginary part of the active OT reference orbitals
     941              : !> \param matrix_h_re real part of H(k)
     942              : !> \param matrix_h_im imaginary part of H(k)
     943              : !> \param matrix_s_re real part of S(k)
     944              : !> \param matrix_s_im imaginary part of S(k)
     945              : !> \param mo_set ...
     946              : !> \param energy_gap denominator floor
     947              : !> \param solver_type inverse application selected in the OT input
     948              : ! **************************************************************************************************
     949          565 :    SUBROUTINE make_preconditioner_complex_full_all(preconditioner_env, &
     950              :                                                    matrix_c_re, matrix_c_im, &
     951              :                                                    matrix_h_re, matrix_h_im, &
     952              :                                                    matrix_s_re, matrix_s_im, &
     953              :                                                    mo_set, energy_gap, solver_type)
     954              : 
     955              :       TYPE(preconditioner_type)                          :: preconditioner_env
     956              :       TYPE(dbcsr_type), POINTER                          :: matrix_c_re, matrix_c_im, matrix_h_re, &
     957              :                                                             matrix_h_im, matrix_s_re, matrix_s_im
     958              :       TYPE(mo_set_type), INTENT(IN)                      :: mo_set
     959              :       REAL(KIND=dp), INTENT(IN)                          :: energy_gap
     960              :       INTEGER, INTENT(IN)                                :: solver_type
     961              : 
     962              :       CHARACTER(len=*), PARAMETER :: routineN = 'make_preconditioner_complex_full_all'
     963              : 
     964              :       INTEGER                                            :: handle, k
     965          113 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigenvalues
     966              :       TYPE(cp_cfm_type)                                  :: matrix_c, matrix_h, matrix_s
     967              : 
     968          113 :       CALL timeset(routineN, handle)
     969              : 
     970          113 :       NULLIFY (eigenvalues)
     971          113 :       CPASSERT(ASSOCIATED(matrix_c_re))
     972          113 :       CPASSERT(ASSOCIATED(matrix_c_im))
     973          113 :       CPASSERT(ASSOCIATED(matrix_h_re))
     974          113 :       CPASSERT(ASSOCIATED(matrix_h_im))
     975          113 :       CPASSERT(ASSOCIATED(matrix_s_re))
     976          113 :       CPASSERT(ASSOCIATED(matrix_s_im))
     977          113 :       IF (solver_type /= ot_precond_solver_default) THEN
     978            0 :          CPABORT('Complex FULL_ALL supports only PRECOND_SOLVER DEFAULT')
     979              :       END IF
     980          113 :       CALL dbcsr_get_info(matrix_c_re, nfullcols_total=k)
     981          113 :       CPASSERT(k > 0)
     982          113 :       CALL get_mo_set(mo_set, eigenvalues=eigenvalues)
     983          113 :       CPASSERT(ASSOCIATED(eigenvalues))
     984          113 :       CPASSERT(SIZE(eigenvalues) >= k)
     985              : 
     986              :       CALL dbcsr_pair_to_cfm(matrix_c_re, matrix_c_im, preconditioner_env, &
     987          113 :                              'complex FULL_ALL C', matrix_c)
     988              :       CALL dbcsr_pair_to_cfm(matrix_h_re, matrix_h_im, preconditioner_env, &
     989          113 :                              'complex FULL_ALL H', matrix_h)
     990              :       CALL dbcsr_pair_to_cfm(matrix_s_re, matrix_s_im, preconditioner_env, &
     991          113 :                              'complex FULL_ALL S', matrix_s)
     992              :       CALL make_complex_full_all(preconditioner_env, matrix_c, matrix_h, matrix_s, &
     993          113 :                                  eigenvalues(1:k), energy_gap)
     994              : 
     995          113 :       CALL cp_cfm_release(matrix_c)
     996          113 :       CALL cp_cfm_release(matrix_s)
     997          113 :       CALL cp_cfm_release(matrix_h)
     998              : 
     999          113 :       CALL timestop(handle)
    1000              : 
    1001          113 :    END SUBROUTINE make_preconditioner_complex_full_all
    1002              : 
    1003              : ! **************************************************************************************************
    1004              : !> \brief Construct a complex FULL_SINGLE preconditioner from H(k) and S(k).
    1005              : !> \param preconditioner_env preconditioner storage
    1006              : !> \param matrix_h_re real part of H(k)
    1007              : !> \param matrix_h_im imaginary part of H(k)
    1008              : !> \param matrix_s_re real part of S(k)
    1009              : !> \param matrix_s_im imaginary part of S(k)
    1010              : !> \param mo_set orbital energy labels defining the occupied edge
    1011              : !> \param energy_gap denominator floor
    1012              : !> \param solver_type requested inverse solver
    1013              : ! **************************************************************************************************
    1014          104 :    SUBROUTINE make_preconditioner_complex_full_single(preconditioner_env, &
    1015              :                                                       matrix_h_re, matrix_h_im, &
    1016              :                                                       matrix_s_re, matrix_s_im, &
    1017              :                                                       mo_set, energy_gap, solver_type)
    1018              : 
    1019              :       TYPE(preconditioner_type)                          :: preconditioner_env
    1020              :       TYPE(dbcsr_type), POINTER                          :: matrix_h_re, matrix_h_im, matrix_s_re, &
    1021              :                                                             matrix_s_im
    1022              :       TYPE(mo_set_type), INTENT(IN)                      :: mo_set
    1023              :       REAL(KIND=dp), INTENT(IN)                          :: energy_gap
    1024              :       INTEGER, INTENT(IN)                                :: solver_type
    1025              : 
    1026              :       INTEGER                                            :: homo
    1027           26 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigenvalues
    1028              :       TYPE(cp_cfm_type)                                  :: matrix_h, matrix_s
    1029              : 
    1030           26 :       NULLIFY (eigenvalues)
    1031            0 :       CPASSERT(ASSOCIATED(matrix_h_re))
    1032           26 :       CPASSERT(ASSOCIATED(matrix_h_im))
    1033           26 :       CPASSERT(ASSOCIATED(matrix_s_re))
    1034           26 :       CPASSERT(ASSOCIATED(matrix_s_im))
    1035           26 :       IF (solver_type /= ot_precond_solver_default) THEN
    1036            0 :          CPABORT('Complex FULL_SINGLE supports only PRECOND_SOLVER DEFAULT')
    1037              :       END IF
    1038           26 :       CALL get_mo_set(mo_set, homo=homo, eigenvalues=eigenvalues)
    1039           26 :       CPASSERT(ASSOCIATED(eigenvalues))
    1040           26 :       CPASSERT(homo > 0 .AND. homo <= SIZE(eigenvalues))
    1041              : 
    1042              :       CALL dbcsr_pair_to_cfm(matrix_h_re, matrix_h_im, preconditioner_env, &
    1043           26 :                              'complex FULL_SINGLE H', matrix_h)
    1044              :       CALL dbcsr_pair_to_cfm(matrix_s_re, matrix_s_im, preconditioner_env, &
    1045           26 :                              'complex FULL_SINGLE S', matrix_s)
    1046              :       CALL make_complex_full_single(preconditioner_env, matrix_h, matrix_s, &
    1047           26 :                                     eigenvalues(homo), energy_gap)
    1048           26 :       CALL cp_cfm_release(matrix_s)
    1049           26 :       CALL cp_cfm_release(matrix_h)
    1050              : 
    1051           26 :    END SUBROUTINE make_preconditioner_complex_full_single
    1052              : 
    1053              : ! **************************************************************************************************
    1054              : !> \brief Construct FERMI_LOW_RANK directly for one complex k-point channel.
    1055              : !> \param preconditioner_env preconditioner storage
    1056              : !> \param matrix_c_re real part of the active OT reference orbitals
    1057              : !> \param matrix_c_im imaginary part of the active OT reference orbitals
    1058              : !> \param matrix_h_re real part of H(k)
    1059              : !> \param matrix_h_im imaginary part of H(k)
    1060              : !> \param matrix_s_re real part of S(k)
    1061              : !> \param matrix_s_im imaginary part of S(k)
    1062              : !> \param energy_gap denominator floor
    1063              : !> \param max_rank maximum complementary rank, or -1 for the full complement
    1064              : !> \param solver_type inverse application selected in the OT input
    1065              : ! **************************************************************************************************
    1066          184 :    SUBROUTINE make_preconditioner_complex_fermi_low_rank( &
    1067              :       preconditioner_env, matrix_c_re, matrix_c_im, matrix_h_re, matrix_h_im, &
    1068              :       matrix_s_re, matrix_s_im, energy_gap, max_rank, solver_type)
    1069              : 
    1070              :       TYPE(preconditioner_type)                          :: preconditioner_env
    1071              :       TYPE(dbcsr_type), POINTER                          :: matrix_c_re, matrix_c_im, matrix_h_re, &
    1072              :                                                             matrix_h_im, matrix_s_re, matrix_s_im
    1073              :       REAL(KIND=dp), INTENT(IN)                          :: energy_gap
    1074              :       INTEGER, INTENT(IN)                                :: max_rank, solver_type
    1075              : 
    1076              :       TYPE(cp_cfm_type)                                  :: matrix_c, matrix_h, matrix_s
    1077              : 
    1078           46 :       IF (solver_type /= ot_precond_solver_default) THEN
    1079            0 :          CPABORT('Complex FERMI_LOW_RANK supports only PRECOND_SOLVER DEFAULT')
    1080              :       END IF
    1081              : 
    1082              :       CALL dbcsr_pair_to_cfm(matrix_c_re, matrix_c_im, preconditioner_env, &
    1083           46 :                              'complex FERMI_LOW_RANK C', matrix_c)
    1084              :       CALL dbcsr_pair_to_cfm(matrix_h_re, matrix_h_im, preconditioner_env, &
    1085           46 :                              'complex FERMI_LOW_RANK H', matrix_h)
    1086              :       CALL dbcsr_pair_to_cfm(matrix_s_re, matrix_s_im, preconditioner_env, &
    1087           46 :                              'complex FERMI_LOW_RANK S', matrix_s)
    1088              :       CALL make_complex_fermi_low_rank( &
    1089              :          preconditioner_env, matrix_c, matrix_h, matrix_s, energy_gap, &
    1090              :          max_rank, MAX(fermi_low_rank_min_window, fermi_low_rank_gap_factor*energy_gap), &
    1091           46 :          fermi_low_rank_degeneracy_tolerance)
    1092              : 
    1093           46 :       CALL cp_cfm_release(matrix_s)
    1094           46 :       CALL cp_cfm_release(matrix_h)
    1095           46 :       CALL cp_cfm_release(matrix_c)
    1096              : 
    1097           46 :    END SUBROUTINE make_preconditioner_complex_fermi_low_rank
    1098              : 
    1099              : ! **************************************************************************************************
    1100              : !> \brief Construct rotation-covariant FULL_ALL for one complex k-point channel.
    1101              : !> \param preconditioner_env preconditioner storage
    1102              : !> \param matrix_c_re real part of the active OT reference orbitals
    1103              : !> \param matrix_c_im imaginary part of the active OT reference orbitals
    1104              : !> \param matrix_h_re real part of H(k)
    1105              : !> \param matrix_h_im imaginary part of H(k)
    1106              : !> \param matrix_s_re real part of S(k)
    1107              : !> \param matrix_s_im imaginary part of S(k)
    1108              : !> \param energy_gap denominator floor
    1109              : !> \param solver_type inverse application selected in the OT input
    1110              : !> \param occupation_signature occupations that define the admissible private gauge
    1111              : ! **************************************************************************************************
    1112          208 :    SUBROUTINE make_preconditioner_complex_full_all_covariant( &
    1113              :       preconditioner_env, matrix_c_re, matrix_c_im, matrix_h_re, matrix_h_im, &
    1114           52 :       matrix_s_re, matrix_s_im, energy_gap, solver_type, occupation_signature)
    1115              : 
    1116              :       TYPE(preconditioner_type)                          :: preconditioner_env
    1117              :       TYPE(dbcsr_type), POINTER                          :: matrix_c_re, matrix_c_im, matrix_h_re, &
    1118              :                                                             matrix_h_im, matrix_s_re, matrix_s_im
    1119              :       REAL(KIND=dp), INTENT(IN)                          :: energy_gap
    1120              :       INTEGER, INTENT(IN)                                :: solver_type
    1121              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
    1122              :          OPTIONAL                                        :: occupation_signature
    1123              : 
    1124              :       TYPE(cp_cfm_type)                                  :: matrix_c, matrix_h, matrix_s
    1125              : 
    1126           52 :       IF (solver_type /= ot_precond_solver_default) THEN
    1127            0 :          CPABORT('Complex FULL_ALL_COVARIANT supports only PRECOND_SOLVER DEFAULT')
    1128              :       END IF
    1129              :       CALL dbcsr_pair_to_cfm(matrix_c_re, matrix_c_im, preconditioner_env, &
    1130           52 :                              'complex FULL_ALL_COVARIANT C', matrix_c)
    1131              :       CALL dbcsr_pair_to_cfm(matrix_h_re, matrix_h_im, preconditioner_env, &
    1132           52 :                              'complex FULL_ALL_COVARIANT H', matrix_h)
    1133              :       CALL dbcsr_pair_to_cfm(matrix_s_re, matrix_s_im, preconditioner_env, &
    1134           52 :                              'complex FULL_ALL_COVARIANT S', matrix_s)
    1135              :       CALL make_complex_full_all_covariant(preconditioner_env, matrix_c, matrix_h, matrix_s, &
    1136           96 :                                            energy_gap, occupation_signature)
    1137              : 
    1138           52 :       CALL cp_cfm_release(matrix_s)
    1139           52 :       CALL cp_cfm_release(matrix_h)
    1140           52 :       CALL cp_cfm_release(matrix_c)
    1141              : 
    1142           52 :    END SUBROUTINE make_preconditioner_complex_full_all_covariant
    1143              : 
    1144              : ! **************************************************************************************************
    1145              : !> \brief Construct a complex FULL_SINGLE_INVERSE preconditioner without discarding Im(H,S,C).
    1146              : !> \param preconditioner_env preconditioner storage
    1147              : !> \param matrix_c_re real part of the occupied reference orbitals
    1148              : !> \param matrix_c_im imaginary part of the occupied reference orbitals
    1149              : !> \param matrix_h_re real part of H(k)
    1150              : !> \param matrix_h_im imaginary part of H(k)
    1151              : !> \param matrix_s_re real part of S(k)
    1152              : !> \param matrix_s_im imaginary part of S(k)
    1153              : !> \param energy_gap lower spectral bound
    1154              : !> \param solver_type requested inverse solver
    1155              : ! **************************************************************************************************
    1156          484 :    SUBROUTINE make_preconditioner_complex_full_single_inverse(preconditioner_env, &
    1157              :                                                               matrix_c_re, matrix_c_im, &
    1158              :                                                               matrix_h_re, matrix_h_im, &
    1159              :                                                               matrix_s_re, matrix_s_im, &
    1160              :                                                               energy_gap, solver_type)
    1161              : 
    1162              :       TYPE(preconditioner_type)                          :: preconditioner_env
    1163              :       TYPE(dbcsr_type), POINTER                          :: matrix_c_re, matrix_c_im, matrix_h_re, &
    1164              :                                                             matrix_h_im, matrix_s_re, matrix_s_im
    1165              :       REAL(KIND=dp), INTENT(IN)                          :: energy_gap
    1166              :       INTEGER, INTENT(IN)                                :: solver_type
    1167              : 
    1168              :       INTEGER                                            :: k, n
    1169              :       TYPE(cp_cfm_type)                                  :: matrix_c, matrix_h, matrix_s
    1170              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_mo, fm_struct_square
    1171              :       TYPE(cp_fm_type)                                   :: matrix_c_im_fm, matrix_c_re_fm, &
    1172              :                                                             matrix_h_im_fm, matrix_h_re_fm, &
    1173              :                                                             matrix_s_im_fm, matrix_s_re_fm
    1174              : 
    1175           44 :       NULLIFY (fm_struct_mo, fm_struct_square)
    1176            0 :       CPASSERT(ASSOCIATED(matrix_c_re))
    1177           44 :       CPASSERT(ASSOCIATED(matrix_c_im))
    1178           44 :       CPASSERT(ASSOCIATED(matrix_h_re))
    1179           44 :       CPASSERT(ASSOCIATED(matrix_h_im))
    1180           44 :       CPASSERT(ASSOCIATED(matrix_s_re))
    1181           44 :       CPASSERT(ASSOCIATED(matrix_s_im))
    1182           44 :       IF (solver_type /= ot_precond_solver_default .AND. &
    1183              :           solver_type /= ot_precond_solver_inv_chol) THEN
    1184            0 :          CPABORT("Complex FULL_SINGLE_INVERSE supports only PRECOND_SOLVER DEFAULT/INVERSE_CHOLESKY")
    1185              :       END IF
    1186           44 :       CALL dbcsr_get_info(matrix_c_re, nfullrows_total=n, nfullcols_total=k)
    1187           44 :       CPASSERT(n > 0 .AND. k > 0 .AND. k <= n)
    1188              : 
    1189              :       CALL cp_fm_struct_create(fm_struct_mo, nrow_global=n, ncol_global=k, &
    1190              :                                context=preconditioner_env%ctxt, &
    1191           44 :                                para_env=preconditioner_env%para_env)
    1192              :       CALL cp_fm_struct_create(fm_struct_square, nrow_global=n, ncol_global=n, &
    1193              :                                context=preconditioner_env%ctxt, &
    1194           44 :                                para_env=preconditioner_env%para_env)
    1195           44 :       CALL cp_fm_create(matrix_c_re_fm, fm_struct_mo, name='complex preconditioner C real')
    1196           44 :       CALL cp_fm_create(matrix_c_im_fm, fm_struct_mo, name='complex preconditioner C imaginary')
    1197           44 :       CALL cp_fm_create(matrix_h_re_fm, fm_struct_square, name='complex preconditioner H real')
    1198           44 :       CALL cp_fm_create(matrix_h_im_fm, fm_struct_square, name='complex preconditioner H imaginary')
    1199           44 :       CALL cp_fm_create(matrix_s_re_fm, fm_struct_square, name='complex preconditioner S real')
    1200           44 :       CALL cp_fm_create(matrix_s_im_fm, fm_struct_square, name='complex preconditioner S imaginary')
    1201           44 :       CALL cp_fm_struct_release(fm_struct_mo)
    1202           44 :       CALL cp_fm_struct_release(fm_struct_square)
    1203           44 :       CALL copy_dbcsr_to_fm(matrix_c_re, matrix_c_re_fm)
    1204           44 :       CALL copy_dbcsr_to_fm(matrix_c_im, matrix_c_im_fm)
    1205           44 :       CALL copy_dbcsr_to_fm(matrix_h_re, matrix_h_re_fm)
    1206           44 :       CALL copy_dbcsr_to_fm(matrix_h_im, matrix_h_im_fm)
    1207           44 :       CALL copy_dbcsr_to_fm(matrix_s_re, matrix_s_re_fm)
    1208           44 :       CALL copy_dbcsr_to_fm(matrix_s_im, matrix_s_im_fm)
    1209              : 
    1210           44 :       CALL cp_cfm_create(matrix_c, matrix_c_re_fm%matrix_struct, name='complex preconditioner C')
    1211           44 :       CALL cp_cfm_create(matrix_h, matrix_h_re_fm%matrix_struct, name='complex preconditioner H')
    1212           44 :       CALL cp_cfm_create(matrix_s, matrix_s_re_fm%matrix_struct, name='complex preconditioner S')
    1213           44 :       CALL cp_fm_to_cfm(matrix_c_re_fm, matrix_c_im_fm, matrix_c)
    1214           44 :       CALL cp_fm_to_cfm(matrix_h_re_fm, matrix_h_im_fm, matrix_h)
    1215           44 :       CALL cp_fm_to_cfm(matrix_s_re_fm, matrix_s_im_fm, matrix_s)
    1216              :       CALL make_complex_full_single_inverse(preconditioner_env, matrix_c, matrix_h, matrix_s, &
    1217           44 :                                             energy_gap)
    1218           44 :       preconditioner_env%solver = solver_type
    1219              : 
    1220           44 :       CALL cp_cfm_release(matrix_s)
    1221           44 :       CALL cp_cfm_release(matrix_h)
    1222           44 :       CALL cp_cfm_release(matrix_c)
    1223           44 :       CALL cp_fm_release(matrix_s_im_fm)
    1224           44 :       CALL cp_fm_release(matrix_s_re_fm)
    1225           44 :       CALL cp_fm_release(matrix_h_im_fm)
    1226           44 :       CALL cp_fm_release(matrix_h_re_fm)
    1227           44 :       CALL cp_fm_release(matrix_c_im_fm)
    1228           44 :       CALL cp_fm_release(matrix_c_re_fm)
    1229              : 
    1230           44 :    END SUBROUTINE make_preconditioner_complex_full_single_inverse
    1231              : 
    1232              : ! **************************************************************************************************
    1233              : !> \brief Construct a complex FULL_S_INVERSE preconditioner.
    1234              : !> \param preconditioner_env preconditioner storage
    1235              : !> \param matrix_s_re real part of S(k)
    1236              : !> \param matrix_s_im imaginary part of S(k)
    1237              : !> \param solver_type requested inverse solver
    1238              : ! **************************************************************************************************
    1239          164 :    SUBROUTINE make_preconditioner_complex_full_s_inverse(preconditioner_env, &
    1240              :                                                          matrix_s_re, matrix_s_im, solver_type)
    1241              : 
    1242              :       TYPE(preconditioner_type)                          :: preconditioner_env
    1243              :       TYPE(dbcsr_type), POINTER                          :: matrix_s_re, matrix_s_im
    1244              :       INTEGER, INTENT(IN)                                :: solver_type
    1245              : 
    1246              :       TYPE(cp_cfm_type)                                  :: matrix_s
    1247              : 
    1248           82 :       IF (solver_type /= ot_precond_solver_default .AND. &
    1249              :           solver_type /= ot_precond_solver_inv_chol) THEN
    1250            0 :          CPABORT("Complex FULL_S_INVERSE supports only PRECOND_SOLVER DEFAULT/INVERSE_CHOLESKY")
    1251              :       END IF
    1252              :       CALL dbcsr_pair_to_cfm(matrix_s_re, matrix_s_im, preconditioner_env, &
    1253           82 :                              'complex preconditioner S', matrix_s)
    1254           82 :       CALL make_complex_full_s_inverse(preconditioner_env, matrix_s)
    1255           82 :       preconditioner_env%solver = solver_type
    1256           82 :       CALL cp_cfm_release(matrix_s)
    1257              : 
    1258           82 :    END SUBROUTINE make_preconditioner_complex_full_s_inverse
    1259              : 
    1260              : ! **************************************************************************************************
    1261              : !> \brief Construct a complex FULL_KINETIC preconditioner.
    1262              : !> \param preconditioner_env preconditioner storage
    1263              : !> \param matrix_t_re real part of T(k)
    1264              : !> \param matrix_t_im imaginary part of T(k)
    1265              : !> \param matrix_s_re real part of S(k)
    1266              : !> \param matrix_s_im imaginary part of S(k)
    1267              : !> \param energy_gap non-negative overlap shift
    1268              : !> \param solver_type requested inverse solver
    1269              : ! **************************************************************************************************
    1270          360 :    SUBROUTINE make_preconditioner_complex_full_kinetic(preconditioner_env, &
    1271              :                                                        matrix_t_re, matrix_t_im, &
    1272              :                                                        matrix_s_re, matrix_s_im, &
    1273              :                                                        energy_gap, solver_type)
    1274              : 
    1275              :       TYPE(preconditioner_type)                          :: preconditioner_env
    1276              :       TYPE(dbcsr_type), POINTER                          :: matrix_t_re, matrix_t_im, matrix_s_re, &
    1277              :                                                             matrix_s_im
    1278              :       REAL(KIND=dp), INTENT(IN)                          :: energy_gap
    1279              :       INTEGER, INTENT(IN)                                :: solver_type
    1280              : 
    1281              :       TYPE(cp_cfm_type)                                  :: matrix_s, matrix_t
    1282              : 
    1283          120 :       IF (solver_type /= ot_precond_solver_default .AND. &
    1284              :           solver_type /= ot_precond_solver_inv_chol) THEN
    1285            0 :          CPABORT("Complex FULL_KINETIC supports only PRECOND_SOLVER DEFAULT/INVERSE_CHOLESKY")
    1286              :       END IF
    1287              :       CALL dbcsr_pair_to_cfm(matrix_t_re, matrix_t_im, preconditioner_env, &
    1288          120 :                              'complex preconditioner T', matrix_t)
    1289              :       CALL dbcsr_pair_to_cfm(matrix_s_re, matrix_s_im, preconditioner_env, &
    1290          120 :                              'complex preconditioner S', matrix_s)
    1291          120 :       CALL make_complex_full_kinetic(preconditioner_env, matrix_t, matrix_s, energy_gap)
    1292          120 :       preconditioner_env%solver = solver_type
    1293          120 :       CALL cp_cfm_release(matrix_s)
    1294          120 :       CALL cp_cfm_release(matrix_t)
    1295              : 
    1296          120 :    END SUBROUTINE make_preconditioner_complex_full_kinetic
    1297              : 
    1298              : ! **************************************************************************************************
    1299              : !> \brief Copy a real/imaginary DBCSR pair to one distributed complex full matrix.
    1300              : !> \param matrix_re real matrix component
    1301              : !> \param matrix_im imaginary matrix component
    1302              : !> \param preconditioner_env source of the distribution context
    1303              : !> \param matrix_name matrix label
    1304              : !> \param matrix complex output matrix
    1305              : ! **************************************************************************************************
    1306         3357 :    SUBROUTINE dbcsr_pair_to_cfm(matrix_re, matrix_im, preconditioner_env, matrix_name, matrix)
    1307              : 
    1308              :       TYPE(dbcsr_type), POINTER                          :: matrix_re, matrix_im
    1309              :       TYPE(preconditioner_type)                          :: preconditioner_env
    1310              :       CHARACTER(LEN=*), INTENT(IN)                       :: matrix_name
    1311              :       TYPE(cp_cfm_type), INTENT(OUT)                     :: matrix
    1312              : 
    1313              :       INTEGER                                            :: ncol, nrow
    1314              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
    1315              :       TYPE(cp_fm_type)                                   :: matrix_im_fm, matrix_re_fm
    1316              : 
    1317         1119 :       NULLIFY (fm_struct)
    1318            0 :       CPASSERT(ASSOCIATED(matrix_re))
    1319         1119 :       CPASSERT(ASSOCIATED(matrix_im))
    1320         1119 :       CALL dbcsr_get_info(matrix_re, nfullrows_total=nrow, nfullcols_total=ncol)
    1321              :       CALL cp_fm_struct_create(fm_struct, nrow_global=nrow, ncol_global=ncol, &
    1322              :                                context=preconditioner_env%ctxt, &
    1323         1119 :                                para_env=preconditioner_env%para_env)
    1324         1119 :       CALL cp_fm_create(matrix_re_fm, fm_struct, name=TRIM(matrix_name)//' real')
    1325         1119 :       CALL cp_fm_create(matrix_im_fm, fm_struct, name=TRIM(matrix_name)//' imaginary')
    1326         1119 :       CALL cp_fm_struct_release(fm_struct)
    1327         1119 :       CALL copy_dbcsr_to_fm(matrix_re, matrix_re_fm)
    1328         1119 :       CALL copy_dbcsr_to_fm(matrix_im, matrix_im_fm)
    1329         1119 :       CALL cp_cfm_create(matrix, matrix_re_fm%matrix_struct, name=matrix_name)
    1330         1119 :       CALL cp_fm_to_cfm(matrix_re_fm, matrix_im_fm, matrix)
    1331         1119 :       CALL cp_fm_release(matrix_im_fm)
    1332         1119 :       CALL cp_fm_release(matrix_re_fm)
    1333              : 
    1334         1119 :    END SUBROUTINE dbcsr_pair_to_cfm
    1335              : 
    1336              : ! **************************************************************************************************
    1337              : !> \brief Allows for a restart of the preconditioner
    1338              : !>        depending on the method it purges all arrays or keeps them
    1339              : !> \param qs_env ...
    1340              : !> \param preconditioner ...
    1341              : !> \param prec_type ...
    1342              : !> \param nspins ...
    1343              : ! **************************************************************************************************
    1344         7611 :    SUBROUTINE restart_preconditioner(qs_env, preconditioner, prec_type, nspins)
    1345              : 
    1346              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1347              :       TYPE(preconditioner_p_type), DIMENSION(:), POINTER :: preconditioner
    1348              :       INTEGER, INTENT(IN)                                :: prec_type, nspins
    1349              : 
    1350              :       INTEGER                                            :: ispin
    1351              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    1352              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1353              : 
    1354         7611 :       NULLIFY (para_env, blacs_env)
    1355         7611 :       CALL get_qs_env(qs_env, para_env=para_env, blacs_env=blacs_env)
    1356              : 
    1357         7611 :       IF (ASSOCIATED(preconditioner)) THEN
    1358         6776 :          SELECT CASE (prec_type)
    1359              :          CASE (ot_precond_full_all, ot_precond_fermi_low_rank, &
    1360              :                ot_precond_full_all_covariant, &
    1361              :                ot_precond_full_single) ! these depend on the ks matrix
    1362         3476 :             DO ispin = 1, SIZE(preconditioner)
    1363         1938 :                CALL destroy_preconditioner(preconditioner(ispin)%preconditioner)
    1364         3476 :                DEALLOCATE (preconditioner(ispin)%preconditioner)
    1365              :             END DO
    1366         1538 :             DEALLOCATE (preconditioner)
    1367              :          CASE (ot_precond_none, ot_precond_full_kinetic, ot_precond_s_inverse, &
    1368              :                ot_precond_full_single_inverse) ! these are 'independent'
    1369              :             ! do nothing
    1370              :          CASE DEFAULT
    1371         5238 :             CPABORT("Unknown preconditioner type")
    1372              :          END SELECT
    1373              :       END IF
    1374              : 
    1375              :       ! add an OT preconditioner if none is present
    1376         7611 :       IF (.NOT. ASSOCIATED(preconditioner)) THEN
    1377         7169 :          SELECT CASE (prec_type)
    1378              :          CASE (ot_precond_full_all, ot_precond_fermi_low_rank, ot_precond_full_all_covariant, &
    1379              :                ot_precond_full_single_inverse)
    1380        13959 :             ALLOCATE (preconditioner(nspins))
    1381              :          CASE DEFAULT
    1382         4564 :             ALLOCATE (preconditioner(1))
    1383              :          END SELECT
    1384         8749 :          DO ispin = 1, SIZE(preconditioner)
    1385        24190 :             ALLOCATE (preconditioner(ispin)%preconditioner)
    1386              :             CALL init_preconditioner(preconditioner(ispin)%preconditioner, &
    1387              :                                      para_env=para_env, &
    1388         8749 :                                      blacs_env=blacs_env)
    1389              :          END DO
    1390              :       END IF
    1391              : 
    1392         7611 :    END SUBROUTINE restart_preconditioner
    1393              : 
    1394              : ! **************************************************************************************************
    1395              : !> \brief ...
    1396              : !> \param qs_env ...
    1397              : !> \param mos ...
    1398              : !> \param matrix_ks ...
    1399              : !> \param matrix_s ...
    1400              : !> \param ot_preconditioner ...
    1401              : !> \param prec_type ...
    1402              : !> \param solver_type ...
    1403              : !> \param energy_gap ...
    1404              : !> \param nspins ...
    1405              : !> \param has_unit_metric ...
    1406              : !> \param convert_to_dbcsr ...
    1407              : !> \param chol_type ...
    1408              : !> \param full_mo_set ...
    1409              : !> \param chebyshev_degree ...
    1410              : !> \param low_rank_base ...
    1411              : !> \param fermi_low_rank_max_rank ...
    1412              : !> \param lattice_fft ...
    1413              : !> \param lattice_fft_local_cells ...
    1414              : ! **************************************************************************************************
    1415         7611 :    SUBROUTINE prepare_preconditioner(qs_env, mos, matrix_ks, matrix_s, &
    1416              :                                      ot_preconditioner, prec_type, solver_type, &
    1417              :                                      energy_gap, nspins, has_unit_metric, &
    1418              :                                      convert_to_dbcsr, chol_type, full_mo_set, chebyshev_degree, &
    1419              :                                      low_rank_base, fermi_low_rank_max_rank, lattice_fft, &
    1420              :                                      lattice_fft_local_cells)
    1421              : 
    1422              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1423              :       TYPE(mo_set_type), DIMENSION(:), INTENT(INOUT)     :: mos
    1424              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s
    1425              :       TYPE(preconditioner_p_type), DIMENSION(:), POINTER :: ot_preconditioner
    1426              :       INTEGER, INTENT(IN)                                :: prec_type, solver_type
    1427              :       REAL(dp), INTENT(IN)                               :: energy_gap
    1428              :       INTEGER, INTENT(IN)                                :: nspins
    1429              :       LOGICAL, INTENT(IN), OPTIONAL                      :: has_unit_metric, convert_to_dbcsr
    1430              :       INTEGER, INTENT(IN), OPTIONAL                      :: chol_type
    1431              :       LOGICAL, INTENT(IN), OPTIONAL                      :: full_mo_set
    1432              :       INTEGER, INTENT(IN), OPTIONAL                      :: chebyshev_degree, low_rank_base, &
    1433              :                                                             fermi_low_rank_max_rank, lattice_fft, &
    1434              :                                                             lattice_fft_local_cells
    1435              : 
    1436              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'prepare_preconditioner'
    1437              : 
    1438              :       CHARACTER(LEN=default_string_length)               :: msg
    1439              :       INTEGER :: handle, icall, ispin, my_chebyshev_degree, my_fermi_low_rank_max_rank, &
    1440              :          my_lattice_fft, my_lattice_fft_local_cells, my_low_rank_base, n_loops
    1441              :       INTEGER, DIMENSION(5)                              :: nocc, norb
    1442         7611 :       INTEGER, DIMENSION(:), POINTER                     :: multiple_unit_cell
    1443              :       LOGICAL :: do_co_rotate, do_kpoints, my_convert_to_dbcsr, my_full_mo_set, &
    1444              :          my_has_unit_metric, use_covariant_full_all, use_mo_coeff_b
    1445              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    1446              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
    1447         7611 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: kinetic
    1448              :       TYPE(dbcsr_type), POINTER                          :: matrix_t, mo_coeff_b
    1449              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1450         7611 :       TYPE(mo_set_type), ALLOCATABLE, DIMENSION(:)       :: canonical_mos
    1451              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1452              :       TYPE(section_vals_type), POINTER                   :: input, subsys_section
    1453              : 
    1454         7611 :       CALL timeset(routineN, handle)
    1455         7611 :       NULLIFY (matrix_t, mo_coeff_b, mo_coeff, kinetic, dft_control, para_env, blacs_env, &
    1456         7611 :                input, subsys_section, multiple_unit_cell)
    1457         7611 :       my_has_unit_metric = .FALSE.
    1458         7611 :       IF (PRESENT(has_unit_metric)) my_has_unit_metric = has_unit_metric
    1459         7611 :       my_convert_to_dbcsr = .TRUE.
    1460         7611 :       IF (PRESENT(convert_to_dbcsr)) my_convert_to_dbcsr = convert_to_dbcsr
    1461         7611 :       my_full_mo_set = .FALSE.
    1462         7611 :       IF (PRESENT(full_mo_set)) my_full_mo_set = full_mo_set
    1463         7611 :       my_chebyshev_degree = 8
    1464         7611 :       IF (PRESENT(chebyshev_degree)) my_chebyshev_degree = chebyshev_degree
    1465         7611 :       my_low_rank_base = ot_low_rank_base_overlap
    1466         7611 :       IF (PRESENT(low_rank_base)) my_low_rank_base = low_rank_base
    1467         7611 :       my_fermi_low_rank_max_rank = 48
    1468         7611 :       IF (PRESENT(fermi_low_rank_max_rank)) my_fermi_low_rank_max_rank = fermi_low_rank_max_rank
    1469         7611 :       my_lattice_fft = ot_lattice_fft_off
    1470         7611 :       IF (PRESENT(lattice_fft)) my_lattice_fft = lattice_fft
    1471         7611 :       my_lattice_fft_local_cells = 0
    1472         7611 :       IF (PRESENT(lattice_fft_local_cells)) my_lattice_fft_local_cells = lattice_fft_local_cells
    1473         7593 :       IF (my_lattice_fft_local_cells < 0) CPABORT("LATTICE_FFT_LOCAL_CELLS must not be negative")
    1474         7611 :       do_kpoints = .FALSE.
    1475         7611 :       use_covariant_full_all = prec_type == ot_precond_full_all_covariant
    1476              : 
    1477              :       CALL get_qs_env(qs_env, &
    1478              :                       dft_control=dft_control, &
    1479              :                       do_kpoints=do_kpoints, &
    1480              :                       input=input, &
    1481              :                       para_env=para_env, &
    1482         7611 :                       blacs_env=blacs_env)
    1483              : 
    1484         7611 :       IF (my_low_rank_base == ot_low_rank_base_lattice_fft) THEN
    1485            0 :          IF (prec_type /= ot_precond_fermi_low_rank) THEN
    1486            0 :             CPABORT("FERMI_LOW_RANK_BASE LATTICE_FFT requires PRECONDITIONER FERMI_LOW_RANK")
    1487              :          END IF
    1488              :          my_lattice_fft = ot_lattice_fft_on
    1489         7611 :       ELSE IF (my_low_rank_base /= ot_low_rank_base_overlap) THEN
    1490            0 :          CPABORT("Unknown FERMI_LOW_RANK_BASE setting")
    1491              :       END IF
    1492              : 
    1493              :       IF (my_lattice_fft /= ot_lattice_fft_off .AND. &
    1494         7611 :           my_lattice_fft /= ot_lattice_fft_on .AND. &
    1495              :           my_lattice_fft /= ot_lattice_fft_auto) THEN
    1496            0 :          CPABORT("Unknown LATTICE_FFT setting")
    1497              :       END IF
    1498         7611 :       IF (my_lattice_fft_local_cells > 0 .AND. my_lattice_fft /= ot_lattice_fft_on) THEN
    1499            0 :          CPABORT("LATTICE_FFT_LOCAL_CELLS requires LATTICE_FFT ON")
    1500              :       END IF
    1501         7611 :       IF (my_lattice_fft /= ot_lattice_fft_off) THEN
    1502            0 :          SELECT CASE (prec_type)
    1503              :          CASE (ot_precond_fermi_low_rank, ot_precond_full_all_covariant, &
    1504              :                ot_precond_full_kinetic, ot_precond_full_single_inverse, ot_precond_s_inverse)
    1505              :          CASE DEFAULT
    1506           18 :             CPABORT("LATTICE_FFT does not support the selected OT preconditioner")
    1507              :          END SELECT
    1508           18 :          IF (solver_type /= ot_precond_solver_default .AND. &
    1509              :              solver_type /= ot_precond_solver_inv_chol) THEN
    1510            0 :             CPABORT("LATTICE_FFT requires PRECOND_SOLVER DEFAULT or INVERSE_CHOLESKY")
    1511              :          END IF
    1512           18 :          IF (my_has_unit_metric .OR. do_kpoints .OR. .NOT. ASSOCIATED(input)) THEN
    1513            0 :             IF (my_lattice_fft == ot_lattice_fft_on) THEN
    1514            0 :                CPABORT("LATTICE_FFT ON requires a non-unit metric in a real Gamma-point calculation")
    1515              :             END IF
    1516              :             my_lattice_fft = ot_lattice_fft_off
    1517              :          END IF
    1518              :       END IF
    1519              :       IF (my_lattice_fft /= ot_lattice_fft_off) THEN
    1520           18 :          subsys_section => section_vals_get_subs_vals(input, "SUBSYS")
    1521           18 :          IF (.NOT. ASSOCIATED(subsys_section)) THEN
    1522            0 :             IF (my_lattice_fft == ot_lattice_fft_on) CPABORT("LATTICE_FFT ON requires a SUBSYS section")
    1523              :             my_lattice_fft = ot_lattice_fft_off
    1524              :          END IF
    1525              :          IF (my_lattice_fft /= ot_lattice_fft_off) THEN
    1526              :             CALL section_vals_val_get(subsys_section, "CELL%MULTIPLE_UNIT_CELL", &
    1527           18 :                                       i_vals=multiple_unit_cell)
    1528           18 :             IF (.NOT. ASSOCIATED(multiple_unit_cell)) THEN
    1529            0 :                IF (my_lattice_fft == ot_lattice_fft_on) THEN
    1530            0 :                   CPABORT("LATTICE_FFT ON requires a valid CELL%MULTIPLE_UNIT_CELL")
    1531              :                END IF
    1532              :                my_lattice_fft = ot_lattice_fft_off
    1533              :             ELSE
    1534           72 :                IF (SIZE(multiple_unit_cell) /= 3 .OR. ANY(multiple_unit_cell <= 0)) THEN
    1535            0 :                   IF (my_lattice_fft == ot_lattice_fft_on) THEN
    1536            0 :                      CPABORT("LATTICE_FFT ON requires a valid CELL%MULTIPLE_UNIT_CELL")
    1537              :                   END IF
    1538              :                   my_lattice_fft = ot_lattice_fft_off
    1539           72 :                ELSE IF (PRODUCT(multiple_unit_cell) <= 1 .AND. my_lattice_fft == ot_lattice_fft_on) THEN
    1540            0 :                   CPABORT("LATTICE_FFT ON requires an explicitly replicated multiple unit cell")
    1541              :                END IF
    1542           72 :                IF (my_lattice_fft_local_cells >= PRODUCT(multiple_unit_cell)) THEN
    1543            0 :                   CPABORT("LATTICE_FFT_LOCAL_CELLS must be smaller than the replicated cell count")
    1544              :                END IF
    1545              :             END IF
    1546              :          END IF
    1547              :       END IF
    1548              : 
    1549         7611 :       IF (dft_control%qs_control%semi_empirical .OR. dft_control%qs_control%dftb .OR. &
    1550              :           dft_control%qs_control%xtb) THEN
    1551         2152 :          IF (prec_type == ot_precond_full_kinetic) THEN
    1552            0 :             msg = "Full_kinetic not available for semi-empirical methods"
    1553            0 :             CPABORT(TRIM(msg))
    1554              :          END IF
    1555         2152 :          matrix_t => matrix_s(1)%matrix
    1556              :       ELSE
    1557         5459 :          CPASSERT(.NOT. my_has_unit_metric)
    1558         5459 :          CALL get_qs_env(qs_env, kinetic=kinetic)
    1559         5459 :          matrix_t => kinetic(1)%matrix
    1560              :       END IF
    1561              : 
    1562              :       ! use full set of MOs or just occupied MOs
    1563         7611 :       nocc = 0
    1564         7611 :       norb = 0
    1565         7611 :       IF (my_full_mo_set) THEN
    1566           38 :          DO ispin = 1, nspins
    1567           20 :             CALL get_mo_set(mo_set=mos(ispin), homo=nocc(ispin), nmo=norb(ispin))
    1568           38 :             CALL set_mo_set(mo_set=mos(ispin), homo=norb(ispin))
    1569              :          END DO
    1570              :       END IF
    1571              :       !determines how often make preconditioner is called, spin dependent methods have to be called twice
    1572         7611 :       n_loops = 1
    1573         7611 :       IF (prec_type == ot_precond_full_single_inverse) n_loops = nspins
    1574              :       ! check whether we need the ev and rotate the MOs
    1575         2562 :       SELECT CASE (prec_type)
    1576              :       CASE (ot_precond_full_all)
    1577              :          ! FULL_ALL needs canonical occupied eigenstates and one preconditioner per spin.
    1578         2562 :          n_loops = nspins
    1579              : 
    1580         2562 :          do_co_rotate = ASSOCIATED(qs_env%mo_derivs)
    1581         5920 :          DO ispin = 1, nspins
    1582         3358 :             CALL get_mo_set(mo_set=mos(ispin), mo_coeff_b=mo_coeff_b, mo_coeff=mo_coeff)
    1583         3358 :             use_mo_coeff_b = mos(ispin)%use_mo_coeff_b
    1584         5920 :             IF (use_mo_coeff_b .AND. do_co_rotate) THEN
    1585              :                CALL calculate_subspace_eigenvalues(mo_coeff_b, matrix_ks(ispin)%matrix, &
    1586              :                                                    do_rotation=.TRUE., &
    1587              :                                                    co_rotate=qs_env%mo_derivs(ispin)%matrix, &
    1588              :                                                    para_env=para_env, &
    1589         3338 :                                                    blacs_env=blacs_env)
    1590           20 :             ELSE IF (use_mo_coeff_b) THEN
    1591              :                CALL calculate_subspace_eigenvalues(mo_coeff_b, matrix_ks(ispin)%matrix, &
    1592              :                                                    do_rotation=.TRUE., &
    1593              :                                                    para_env=para_env, &
    1594           20 :                                                    blacs_env=blacs_env)
    1595              :             ELSE
    1596              :                CALL calculate_subspace_eigenvalues(mo_coeff, matrix_ks(ispin)%matrix, &
    1597            0 :                                                    do_rotation=.TRUE.)
    1598              :             END IF
    1599              :          END DO
    1600              :       CASE (ot_precond_fermi_low_rank)
    1601              :          ! The common-reference low-rank operator depends only on the occupied projector.
    1602              :          ! Keep the input gauge unchanged so that OT ROTATION remains well defined.
    1603            6 :          n_loops = nspins
    1604              :       CASE (ot_precond_full_all_covariant)
    1605              :          ! Diagonalize a private occupied copy. The physical MOs and their
    1606              :          ! derivatives remain in the user-selected gauge.
    1607            8 :          n_loops = nspins
    1608           32 :          ALLOCATE (canonical_mos(nspins))
    1609         7627 :          DO ispin = 1, nspins
    1610            8 :             CALL duplicate_mo_set(canonical_mos(ispin), mos(ispin))
    1611            8 :             CALL get_mo_set(mo_set=canonical_mos(ispin), mo_coeff_b=mo_coeff_b, mo_coeff=mo_coeff)
    1612            8 :             IF (canonical_mos(ispin)%use_mo_coeff_b) THEN
    1613            8 :                CALL copy_dbcsr_to_fm(mo_coeff_b, mo_coeff)
    1614            8 :                canonical_mos(ispin)%use_mo_coeff_b = .FALSE.
    1615              :             END IF
    1616              :             CALL canonicalize_full_all_copy(ot_preconditioner(ispin)%preconditioner, &
    1617              :                                             mo_coeff, matrix_ks(ispin)%matrix, &
    1618           16 :                                             canonical_mos(ispin)%homo)
    1619              :          END DO
    1620              :       CASE DEFAULT
    1621              :          ! No need to rotate the MOs
    1622              :       END SELECT
    1623              : 
    1624              :       ! check whether we have a preconditioner
    1625          724 :       SELECT CASE (prec_type)
    1626              :       CASE (ot_precond_none)
    1627         1448 :          DO ispin = 1, SIZE(ot_preconditioner)
    1628         1448 :             ot_preconditioner(ispin)%preconditioner%in_use = 0
    1629              :          END DO
    1630              :       CASE DEFAULT
    1631        22636 :          DO icall = 1, n_loops
    1632         8138 :             ot_preconditioner(icall)%preconditioner%polynomial_degree = my_chebyshev_degree
    1633         8138 :             ot_preconditioner(icall)%preconditioner%low_rank_base = my_low_rank_base
    1634         8138 :             ot_preconditioner(icall)%preconditioner%lattice_fft_mode = my_lattice_fft
    1635         8138 :             ot_preconditioner(icall)%preconditioner%lattice_local_cells = my_lattice_fft_local_cells
    1636        32552 :             ot_preconditioner(icall)%preconditioner%lattice_dims = [1, 1, 1]
    1637         8138 :             IF (my_lattice_fft /= ot_lattice_fft_off) THEN
    1638           18 :                CPASSERT(ASSOCIATED(multiple_unit_cell))
    1639          144 :                ot_preconditioner(icall)%preconditioner%lattice_dims = multiple_unit_cell
    1640              :             END IF
    1641         8138 :             ot_preconditioner(icall)%preconditioner%spectral_max_rank = my_fermi_low_rank_max_rank
    1642        15025 :             IF (my_has_unit_metric) THEN
    1643          474 :                IF (use_covariant_full_all) THEN
    1644              :                   CALL make_preconditioner(ot_preconditioner(icall)%preconditioner, &
    1645              :                                            prec_type, solver_type, &
    1646              :                                            matrix_h=matrix_ks(icall)%matrix, &
    1647              :                                            mo_set=canonical_mos(icall), &
    1648              :                                            energy_gap=energy_gap, &
    1649            0 :                                            convert_precond_to_dbcsr=my_convert_to_dbcsr)
    1650              :                ELSE
    1651              :                   CALL make_preconditioner(ot_preconditioner(icall)%preconditioner, &
    1652              :                                            prec_type, solver_type, &
    1653              :                                            matrix_h=matrix_ks(icall)%matrix, &
    1654              :                                            mo_set=mos(icall), &
    1655              :                                            energy_gap=energy_gap, &
    1656          474 :                                            convert_precond_to_dbcsr=my_convert_to_dbcsr)
    1657              :                END IF
    1658              :             ELSE
    1659         7664 :                IF (use_covariant_full_all) THEN
    1660              :                   CALL make_preconditioner(ot_preconditioner(icall)%preconditioner, &
    1661              :                                            prec_type, solver_type, &
    1662              :                                            matrix_h=matrix_ks(icall)%matrix, &
    1663              :                                            matrix_s=matrix_s(1)%matrix, matrix_t=matrix_t, &
    1664              :                                            mo_set=canonical_mos(icall), &
    1665              :                                            energy_gap=energy_gap, &
    1666            8 :                                            convert_precond_to_dbcsr=my_convert_to_dbcsr, chol_type=chol_type)
    1667              :                ELSE
    1668              :                   CALL make_preconditioner(ot_preconditioner(icall)%preconditioner, &
    1669              :                                            prec_type, solver_type, &
    1670              :                                            matrix_h=matrix_ks(icall)%matrix, &
    1671              :                                            matrix_s=matrix_s(1)%matrix, matrix_t=matrix_t, &
    1672              :                                            mo_set=mos(icall), energy_gap=energy_gap, &
    1673         7656 :                                            convert_precond_to_dbcsr=my_convert_to_dbcsr, chol_type=chol_type)
    1674              :                END IF
    1675              :             END IF
    1676              :          END DO
    1677              :       END SELECT
    1678              : 
    1679         7611 :       IF (ALLOCATED(canonical_mos)) THEN
    1680           16 :          DO ispin = 1, SIZE(canonical_mos)
    1681           16 :             CALL deallocate_mo_set(canonical_mos(ispin))
    1682              :          END DO
    1683            8 :          DEALLOCATE (canonical_mos)
    1684              :       END IF
    1685              : 
    1686              :       ! reset homo values
    1687         7611 :       IF (my_full_mo_set) THEN
    1688           38 :          DO ispin = 1, nspins
    1689           38 :             CALL set_mo_set(mo_set=mos(ispin), homo=nocc(ispin))
    1690              :          END DO
    1691              :       END IF
    1692              : 
    1693         7611 :       CALL timestop(handle)
    1694              : 
    1695        15222 :    END SUBROUTINE prepare_preconditioner
    1696              : 
    1697              : ! **************************************************************************************************
    1698              : !> \brief Canonicalize an occupied copy and retain the occupied-space rotation.
    1699              : !> \param preconditioner_env ...
    1700              : !> \param mo_coeff ...
    1701              : !> \param matrix_h ...
    1702              : !> \param nocc ...
    1703              : ! **************************************************************************************************
    1704            8 :    SUBROUTINE canonicalize_full_all_copy(preconditioner_env, mo_coeff, matrix_h, nocc)
    1705              : 
    1706              :       TYPE(preconditioner_type)                          :: preconditioner_env
    1707              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
    1708              :       TYPE(dbcsr_type), POINTER                          :: matrix_h
    1709              :       INTEGER, INTENT(IN)                                :: nocc
    1710              : 
    1711              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'canonicalize_full_all_copy'
    1712              : 
    1713              :       INTEGER                                            :: handle, nao
    1714            8 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: occupied_evals
    1715              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
    1716              :       TYPE(cp_fm_type)                                   :: canonical_coeff, h_block, weighted_coeff
    1717              : 
    1718            8 :       CALL timeset(routineN, handle)
    1719            8 :       CALL cp_fm_get_info(mo_coeff, nrow_global=nao)
    1720            8 :       CPASSERT(nocc > 0)
    1721              : 
    1722              :       CALL cp_fm_struct_create(fm_struct, nrow_global=nao, ncol_global=nocc, &
    1723              :                                context=preconditioner_env%ctxt, &
    1724            8 :                                para_env=preconditioner_env%para_env)
    1725            8 :       CALL cp_fm_create(canonical_coeff, fm_struct, name=routineN)
    1726            8 :       CALL cp_fm_create(weighted_coeff, fm_struct, name=routineN)
    1727            8 :       CALL cp_fm_struct_release(fm_struct)
    1728            8 :       CALL cp_fm_to_fm(mo_coeff, canonical_coeff, nocc)
    1729              : 
    1730              :       CALL cp_fm_struct_create(fm_struct, nrow_global=nocc, ncol_global=nocc, &
    1731              :                                context=preconditioner_env%ctxt, &
    1732            8 :                                para_env=preconditioner_env%para_env)
    1733            8 :       CALL cp_fm_create(h_block, fm_struct, name=routineN)
    1734            8 :       IF (ASSOCIATED(preconditioner_env%occ_rotation_dbcsr)) THEN
    1735            0 :          CALL dbcsr_release_p(preconditioner_env%occ_rotation_dbcsr)
    1736              :       END IF
    1737            8 :       IF (ASSOCIATED(preconditioner_env%occ_rotation)) THEN
    1738            0 :          CALL cp_fm_release(preconditioner_env%occ_rotation)
    1739            0 :          DEALLOCATE (preconditioner_env%occ_rotation)
    1740              :       END IF
    1741            8 :       ALLOCATE (preconditioner_env%occ_rotation)
    1742            8 :       CALL cp_fm_create(preconditioner_env%occ_rotation, fm_struct, name="occupied rotation")
    1743            8 :       CALL cp_fm_struct_release(fm_struct)
    1744              : 
    1745            8 :       CALL cp_dbcsr_sm_fm_multiply(matrix_h, canonical_coeff, weighted_coeff, nocc)
    1746              :       CALL parallel_gemm('T', 'N', nocc, nocc, nao, 1.0_dp, canonical_coeff, &
    1747            8 :                          weighted_coeff, 0.0_dp, h_block)
    1748           24 :       ALLOCATE (occupied_evals(nocc))
    1749            8 :       CALL choose_eigv_solver(h_block, preconditioner_env%occ_rotation, occupied_evals)
    1750              : 
    1751              :       CALL parallel_gemm('N', 'N', nao, nocc, nocc, 1.0_dp, canonical_coeff, &
    1752            8 :                          preconditioner_env%occ_rotation, 0.0_dp, weighted_coeff)
    1753            8 :       CALL cp_fm_to_fm(weighted_coeff, mo_coeff, nocc, 1, 1)
    1754              : 
    1755            8 :       DEALLOCATE (occupied_evals)
    1756            8 :       CALL cp_fm_release(canonical_coeff)
    1757            8 :       CALL cp_fm_release(h_block)
    1758            8 :       CALL cp_fm_release(weighted_coeff)
    1759            8 :       CALL timestop(handle)
    1760              : 
    1761           24 :    END SUBROUTINE canonicalize_full_all_copy
    1762              : 
    1763              : END MODULE preconditioner
        

Generated by: LCOV version 2.0-1