LCOV - code coverage report
Current view: top level - src - preconditioner.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:123285f) Lines: 58.9 % 791 466
Test Date: 2026-11-04 00:58:17 Functions: 72.2 % 18 13

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

Generated by: LCOV version 2.0-1