LCOV - code coverage report
Current view: top level - src - qs_active_space_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:123285f) Lines: 78.8 % 1835 1446
Test Date: 2026-11-04 00:58:17 Functions: 75.0 % 32 24

            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 Determine active space Hamiltonian
      10              : !> \par History
      11              : !>      04.2016 created [JGH]
      12              : !> \author JGH
      13              : ! **************************************************************************************************
      14              : MODULE qs_active_space_methods
      15              :    USE admm_types, ONLY: admm_type, &
      16              :                          get_admm_env, &
      17              :                          admm_env_release
      18              :    USE atomic_kind_types, ONLY: atomic_kind_type
      19              :    USE basis_set_types, ONLY: allocate_sto_basis_set, &
      20              :                               create_gto_from_sto_basis, &
      21              :                               deallocate_sto_basis_set, &
      22              :                               gto_basis_set_type, &
      23              :                               init_orb_basis_set, &
      24              :                               set_sto_basis_set, &
      25              :                               srules, &
      26              :                               sto_basis_set_type
      27              :    USE cell_types, ONLY: cell_type, use_perd_none, use_perd_xyz
      28              :    USE cell_methods, ONLY: init_cell, set_cell_param, write_cell_low
      29              :    USE cp_blacs_env, ONLY: cp_blacs_env_type, cp_blacs_env_create, cp_blacs_env_release, BLACS_GRID_SQUARE
      30              :    USE cp_control_types, ONLY: dft_control_type, qs_control_type
      31              :    USE cp_dbcsr_operations, ONLY: cp_dbcsr_plus_fm_fm_t, &
      32              :                                   cp_dbcsr_sm_fm_multiply, &
      33              :                                   dbcsr_allocate_matrix_set, &
      34              :                                   cp_dbcsr_m_by_n_from_template, copy_dbcsr_to_fm
      35              :    USE cp_dbcsr_output, ONLY: cp_dbcsr_write_sparse_matrix
      36              :    USE cp_files, ONLY: close_file, &
      37              :                        file_exists, &
      38              :                        open_file
      39              :    USE cp_fm_basic_linalg, ONLY: cp_fm_column_scale
      40              :    USE cp_fm_struct, ONLY: cp_fm_struct_create, &
      41              :                            cp_fm_struct_release, &
      42              :                            cp_fm_struct_type
      43              :    USE cp_fm_types, ONLY: &
      44              :       cp_fm_create, cp_fm_get_element, cp_fm_get_info, cp_fm_init_random, cp_fm_release, &
      45              :       cp_fm_set_all, cp_fm_set_element, cp_fm_to_fm, cp_fm_type, cp_fm_write_formatted
      46              :    USE cp_log_handling, ONLY: cp_get_default_logger, &
      47              :                               cp_logger_get_default_io_unit, &
      48              :                               cp_logger_type
      49              :    USE cp_output_handling, ONLY: &
      50              :       cp_p_file, cp_print_key_finished_output, cp_print_key_should_output, cp_print_key_unit_nr, &
      51              :       debug_print_level, high_print_level, low_print_level, medium_print_level, &
      52              :       silent_print_level
      53              :    USE cp_realspace_grid_cube, ONLY: cp_pw_to_cube
      54              :    USE cp_dbcsr_api, ONLY: &
      55              :       dbcsr_copy, dbcsr_csr_create, dbcsr_csr_type, dbcsr_p_type, dbcsr_type, dbcsr_release, &
      56              :       dbcsr_type_no_symmetry, dbcsr_create, dbcsr_set, dbcsr_multiply, dbcsr_iterator_next_block, &
      57              :       dbcsr_iterator_start, dbcsr_iterator_stop, dbcsr_iterator_blocks_left, &
      58              :       dbcsr_iterator_type, dbcsr_type_symmetric, dbcsr_get_occupation, dbcsr_get_info
      59              :    USE erf_complex, ONLY: erfz_fast
      60              :    USE group_dist_types, ONLY: get_group_dist, release_group_dist, group_dist_d1_type
      61              :    USE input_constants, ONLY: &
      62              :       casci_canonical, eri_method_full_gpw, eri_method_gpw_ht, eri_operator_coulomb, &
      63              :       eri_operator_erf, eri_operator_erfc, eri_operator_gaussian, eri_operator_yukawa, &
      64              :       eri_operator_trunc, eri_operator_lr_trunc, &
      65              :       fci_solver, manual_selection, mao_projection, no_solver, qiskit_solver, wannier_projection, &
      66              :       eri_poisson_analytic, eri_poisson_periodic, eri_poisson_mt, high_spin_roks, &
      67              :       ot_precond_full_single_inverse, ot_precond_solver_default
      68              :    USE kpoint_types, ONLY: get_kpoint_info, kpoint_type
      69              :    USE input_section_types, ONLY: section_vals_get, section_vals_get_subs_vals, &
      70              :                                   section_vals_set_subs_vals, section_vals_type, &
      71              :                                   section_vals_val_get, &
      72              :                                   section_vals_val_set
      73              :    USE ISO_C_BINDING, ONLY: c_null_char
      74              :    USE kinds, ONLY: default_path_length, &
      75              :                     default_string_length, &
      76              :                     dp, &
      77              :                     int_8
      78              :    USE hfx_types, ONLY: hfx_create, hfx_release
      79              :    USE machine, ONLY: m_walltime, m_flush
      80              :    USE mathlib, ONLY: diamat_all
      81              :    USE mathconstants, ONLY: fourpi, twopi, pi, rootpi
      82              :    USE memory_utilities, ONLY: reallocate
      83              :    USE molden_utils, ONLY: write_mos_molden
      84              :    USE message_passing, ONLY: mp_comm_type, &
      85              :                               mp_para_env_type, &
      86              :                               mp_para_env_release
      87              :    USE mp2_gpw, ONLY: create_mat_munu, grep_rows_in_subgroups, build_dbcsr_from_rows
      88              :    USE mt_util, ONLY: MT0D
      89              :    USE parallel_gemm_api, ONLY: parallel_gemm
      90              :    USE particle_list_types, ONLY: particle_list_type
      91              :    USE particle_types, ONLY: particle_type
      92              :    USE periodic_table, ONLY: ptable
      93              :    USE physcon, ONLY: angstrom, bohr
      94              :    USE preconditioner, ONLY: make_preconditioner
      95              :    USE preconditioner_types, ONLY: destroy_preconditioner, &
      96              :                                    init_preconditioner, &
      97              :                                    preconditioner_type
      98              :    USE pw_env_methods, ONLY: pw_env_create, &
      99              :                              pw_env_rebuild
     100              :    USE pw_env_types, ONLY: pw_env_get, &
     101              :                            pw_env_release, &
     102              :                            pw_env_type
     103              :    USE pw_methods, ONLY: pw_integrate_function, &
     104              :                          pw_multiply, &
     105              :                          pw_multiply_with, &
     106              :                          pw_transfer, &
     107              :                          pw_zero, pw_integral_ab, pw_scale, &
     108              :                          pw_gauss_damp, pw_compl_gauss_damp
     109              :    USE pw_poisson_methods, ONLY: pw_poisson_rebuild, &
     110              :                                  pw_poisson_solve
     111              :    USE pw_poisson_types, ONLY: ANALYTIC0D, &
     112              :                                PERIODIC3D, &
     113              :                                greens_fn_type, &
     114              :                                pw_poisson_analytic, &
     115              :                                pw_poisson_periodic, &
     116              :                                pw_poisson_type
     117              :    USE pw_pool_types, ONLY: &
     118              :       pw_pool_type
     119              :    USE pw_types, ONLY: &
     120              :       pw_c1d_gs_type, &
     121              :       pw_r3d_rs_type
     122              :    USE qcschema, ONLY: qcschema_env_create, &
     123              :                        qcschema_env_release, &
     124              :                        qcschema_to_hdf5, &
     125              :                        qcschema_type
     126              :    USE qs_active_space_fci, ONLY: solve_active_space_fci
     127              :    USE qs_active_space_types, ONLY: active_space_type, &
     128              :                                     create_active_space_type, &
     129              :                                     csr_idx_from_combined, &
     130              :                                     csr_idx_to_combined, &
     131              :                                     eri_type, &
     132              :                                     eri_type_eri_element_func
     133              :    USE qs_active_space_mixing, ONLY: active_space_mixing_label, &
     134              :                                      initialize_active_space_mixing, &
     135              :                                      update_active_density
     136              :    USE qs_active_space_utils, ONLY: eri_to_array, &
     137              :                                     find_degenerate_splits, &
     138              :                                     subspace_matrix_to_array
     139              :    USE qs_collocate_density, ONLY: calculate_wavefunction
     140              :    USE qs_density_matrices, ONLY: calculate_density_matrix
     141              :    USE qs_energy_types, ONLY: qs_energy_type
     142              :    USE qs_environment_types, ONLY: get_qs_env, &
     143              :                                    qs_environment_type, &
     144              :                                    set_qs_env
     145              :    USE qs_integrate_potential, ONLY: integrate_v_rspace
     146              :    USE qs_kind_types, ONLY: qs_kind_type
     147              :    USE qs_ks_methods, ONLY: qs_ks_update_qs_env, qs_ks_build_kohn_sham_matrix, &
     148              :                             evaluate_core_matrix_traces
     149              :    USE qs_ks_types, ONLY: qs_ks_did_change, &
     150              :                           qs_ks_env_type, set_ks_env
     151              :    USE qs_mo_io, ONLY: write_mo_set_to_output_unit
     152              :    USE qs_mo_methods, ONLY: calculate_orbital_fock_elements, &
     153              :                             calculate_subspace_eigenvalues, &
     154              :                             make_mo_set_canonical
     155              :    USE qs_mo_types, ONLY: allocate_mo_set, &
     156              :                           deallocate_mo_set, &
     157              :                           get_mo_set, &
     158              :                           init_mo_set, &
     159              :                           mo_set_type
     160              :    USE qs_neighbor_list_types, ONLY: neighbor_list_set_p_type, release_neighbor_list_sets
     161              :    USE qs_ot_eigensolver, ONLY: ot_eigensolver
     162              :    USE qs_rho_methods, ONLY: qs_rho_update_rho
     163              :    USE qs_rho_types, ONLY: qs_rho_get, &
     164              :                            qs_rho_type
     165              :    USE qs_subsys_types, ONLY: qs_subsys_get, &
     166              :                               qs_subsys_type
     167              :    USE qs_scf_post_scf, ONLY: qs_scf_compute_properties
     168              :    USE scf_control_types, ONLY: scf_control_type
     169              : #ifndef __NO_SOCKETS
     170              :    USE sockets_interface, ONLY: accept_socket, &
     171              :                                 close_socket, &
     172              :                                 listen_socket, &
     173              :                                 open_bind_socket, &
     174              :                                 readbuffer, &
     175              :                                 remove_socket_file, &
     176              :                                 writebuffer
     177              : #endif
     178              :    USE task_list_methods, ONLY: generate_qs_task_list
     179              :    USE task_list_types, ONLY: allocate_task_list, &
     180              :                               deallocate_task_list, &
     181              :                               task_list_type
     182              :    USE util, ONLY: get_limit
     183              : #include "./base/base_uses.f90"
     184              : 
     185              :    IMPLICIT NONE
     186              :    PRIVATE
     187              : 
     188              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_active_space_methods'
     189              : 
     190              :    PUBLIC :: active_space_main
     191              : 
     192              :    TYPE, EXTENDS(eri_type_eri_element_func) :: eri_fcidump_print
     193              :       INTEGER :: unit_nr = -1, bra_start = -1, ket_start = -1
     194              :    CONTAINS
     195              :       PROCEDURE :: func => eri_fcidump_print_func
     196              :    END TYPE eri_fcidump_print
     197              : 
     198              :    TYPE, EXTENDS(eri_type_eri_element_func) :: eri_fcidump_checksum
     199              :       INTEGER :: bra_start = 0, ket_start = 0
     200              :       REAL(KIND=dp) :: checksum = 0.0_dp
     201              :    CONTAINS
     202              :       PROCEDURE, PASS :: set => eri_fcidump_set
     203              :       PROCEDURE :: func => eri_fcidump_checksum_func
     204              :    END TYPE eri_fcidump_checksum
     205              : 
     206              : CONTAINS
     207              : 
     208              : ! **************************************************************************************************
     209              : !> \brief Sets the starting indices of the bra and ket.
     210              : !> \param this object reference
     211              : !> \param bra_start starting index of the bra
     212              : !> \param ket_start starting index of the ket
     213              : ! **************************************************************************************************
     214          128 :    SUBROUTINE eri_fcidump_set(this, bra_start, ket_start)
     215              :       CLASS(eri_fcidump_checksum) :: this
     216              :       INTEGER, INTENT(IN) :: bra_start, ket_start
     217          128 :       this%bra_start = bra_start
     218          128 :       this%ket_start = ket_start
     219          128 :    END SUBROUTINE eri_fcidump_set
     220              : 
     221              : ! **************************************************************************************************
     222              : !> \brief Main method for determining the active space Hamiltonian
     223              : !> \param qs_env ...
     224              : ! **************************************************************************************************
     225        29031 :    SUBROUTINE active_space_main(qs_env)
     226              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     227              : 
     228              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'active_space_main'
     229              : 
     230              :       CHARACTER(len=10)                                  :: cshell, lnam(5)
     231              :       CHARACTER(len=default_path_length)                 :: qcschema_filename
     232              :       CHARACTER(LEN=default_string_length)               :: basis_type, kp_scheme
     233              :       INTEGER :: as_solver, eri_method, eri_operator, eri_print, group_size, handle, i, iatom, &
     234              :          ishell, isp, ispin, iw, j, jm, m, max_orb_ind, mselect, n1, n2, nao, natom, nel, &
     235              :          nelec_active, nelec_inactive, nelec_total, nkp, nmo, nmo_active, nmo_available, &
     236              :          nmo_inactive, nmo_inactive_remaining, nmo_occ, nmo_virtual, nn1, nn2, nrow_global, nspins
     237              :       INTEGER, DIMENSION(5)                              :: nshell
     238        29031 :       INTEGER, DIMENSION(:), POINTER                     :: invals
     239              :       LOGICAL                                            :: do_ddapc, do_kpoints, ex_omega, &
     240              :                                                             ex_operator, ex_perd, ex_rcut, &
     241              :                                                             explicit, stop_after_print, store_wfn, &
     242              :                                                             use_real_wfn
     243              :       REAL(KIND=dp) :: eri_eps_filter, eri_eps_grid, eri_eps_int, eri_gpw_cutoff, eri_op_omega, &
     244              :          eri_rcut, eri_rel_cutoff, fel, focc, max_offdiag, maxocc, nze_percentage
     245        29031 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: eigenvalues
     246        29031 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: evals_virtual
     247              :       TYPE(active_space_type), POINTER                   :: active_space_env
     248        29031 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     249              :       TYPE(cell_type), POINTER                           :: cell
     250              :       TYPE(cp_blacs_env_type), POINTER                   :: context
     251              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     252              :       TYPE(cp_fm_type)                                   :: mo_virtual
     253              :       TYPE(cp_fm_type), POINTER                          :: fm_target_active, fm_target_inactive, &
     254              :                                                             fmat, mo_coeff, mo_ref, mo_target
     255              :       TYPE(cp_logger_type), POINTER                      :: logger
     256              :       TYPE(dbcsr_csr_type), POINTER                      :: eri_mat
     257        58062 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: ks_matrix, rho_ao, s_matrix
     258        58062 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: ks_matrix_kp, rho_ao_kp, s_matrix_kp
     259              :       TYPE(dbcsr_type), POINTER                          :: denmat
     260              :       TYPE(dft_control_type), POINTER                    :: dft_control
     261              :       TYPE(kpoint_type), POINTER                         :: kpoints
     262        29031 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     263              :       TYPE(mo_set_type), POINTER                         :: mo_set, mo_set_active, mo_set_inactive
     264              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     265        29031 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     266              :       TYPE(preconditioner_type), POINTER                 :: local_preconditioner
     267       116124 :       TYPE(qcschema_type)                                :: qcschema_env
     268              :       TYPE(qs_energy_type), POINTER                      :: energy
     269        29031 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     270              :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
     271              :       TYPE(qs_rho_type), POINTER                         :: rho
     272              :       TYPE(scf_control_type), POINTER                    :: scf_control
     273              :       TYPE(section_vals_type), POINTER                   :: adiabatic_rescaling, as_input, &
     274              :                                                             hfx_section, input, loc_print, &
     275              :                                                             loc_section, print_orb, xc_section
     276              : 
     277              :       !--------------------------------------------------------------------------------------------!
     278              : 
     279        29031 :       CALL get_qs_env(qs_env, input=input)
     280        29031 :       as_input => section_vals_get_subs_vals(input, "DFT%ACTIVE_SPACE")
     281        29031 :       CALL section_vals_get(as_input, explicit=explicit)
     282        29031 :       IF (.NOT. explicit) RETURN
     283          108 :       CALL timeset(routineN, handle)
     284              : 
     285          108 :       logger => cp_get_default_logger()
     286          108 :       iw = cp_logger_get_default_io_unit(logger)
     287              : 
     288          108 :       IF (iw > 0) THEN
     289              :          WRITE (iw, '(/,T2,A)') &
     290           54 :             '!-----------------------------------------------------------------------------!'
     291           54 :          WRITE (iw, '(T26,A)') "Active Space Embedding Module"
     292              :          WRITE (iw, '(T2,A)') &
     293           54 :             '!-----------------------------------------------------------------------------!'
     294              :       END IF
     295              : 
     296              :       ! k-points?
     297          108 :       NULLIFY (kpoints)
     298          108 :       CALL get_qs_env(qs_env, do_kpoints=do_kpoints, dft_control=dft_control, kpoints=kpoints)
     299          108 :       IF (do_kpoints) THEN
     300            2 :          IF (.NOT. ASSOCIATED(kpoints)) THEN
     301            0 :             CALL cp_abort(__LOCATION__, "Missing Gamma-point environment for active space module")
     302              :          END IF
     303            2 :          CALL get_kpoint_info(kpoints, kp_scheme=kp_scheme, nkp=nkp, use_real_wfn=use_real_wfn)
     304            2 :          IF (TRIM(kp_scheme) /= "GAMMA" .OR. nkp /= 1 .OR. .NOT. use_real_wfn) THEN
     305              :             CALL cp_abort(__LOCATION__, &
     306            0 :                           "Only Gamma-point DFT%KPOINTS are supported in the active space module")
     307              :          END IF
     308            2 :          IF (.NOT. ASSOCIATED(kpoints%kp_env)) THEN
     309            0 :             CALL cp_abort(__LOCATION__, "Missing Gamma-point environment for active space module")
     310              :          END IF
     311            2 :          IF (.NOT. ASSOCIATED(kpoints%kp_env(1)%kpoint_env)) THEN
     312            0 :             CALL cp_abort(__LOCATION__, "Missing Gamma-point environment for active space module")
     313              :          END IF
     314            2 :          IF (.NOT. ASSOCIATED(kpoints%kp_env(1)%kpoint_env%mos)) THEN
     315            0 :             CALL cp_abort(__LOCATION__, "Missing Gamma-point MOs for active space module")
     316              :          END IF
     317              :       END IF
     318              : 
     319              :       ! adiabatic rescaling?
     320          108 :       adiabatic_rescaling => section_vals_get_subs_vals(input, "DFT%XC%ADIABATIC_RESCALING")
     321          108 :       CALL section_vals_get(adiabatic_rescaling, explicit=explicit)
     322          108 :       IF (explicit) THEN
     323            0 :          CALL cp_abort(__LOCATION__, "Adiabatic rescaling not supported in active space module")
     324              :       END IF
     325              : 
     326              :       ! Setup the possible usage of DDAPC charges
     327              :       do_ddapc = dft_control%qs_control%ddapc_restraint .OR. &
     328              :                  qs_env%cp_ddapc_ewald%do_decoupling .OR. &
     329              :                  qs_env%cp_ddapc_ewald%do_qmmm_periodic_decpl .OR. &
     330          108 :                  qs_env%cp_ddapc_ewald%do_solvation
     331              :       IF (do_ddapc) THEN
     332            0 :          CALL cp_abort(__LOCATION__, "DDAPC charges are not supported in the active space module")
     333              :       END IF
     334          108 :       IF (dft_control%do_sccs) THEN
     335            0 :          CALL cp_abort(__LOCATION__, "SCCS is not supported in the active space module")
     336              :       END IF
     337          108 :       IF (dft_control%correct_surf_dip) THEN
     338            0 :          IF (dft_control%surf_dip_correct_switch) THEN
     339            0 :             CALL cp_abort(__LOCATION__, "Surface dipole correction not supported in the AS module")
     340              :          END IF
     341              :       END IF
     342          108 :       IF (dft_control%smeagol_control%smeagol_enabled) THEN
     343            0 :          CALL cp_abort(__LOCATION__, "SMEAGOL is not supported in the active space module")
     344              :       END IF
     345          108 :       IF (dft_control%qs_control%do_kg) THEN
     346            0 :          CALL cp_abort(__LOCATION__, "KG correction not supported in the active space module")
     347              :       END IF
     348              : 
     349          108 :       NULLIFY (active_space_env)
     350          108 :       CALL create_active_space_type(active_space_env)
     351          108 :       active_space_env%energy_total = 0.0_dp
     352          108 :       active_space_env%energy_ref = 0.0_dp
     353          108 :       active_space_env%energy_inactive = 0.0_dp
     354          108 :       active_space_env%energy_active = 0.0_dp
     355              : 
     356              :       ! input options
     357              : 
     358          108 :       CALL section_vals_val_get(as_input, "EPS_FCI", r_val=active_space_env%eps_fci)
     359          108 :       IF (.NOT. (active_space_env%eps_fci > 0.0_dp)) THEN
     360            0 :          CPABORT("ACTIVE_SPACE%EPS_FCI must be positive.")
     361              :       END IF
     362              : 
     363              :       ! figure out what needs to be printed/stored
     364          108 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, as_input, "FCIDUMP"), cp_p_file)) THEN
     365          104 :          active_space_env%fcidump = .TRUE.
     366              :       END IF
     367              : 
     368          108 :       CALL section_vals_val_get(as_input, "QCSCHEMA", c_val=qcschema_filename, explicit=explicit)
     369          108 :       IF (explicit) THEN
     370            6 :          active_space_env%qcschema = .TRUE.
     371            6 :          active_space_env%qcschema_filename = qcschema_filename
     372              :       END IF
     373              : 
     374          108 :       CALL section_vals_val_get(as_input, "ACTIVE_ELECTRONS", i_val=nelec_active)
     375          108 :       CALL get_qs_env(qs_env, nelectron_total=nelec_total)
     376              : 
     377          108 :       IF (nelec_active <= 0) CPABORT("Specify a positive number of active electrons.")
     378          108 :       IF (nelec_active > nelec_total) CPABORT("More active electrons than total electrons.")
     379              : 
     380          108 :       nelec_inactive = nelec_total - nelec_active
     381          108 :       IF (MOD(nelec_inactive, 2) /= 0) THEN
     382            0 :          CPABORT("The remaining number of inactive electrons has to be even.")
     383              :       END IF
     384              : 
     385          108 :       IF (iw > 0) THEN
     386           54 :          WRITE (iw, '(T3,A,T70,I10)') "Total number of electrons", nelec_total
     387           54 :          WRITE (iw, '(T3,A,T70,I10)') "Number of inactive electrons", nelec_inactive
     388           54 :          WRITE (iw, '(T3,A,T70,I10)') "Number of active electrons", nelec_active
     389              :       END IF
     390              : 
     391          108 :       CALL get_qs_env(qs_env, dft_control=dft_control)
     392          108 :       nspins = dft_control%nspins
     393              : 
     394          108 :       active_space_env%nelec_active = nelec_active
     395          108 :       active_space_env%nelec_inactive = nelec_inactive
     396          108 :       active_space_env%nelec_total = nelec_total
     397          108 :       active_space_env%nspins = nspins
     398          108 :       active_space_env%multiplicity = dft_control%multiplicity
     399          108 :       active_space_env%restricted_orbitals = dft_control%roks
     400              : 
     401              :       ! define the active/inactive space orbitals
     402          108 :       CALL section_vals_val_get(as_input, "ACTIVE_ORBITALS", explicit=explicit, i_val=nmo_active)
     403          108 :       IF (.NOT. explicit) THEN
     404            0 :          CALL cp_abort(__LOCATION__, "Number of Active Orbitals has to be specified.")
     405              :       END IF
     406          108 :       active_space_env%nmo_active = nmo_active
     407              :       ! this is safe because nelec_inactive is always even
     408          108 :       nmo_inactive = nelec_inactive/2
     409          108 :       active_space_env%nmo_inactive = nmo_inactive
     410              : 
     411          108 :       CALL initialize_active_space_mixing(active_space_env, as_input)
     412              : 
     413          108 :       CALL section_vals_val_get(as_input, "ORBITAL_SELECTION", i_val=mselect)
     414          108 :       IF (iw > 0) THEN
     415            0 :          SELECT CASE (mselect)
     416              :          CASE DEFAULT
     417            0 :             CPABORT("Unknown orbital selection method")
     418              :          CASE (casci_canonical)
     419              :             WRITE (iw, '(/,T3,A)') &
     420           39 :                "Active space orbitals selected using energy ordered canonical orbitals"
     421              :          CASE (wannier_projection)
     422              :             WRITE (iw, '(/,T3,A)') &
     423            0 :                "Active space orbitals selected using projected Wannier orbitals"
     424              :          CASE (mao_projection)
     425              :             WRITE (iw, '(/,T3,A)') &
     426            0 :                "Active space orbitals selected using modified atomic orbitals (MAO)"
     427              :          CASE (manual_selection)
     428              :             WRITE (iw, '(/,T3,A)') &
     429           54 :                "Active space orbitals selected manually"
     430              :          END SELECT
     431              : 
     432           54 :          WRITE (iw, '(T3,A,T70,I10)') "Number of inactive orbitals", nmo_inactive
     433           54 :          WRITE (iw, '(T3,A,T70,I10)') "Number of active orbitals", nmo_active
     434              :       END IF
     435              : 
     436              :       ! get projection spaces
     437          108 :       CALL section_vals_val_get(as_input, "SUBSPACE_ATOM", i_val=iatom, explicit=explicit)
     438          108 :       IF (explicit) THEN
     439            0 :          CALL get_qs_env(qs_env, natom=natom)
     440            0 :          IF (iatom <= 0 .OR. iatom > natom) THEN
     441            0 :             IF (iw > 0) THEN
     442            0 :                WRITE (iw, '(/,T3,A,I3)') "ERROR: SUBSPACE_ATOM number is not valid", iatom
     443              :             END IF
     444            0 :             CPABORT("Select a valid SUBSPACE_ATOM")
     445              :          END IF
     446              :       END IF
     447          108 :       CALL section_vals_val_get(as_input, "SUBSPACE_SHELL", c_val=cshell, explicit=explicit)
     448          108 :       nshell = 0
     449          648 :       lnam = ""
     450          108 :       IF (explicit) THEN
     451            0 :          cshell = ADJUSTL(cshell)
     452            0 :          n1 = 1
     453            0 :          DO i = 1, 5
     454            0 :             ishell = i
     455            0 :             IF (cshell(n1:n1) == " ") THEN
     456          108 :                ishell = ishell - 1
     457              :                EXIT
     458              :             END IF
     459            0 :             READ (cshell(n1:), "(I1,A1)") nshell(i), lnam(i)
     460            0 :             n1 = n1 + 2
     461              :          END DO
     462              :       END IF
     463              : 
     464              :       ! generate orbitals
     465            0 :       SELECT CASE (mselect)
     466              :       CASE DEFAULT
     467            0 :          CPABORT("Unknown orbital selection method")
     468              :       CASE (casci_canonical)
     469           78 :          IF (do_kpoints) THEN
     470            2 :             mos => kpoints%kp_env(1)%kpoint_env%mos(:)
     471              :          ELSE
     472           76 :             CALL get_qs_env(qs_env, mos=mos)
     473              :          END IF
     474              : 
     475              :          ! total number of occupied orbitals, i.e. inactive plus active MOs
     476           78 :          nmo_occ = nmo_inactive + nmo_active
     477              : 
     478              :          ! set inactive orbital indices, these are trivially 1...nmo_inactive
     479          260 :          ALLOCATE (active_space_env%inactive_orbitals(nmo_inactive, nspins))
     480          166 :          DO ispin = 1, nspins
     481          238 :             DO i = 1, nmo_inactive
     482          160 :                active_space_env%inactive_orbitals(i, ispin) = i
     483              :             END DO
     484              :          END DO
     485              : 
     486              :          ! set active orbital indices, these are shifted by nmo_inactive
     487          312 :          ALLOCATE (active_space_env%active_orbitals(nmo_active, nspins))
     488          166 :          DO ispin = 1, nspins
     489          432 :             DO i = 1, nmo_active
     490          354 :                active_space_env%active_orbitals(i, ispin) = nmo_inactive + i
     491              :             END DO
     492              :          END DO
     493              : 
     494              :          ! allocate and initialize inactive and active mo coefficients.
     495              :          ! These are stored in a data structure for the full occupied space:
     496              :          ! for inactive mos, the active subset is set to zero, vice versa for the active mos
     497              :          ! TODO: allocate data structures only for the eaxct number MOs
     498           78 :          maxocc = 2.0_dp
     499           78 :          IF (nspins > 1) maxocc = 1.0_dp
     500          322 :          ALLOCATE (active_space_env%mos_active(nspins))
     501          244 :          ALLOCATE (active_space_env%mos_inactive(nspins))
     502          166 :          DO ispin = 1, nspins
     503           88 :             CALL get_mo_set(mos(ispin), mo_coeff=mo_ref, nao=nao)
     504           88 :             CALL cp_fm_get_info(mo_ref, context=context, para_env=para_env, nrow_global=nrow_global)
     505              :             ! the right number of active electrons per spin channel is initialized further down
     506           88 :             CALL allocate_mo_set(active_space_env%mos_active(ispin), nao, nmo_occ, 0, 0.0_dp, maxocc, 0.0_dp)
     507              :             CALL cp_fm_struct_create(fm_struct_tmp, para_env=para_env, context=context, &
     508           88 :                                      nrow_global=nrow_global, ncol_global=nmo_occ)
     509           88 :             CALL init_mo_set(active_space_env%mos_active(ispin), fm_struct=fm_struct_tmp, name="Active Space MO")
     510           88 :             CALL cp_fm_struct_release(fm_struct_tmp)
     511           88 :             IF (nspins == 2) THEN
     512           20 :                nel = nelec_inactive/2
     513              :             ELSE
     514           68 :                nel = nelec_inactive
     515              :             END IF
     516              :             CALL allocate_mo_set(active_space_env%mos_inactive(ispin), nao, nmo_occ, nel, &
     517           88 :                                  REAL(nel, KIND=dp), maxocc, 0.0_dp)
     518              :             CALL cp_fm_struct_create(fm_struct_tmp, para_env=para_env, context=context, &
     519           88 :                                      nrow_global=nrow_global, ncol_global=nmo_occ)
     520           88 :             CALL init_mo_set(active_space_env%mos_inactive(ispin), fm_struct=fm_struct_tmp, name="Inactive Space MO")
     521          254 :             CALL cp_fm_struct_release(fm_struct_tmp)
     522              :          END DO
     523              : 
     524              :          ! create canonical orbitals
     525           78 :          CALL get_qs_env(qs_env, scf_control=scf_control)
     526           78 :          IF (dft_control%roks .AND. scf_control%roks_scheme /= high_spin_roks) THEN
     527              :             CALL cp_abort(__LOCATION__, &
     528              :                           "Only high-spin ROKS is supported for ACTIVE_SPACE FCI; "// &
     529            0 :                           "general ROKS MO definitions are not implemented.")
     530              :          ELSE
     531           78 :             IF (dft_control%do_admm) THEN
     532            0 :                IF (dft_control%do_admm_mo) THEN
     533            0 :                   CPABORT("ADMM currently possible only with purification none_dm")
     534              :                END IF
     535              :             END IF
     536              : 
     537          312 :             ALLOCATE (eigenvalues(nmo_occ, nspins))
     538           78 :             eigenvalues = 0.0_dp
     539           78 :             IF (do_kpoints) THEN
     540              :                CALL get_qs_env(qs_env, matrix_ks_kp=ks_matrix_kp, matrix_s_kp=s_matrix_kp, &
     541            2 :                                scf_control=scf_control)
     542            2 :                ks_matrix => ks_matrix_kp(:, 1)
     543            2 :                s_matrix => s_matrix_kp(:, 1)
     544              :             ELSE
     545           76 :                CALL get_qs_env(qs_env, matrix_ks=ks_matrix, matrix_s=s_matrix, scf_control=scf_control)
     546              :             END IF
     547              : 
     548              :             ! calculate virtual MOs and copy inactive and active orbitals
     549           78 :             IF (iw > 0) THEN
     550           39 :                WRITE (iw, '(/,T3,A)') "Calculating virtual MOs..."
     551              :             END IF
     552          166 :             DO ispin = 1, nspins
     553              :                ! the selection needs canonical SCF orbitals (e.g. not after OT)
     554              :                CALL ensure_canonical_orbitals(qs_env, mos(ispin), ks_matrix(ispin)%matrix, ispin, &
     555           88 :                                               .FALSE., do_kpoints, iw)
     556              :                ! nmo_available is the number of MOs available from the SCF calculation:
     557              :                ! this is at least the number of occupied orbitals in the SCF, plus
     558              :                ! any number of added MOs (virtuals) requested in the SCF section
     559           88 :                CALL get_mo_set(mos(ispin), mo_coeff=mo_ref, nmo=nmo_available)
     560              : 
     561              :                ! calculate how many extra MOs we still have to compute
     562           88 :                nmo_virtual = nmo_occ - nmo_available
     563           88 :                nmo_virtual = MAX(nmo_virtual, 0)
     564              : 
     565              :                NULLIFY (evals_virtual)
     566          178 :                ALLOCATE (evals_virtual(nmo_virtual))
     567              : 
     568              :                CALL cp_fm_get_info(mo_ref, context=context, para_env=para_env, &
     569           88 :                                    nrow_global=nrow_global)
     570              : 
     571              :                CALL cp_fm_struct_create(fm_struct_tmp, para_env=para_env, context=context, &
     572           88 :                                         nrow_global=nrow_global, ncol_global=nmo_virtual)
     573           88 :                CALL cp_fm_create(mo_virtual, fm_struct_tmp, name="virtual")
     574           88 :                CALL cp_fm_struct_release(fm_struct_tmp)
     575           88 :                CALL cp_fm_init_random(mo_virtual, nmo_virtual)
     576              : 
     577              :                ! compute missing virtual MOs
     578              :                CALL virtual_orbital_preconditioner(local_preconditioner, mos(ispin), ks_matrix(ispin)%matrix, &
     579           88 :                                                    s_matrix(1)%matrix, nmo_virtual, para_env, context)
     580              :                CALL ot_eigensolver(matrix_h=ks_matrix(ispin)%matrix, matrix_s=s_matrix(1)%matrix, &
     581              :                                    matrix_c_fm=mo_virtual, matrix_orthogonal_space_fm=mo_ref, &
     582              :                                    eps_gradient=scf_control%eps_lumos, &
     583              :                                    preconditioner=local_preconditioner, &
     584              :                                    iter_max=scf_control%max_iter_lumos, &
     585           88 :                                    size_ortho_space=nmo_available)
     586           88 :                IF (ASSOCIATED(local_preconditioner)) THEN
     587            2 :                   CALL destroy_preconditioner(local_preconditioner)
     588            2 :                   DEALLOCATE (local_preconditioner)
     589              :                END IF
     590              : 
     591              :                ! get the eigenvalues
     592           88 :                CALL calculate_subspace_eigenvalues(mo_virtual, ks_matrix(ispin)%matrix, evals_virtual)
     593              : 
     594              :                ! orbital energies <i|F|i> of the SCF orbitals, which are used unchanged
     595              :                CALL calculate_orbital_fock_elements(mo_ref, ks_matrix(ispin)%matrix, &
     596           88 :                                                     eigenvalues(:, ispin), max_offdiag)
     597              : 
     598              :                ! copy inactive orbitals
     599           88 :                mo_set => active_space_env%mos_inactive(ispin)
     600           88 :                CALL get_mo_set(mo_set, mo_coeff=mo_target)
     601          160 :                DO i = 1, SIZE(active_space_env%inactive_orbitals, 1)
     602           72 :                   m = active_space_env%inactive_orbitals(i, ispin)
     603           72 :                   CALL cp_fm_to_fm(mo_ref, mo_target, 1, m, m)
     604           72 :                   mo_set%eigenvalues(m) = eigenvalues(m, ispin)
     605          160 :                   IF (nspins > 1) THEN
     606           28 :                      mo_set%occupation_numbers(m) = 1.0_dp
     607              :                   ELSE
     608           44 :                      mo_set%occupation_numbers(m) = 2.0_dp
     609              :                   END IF
     610              :                END DO
     611              : 
     612              :                ! copy active orbitals
     613           88 :                mo_set => active_space_env%mos_active(ispin)
     614           88 :                CALL get_mo_set(mo_set, mo_coeff=mo_target)
     615              :                ! for mult > 1, put the polarized electrons in the alpha channel
     616           88 :                IF (nspins == 2) THEN
     617           20 :                   IF (ispin == 1) THEN
     618           10 :                      nel = (nelec_active + active_space_env%multiplicity - 1)/2
     619              :                   ELSE
     620           10 :                      nel = (nelec_active - active_space_env%multiplicity + 1)/2
     621              :                   END IF
     622              :                ELSE
     623           68 :                   nel = nelec_active
     624              :                END IF
     625           88 :                mo_set%nelectron = nel
     626           88 :                mo_set%n_el_f = REAL(nel, KIND=dp)
     627          354 :                DO i = 1, nmo_active
     628          266 :                   m = active_space_env%active_orbitals(i, ispin)
     629          266 :                   IF (m > nmo_available) THEN
     630            8 :                      CALL cp_fm_to_fm(mo_virtual, mo_target, 1, m - nmo_available, m)
     631            8 :                      eigenvalues(m, ispin) = evals_virtual(m - nmo_available)
     632            8 :                      mo_set%occupation_numbers(m) = 0.0_dp
     633              :                   ELSE
     634          258 :                      CALL cp_fm_to_fm(mo_ref, mo_target, 1, m, m)
     635          258 :                      mo_set%occupation_numbers(m) = mos(ispin)%occupation_numbers(m)
     636              :                   END IF
     637          354 :                   mo_set%eigenvalues(m) = eigenvalues(m, ispin)
     638              :                END DO
     639              :                ! Release
     640           88 :                DEALLOCATE (evals_virtual)
     641          430 :                CALL cp_fm_release(mo_virtual)
     642              :             END DO
     643              : 
     644           78 :             IF (iw > 0) THEN
     645           83 :                DO ispin = 1, nspins
     646           44 :                   WRITE (iw, '(/,T3,A,I3,T66,A)') "Canonical Orbital Selection for spin", ispin, &
     647           88 :                      "[atomic units]"
     648           60 :                   DO i = 1, nmo_inactive, 4
     649           16 :                      jm = MIN(3, nmo_inactive - i)
     650           96 :                      WRITE (iw, '(T3,4(F14.6,A5))') (eigenvalues(i + j, ispin), " [I]", j=0, jm)
     651              :                   END DO
     652           93 :                   DO i = nmo_inactive + 1, nmo_inactive + nmo_active, 4
     653           49 :                      jm = MIN(3, nmo_inactive + nmo_active - i)
     654          226 :                      WRITE (iw, '(T3,4(F14.6,A5))') (eigenvalues(i + j, ispin), " [A]", j=0, jm)
     655              :                   END DO
     656           44 :                   WRITE (iw, '(/,T3,A,I3)') "Active Orbital Indices for spin", ispin
     657          132 :                   DO i = 1, SIZE(active_space_env%active_orbitals, 1), 4
     658           49 :                      jm = MIN(3, SIZE(active_space_env%active_orbitals, 1) - i)
     659          226 :                      WRITE (iw, '(T3,4(I4))') (active_space_env%active_orbitals(i + j, ispin), j=0, jm)
     660              :                   END DO
     661              :                END DO
     662              :             END IF
     663           78 :             DEALLOCATE (eigenvalues)
     664              :          END IF
     665              : 
     666              :       CASE (manual_selection)
     667              :          ! create canonical orbitals
     668           30 :          IF (dft_control%roks) THEN
     669              :             CALL cp_abort(__LOCATION__, &
     670              :                           "Manual ACTIVE_SPACE orbital selection is not supported for ROKS; "// &
     671            0 :                           "use canonical high-spin ROKS.")
     672              :          ELSE
     673           30 :             IF (dft_control%do_admm) THEN
     674              :                ! For admm_mo, the auxiliary density is computed from the MOs, which never change
     675              :                ! in the rs-dft embedding, therefore the energy is wrong as the LR HFX never changes.
     676              :                ! For admm_dm, the auxiliary density is computed from the density matrix, which is
     677              :                ! updated at each iteration and therefore works.
     678            0 :                IF (dft_control%do_admm_mo) THEN
     679            0 :                   CPABORT("ADMM currently possible only with purification none_dm")
     680              :                END IF
     681              :             END IF
     682              : 
     683           30 :             CALL section_vals_val_get(as_input, "ACTIVE_ORBITAL_INDICES", explicit=explicit, i_vals=invals)
     684           30 :             IF (.NOT. explicit) THEN
     685              :                CALL cp_abort(__LOCATION__, "Manual orbital selection requires to explicitly "// &
     686            0 :                              "set the active orbital indices via ACTIVE_ORBITAL_INDICES")
     687              :             END IF
     688              : 
     689           30 :             IF (nspins == 1) THEN
     690           22 :                CPASSERT(SIZE(invals) == nmo_active)
     691              :             ELSE
     692            8 :                CPASSERT(SIZE(invals) == 2*nmo_active)
     693              :             END IF
     694          104 :             ALLOCATE (active_space_env%inactive_orbitals(nmo_inactive, nspins))
     695          120 :             ALLOCATE (active_space_env%active_orbitals(nmo_active, nspins))
     696              : 
     697           68 :             DO ispin = 1, nspins
     698          180 :                DO i = 1, nmo_active
     699          150 :                   active_space_env%active_orbitals(i, ispin) = invals(i + (ispin - 1)*nmo_active)
     700              :                END DO
     701              :             END DO
     702              : 
     703           30 :             IF (do_kpoints) THEN
     704            0 :                mos => kpoints%kp_env(1)%kpoint_env%mos(:)
     705              :             ELSE
     706           30 :                CALL get_qs_env(qs_env, mos=mos)
     707              :             END IF
     708              : 
     709              :             ! include MOs up to the largest index in the list
     710          142 :             max_orb_ind = MAXVAL(invals)
     711           30 :             maxocc = 2.0_dp
     712           30 :             IF (nspins > 1) maxocc = 1.0_dp
     713          128 :             ALLOCATE (active_space_env%mos_active(nspins))
     714           98 :             ALLOCATE (active_space_env%mos_inactive(nspins))
     715           68 :             DO ispin = 1, nspins
     716              :                ! init active orbitals
     717           38 :                CALL get_mo_set(mos(ispin), mo_coeff=mo_ref, nao=nao)
     718           38 :                CALL cp_fm_get_info(mo_ref, context=context, para_env=para_env, nrow_global=nrow_global)
     719           38 :                CALL allocate_mo_set(active_space_env%mos_active(ispin), nao, max_orb_ind, 0, 0.0_dp, maxocc, 0.0_dp)
     720              :                CALL cp_fm_struct_create(fm_struct_tmp, para_env=para_env, context=context, &
     721           38 :                                         nrow_global=nrow_global, ncol_global=max_orb_ind)
     722           38 :                CALL init_mo_set(active_space_env%mos_active(ispin), fm_struct=fm_struct_tmp, name="Active Space MO")
     723           38 :                CALL cp_fm_struct_release(fm_struct_tmp)
     724              : 
     725              :                ! init inactive orbitals
     726           38 :                IF (nspins == 2) THEN
     727           16 :                   nel = nelec_inactive/2
     728              :                ELSE
     729           22 :                   nel = nelec_inactive
     730              :                END IF
     731           38 :                CALL allocate_mo_set(active_space_env%mos_inactive(ispin), nao, max_orb_ind, nel, REAL(nel, KIND=dp), maxocc, 0.0_dp)
     732              :                CALL cp_fm_struct_create(fm_struct_tmp, para_env=para_env, context=context, &
     733           38 :                                         nrow_global=nrow_global, ncol_global=max_orb_ind)
     734           38 :                CALL init_mo_set(active_space_env%mos_inactive(ispin), fm_struct=fm_struct_tmp, name="Inactive Space MO")
     735              :                ! small hack: set the correct inactive occupations down below
     736          186 :                active_space_env%mos_inactive(ispin)%occupation_numbers = 0.0_dp
     737          106 :                CALL cp_fm_struct_release(fm_struct_tmp)
     738              :             END DO
     739              : 
     740          120 :             ALLOCATE (eigenvalues(max_orb_ind, nspins))
     741           30 :             eigenvalues = 0.0_dp
     742           30 :             IF (do_kpoints) THEN
     743              :                CALL get_qs_env(qs_env, matrix_ks_kp=ks_matrix_kp, matrix_s_kp=s_matrix_kp, &
     744            0 :                                scf_control=scf_control)
     745            0 :                ks_matrix => ks_matrix_kp(:, 1)
     746            0 :                s_matrix => s_matrix_kp(:, 1)
     747              :             ELSE
     748           30 :                CALL get_qs_env(qs_env, matrix_ks=ks_matrix, matrix_s=s_matrix, scf_control=scf_control)
     749              :             END IF
     750              : 
     751              :             ! calculate virtual MOs and copy inactive and active orbitals
     752           30 :             IF (iw > 0) THEN
     753           15 :                WRITE (iw, '(/,T3,A)') "Calculating virtual MOs..."
     754              :             END IF
     755           68 :             DO ispin = 1, nspins
     756              :                ! the orbital indices refer to canonical SCF orbitals (e.g. not after OT)
     757              :                CALL ensure_canonical_orbitals(qs_env, mos(ispin), ks_matrix(ispin)%matrix, ispin, &
     758           38 :                                               .TRUE., do_kpoints, iw)
     759           38 :                CALL get_mo_set(mos(ispin), mo_coeff=mo_ref, nmo=nmo_available)
     760           38 :                nmo_virtual = max_orb_ind - nmo_available
     761           38 :                nmo_virtual = MAX(nmo_virtual, 0)
     762              : 
     763              :                NULLIFY (evals_virtual)
     764           78 :                ALLOCATE (evals_virtual(nmo_virtual))
     765              : 
     766              :                CALL cp_fm_get_info(mo_ref, context=context, para_env=para_env, &
     767           38 :                                    nrow_global=nrow_global)
     768              : 
     769              :                CALL cp_fm_struct_create(fm_struct_tmp, para_env=para_env, context=context, &
     770           38 :                                         nrow_global=nrow_global, ncol_global=nmo_virtual)
     771           38 :                CALL cp_fm_create(mo_virtual, fm_struct_tmp, name="virtual")
     772           38 :                CALL cp_fm_struct_release(fm_struct_tmp)
     773           38 :                CALL cp_fm_init_random(mo_virtual, nmo_virtual)
     774              : 
     775              :                CALL virtual_orbital_preconditioner(local_preconditioner, mos(ispin), ks_matrix(ispin)%matrix, &
     776           38 :                                                    s_matrix(1)%matrix, nmo_virtual, para_env, context)
     777              :                CALL ot_eigensolver(matrix_h=ks_matrix(ispin)%matrix, matrix_s=s_matrix(1)%matrix, &
     778              :                                    matrix_c_fm=mo_virtual, matrix_orthogonal_space_fm=mo_ref, &
     779              :                                    eps_gradient=scf_control%eps_lumos, &
     780              :                                    preconditioner=local_preconditioner, &
     781              :                                    iter_max=scf_control%max_iter_lumos, &
     782           38 :                                    size_ortho_space=nmo_available)
     783           38 :                IF (ASSOCIATED(local_preconditioner)) THEN
     784            2 :                   CALL destroy_preconditioner(local_preconditioner)
     785            2 :                   DEALLOCATE (local_preconditioner)
     786              :                END IF
     787              : 
     788              :                CALL calculate_subspace_eigenvalues(mo_virtual, ks_matrix(ispin)%matrix, &
     789           38 :                                                    evals_virtual)
     790              : 
     791              :                ! orbital energies <i|F|i> of the SCF orbitals, which are used unchanged
     792              :                CALL calculate_orbital_fock_elements(mo_ref, ks_matrix(ispin)%matrix, &
     793           38 :                                                     eigenvalues(:, ispin), max_offdiag)
     794              : 
     795           38 :                mo_set_active => active_space_env%mos_active(ispin)
     796           38 :                CALL get_mo_set(mo_set_active, mo_coeff=fm_target_active)
     797           38 :                mo_set_inactive => active_space_env%mos_inactive(ispin)
     798           38 :                CALL get_mo_set(mo_set_inactive, mo_coeff=fm_target_inactive)
     799              : 
     800              :                ! copy orbitals
     801           38 :                nmo_inactive_remaining = nmo_inactive
     802          186 :                DO i = 1, max_orb_ind
     803              :                   ! case for i being an active orbital
     804          454 :                   IF (ANY(active_space_env%active_orbitals(:, ispin) == i)) THEN
     805          112 :                      IF (i > nmo_available) THEN
     806            8 :                         CALL cp_fm_to_fm(mo_virtual, fm_target_active, 1, i - nmo_available, i)
     807            8 :                         eigenvalues(i, ispin) = evals_virtual(i - nmo_available)
     808            8 :                         mo_set_active%occupation_numbers(i) = 0.0_dp
     809              :                      ELSE
     810          104 :                         CALL cp_fm_to_fm(mo_ref, fm_target_active, 1, i, i)
     811          104 :                         mo_set_active%occupation_numbers(i) = mos(ispin)%occupation_numbers(i)
     812              :                      END IF
     813          112 :                      mo_set_active%eigenvalues(i) = eigenvalues(i, ispin)
     814              :                      ! if it was not an active orbital, check whether it is an inactive orbital
     815           36 :                   ELSE IF (nmo_inactive_remaining > 0) THEN
     816           20 :                      CALL cp_fm_to_fm(mo_ref, fm_target_inactive, 1, i, i)
     817              :                      ! store on the fly the mapping of inactive orbitals
     818           20 :                      active_space_env%inactive_orbitals(nmo_inactive - nmo_inactive_remaining + 1, ispin) = i
     819           20 :                      mo_set_inactive%eigenvalues(i) = eigenvalues(i, ispin)
     820           20 :                      mo_set_inactive%occupation_numbers(i) = mos(ispin)%occupation_numbers(i)
     821              :                      ! hack: set homo and lumo manually
     822           20 :                      IF (nmo_inactive_remaining == 1) THEN
     823            8 :                         mo_set_inactive%homo = i
     824            8 :                         mo_set_inactive%lfomo = i + 1
     825              :                      END IF
     826           20 :                      nmo_inactive_remaining = nmo_inactive_remaining - 1
     827              :                   ELSE
     828           16 :                      CYCLE
     829              :                   END IF
     830              :                END DO
     831              : 
     832              :                ! Release
     833           38 :                DEALLOCATE (evals_virtual)
     834          182 :                CALL cp_fm_release(mo_virtual)
     835              :             END DO
     836              : 
     837           30 :             IF (iw > 0) THEN
     838           34 :                DO ispin = 1, nspins
     839           19 :                   WRITE (iw, '(/,T3,A,I3,T66,A)') "Orbital Energies and Selection for spin", ispin, "[atomic units]"
     840              : 
     841           42 :                   DO i = 1, max_orb_ind, 4
     842           23 :                      jm = MIN(3, max_orb_ind - i)
     843           23 :                      WRITE (iw, '(T4)', advance="no")
     844           97 :                      DO j = 0, jm
     845          231 :                         IF (ANY(active_space_env%active_orbitals(:, ispin) == i + j)) THEN
     846           56 :                            WRITE (iw, '(T3,F12.6,A5)', advance="no") eigenvalues(i + j, ispin), " [A]"
     847           23 :                         ELSE IF (ANY(active_space_env%inactive_orbitals(:, ispin) == i + j)) THEN
     848           10 :                            WRITE (iw, '(T3,F12.6,A5)', advance="no") eigenvalues(i + j, ispin), " [I]"
     849              :                         ELSE
     850            8 :                            WRITE (iw, '(T3,F12.6,A5)', advance="no") eigenvalues(i + j, ispin), " [V]"
     851              :                         END IF
     852              :                      END DO
     853           42 :                      WRITE (iw, *)
     854              :                   END DO
     855           19 :                   WRITE (iw, '(/,T3,A,I3)') "Active Orbital Indices for spin", ispin
     856           56 :                   DO i = 1, SIZE(active_space_env%active_orbitals, 1), 4
     857           22 :                      jm = MIN(3, SIZE(active_space_env%active_orbitals, 1) - i)
     858           97 :                      WRITE (iw, '(T3,4(I4))') (active_space_env%active_orbitals(i + j, ispin), j=0, jm)
     859              :                   END DO
     860              :                END DO
     861              :             END IF
     862           60 :             DEALLOCATE (eigenvalues)
     863              :          END IF
     864              : 
     865              :       CASE (wannier_projection)
     866            0 :          NULLIFY (loc_section, loc_print)
     867            0 :          loc_section => section_vals_get_subs_vals(as_input, "LOCALIZE")
     868            0 :          CPASSERT(ASSOCIATED(loc_section))
     869            0 :          loc_print => section_vals_get_subs_vals(as_input, "LOCALIZE%PRINT")
     870              :          !
     871            0 :          CPABORT("not yet available")
     872              :          !
     873              :       CASE (mao_projection)
     874              :          !
     875          108 :          CPABORT("not yet available")
     876              :          !
     877              :       END SELECT
     878              : 
     879              :       ! Warn if the active space splits a set of degenerate orbitals
     880          108 :       CALL check_active_space_degeneracy(active_space_env, mos)
     881              : 
     882              :       ! Print orbitals on Cube files
     883          108 :       print_orb => section_vals_get_subs_vals(as_input, "PRINT_ORBITAL_CUBES")
     884          108 :       CALL section_vals_get(print_orb, explicit=explicit)
     885          108 :       CALL section_vals_val_get(print_orb, "STOP_AFTER_CUBES", l_val=stop_after_print)
     886          108 :       IF (explicit) THEN
     887              :          !
     888            4 :          CALL print_orbital_cubes(print_orb, qs_env, active_space_env%mos_active)
     889              :          !
     890            4 :          IF (stop_after_print) THEN
     891              : 
     892            0 :             IF (iw > 0) THEN
     893              :                WRITE (iw, '(/,T2,A)') &
     894            0 :                   '!----------------- Early End of Active Space Interface -----------------------!'
     895              :             END IF
     896              : 
     897            0 :             CALL timestop(handle)
     898              : 
     899            0 :             RETURN
     900              :          END IF
     901              :       END IF
     902              : 
     903              :       ! calculate inactive density matrix
     904          108 :       CALL get_qs_env(qs_env, rho=rho)
     905          108 :       IF (do_kpoints) THEN
     906            2 :          CALL qs_rho_get(rho, rho_ao_kp=rho_ao_kp)
     907            2 :          rho_ao => rho_ao_kp(:, 1)
     908              :       ELSE
     909          106 :          CALL qs_rho_get(rho, rho_ao=rho_ao)
     910              :       END IF
     911          108 :       CPASSERT(ASSOCIATED(rho_ao))
     912          108 :       CALL dbcsr_allocate_matrix_set(active_space_env%pmat_inactive, nspins)
     913          234 :       DO ispin = 1, nspins
     914          126 :          ALLOCATE (denmat)
     915          126 :          CALL dbcsr_copy(denmat, rho_ao(ispin)%matrix)
     916          126 :          mo_set => active_space_env%mos_inactive(ispin)
     917          126 :          CALL calculate_density_matrix(mo_set, denmat)
     918          234 :          active_space_env%pmat_inactive(ispin)%matrix => denmat
     919              :       END DO
     920              : 
     921              :       ! read in ERI parameters
     922          108 :       CALL section_vals_val_get(as_input, "ERI%METHOD", i_val=eri_method)
     923          108 :       active_space_env%eri%method = eri_method
     924          108 :       CALL section_vals_val_get(as_input, "ERI%OPERATOR", i_val=eri_operator, explicit=ex_operator)
     925          108 :       active_space_env%eri%operator = eri_operator
     926          108 :       CALL section_vals_val_get(as_input, "ERI%OMEGA", r_val=eri_op_omega, explicit=ex_omega)
     927          108 :       active_space_env%eri%omega = eri_op_omega
     928          108 :       CALL section_vals_val_get(as_input, "ERI%CUTOFF_RADIUS", r_val=eri_rcut, explicit=ex_rcut)
     929          108 :       active_space_env%eri%cutoff_radius = eri_rcut  ! this is already converted to bohr!
     930          108 :       CALL section_vals_val_get(as_input, "ERI%PERIODICITY", i_vals=invals, explicit=ex_perd)
     931          108 :       CALL section_vals_val_get(as_input, "ERI%EPS_INTEGRAL", r_val=eri_eps_int)
     932          108 :       active_space_env%eri%eps_integral = eri_eps_int
     933              :       ! if eri periodicity is explicitly set, we use it, otherwise we use the cell periodicity
     934          108 :       IF (ex_perd) THEN
     935           96 :          IF (SIZE(invals) == 1) THEN
     936            0 :             active_space_env%eri%periodicity(1:3) = invals(1)
     937              :          ELSE
     938          672 :             active_space_env%eri%periodicity(1:3) = invals(1:3)
     939              :          END IF
     940              :       ELSE
     941           12 :          CALL get_qs_env(qs_env, cell=cell)
     942           84 :          active_space_env%eri%periodicity(1:3) = cell%perd(1:3)
     943              :       END IF
     944          108 :       IF (iw > 0) THEN
     945           54 :          WRITE (iw, '(/,T3,A)') "Calculation of Electron Repulsion Integrals"
     946              : 
     947           46 :          SELECT CASE (eri_method)
     948              :          CASE (eri_method_full_gpw)
     949           46 :             WRITE (iw, '(T3,A,T50,A)') "Integration method", "GPW Fourier transform over MOs"
     950              :          CASE (eri_method_gpw_ht)
     951            8 :             WRITE (iw, '(T3,A,T44,A)') "Integration method", "Half transformed integrals from GPW"
     952              :          CASE DEFAULT
     953           54 :             CPABORT("Unknown ERI method")
     954              :          END SELECT
     955              : 
     956           44 :          SELECT CASE (eri_operator)
     957              :          CASE (eri_operator_coulomb)
     958           44 :             WRITE (iw, '(T3,A,T73,A)') "ERI operator", "Coulomb"
     959              : 
     960              :          CASE (eri_operator_yukawa)
     961            0 :             WRITE (iw, '(T3,A,T74,A)') "ERI operator", "Yukawa"
     962            0 :             IF (.NOT. ex_omega) CALL cp_abort(__LOCATION__, &
     963            0 :                                               "Yukawa operator requires OMEGA to be explicitly set")
     964            0 :             WRITE (iw, '(T3,A,T66,F14.3)') "ERI operator parameter OMEGA", eri_op_omega
     965              : 
     966              :          CASE (eri_operator_erf)
     967            8 :             WRITE (iw, '(T3,A,T63,A)') "ERI operator", "Longrange Coulomb"
     968            8 :             IF (.NOT. ex_omega) CALL cp_abort(__LOCATION__, &
     969            0 :                                               "Longrange operator requires OMEGA to be explicitly set")
     970            8 :             WRITE (iw, '(T3,A,T66,F14.3)') "ERI operator parameter OMEGA", eri_op_omega
     971              : 
     972              :          CASE (eri_operator_erfc)
     973            0 :             WRITE (iw, '(T3,A,T62,A)') "ERI operator", "Shortrange Coulomb"
     974            0 :             IF (.NOT. ex_omega) CALL cp_abort(__LOCATION__, &
     975            0 :                                               "Shortrange operator requires OMEGA to be explicitly set")
     976            0 :             WRITE (iw, '(T3,A,T66,F14.3)') "ERI operator parameter OMEGA", eri_op_omega
     977              : 
     978              :          CASE (eri_operator_trunc)
     979            0 :             WRITE (iw, '(T3,A,T63,A)') "ERI operator", "Truncated Coulomb"
     980            0 :             IF (.NOT. ex_rcut) CALL cp_abort(__LOCATION__, &
     981            0 :                                              "Cutoff radius not specified for trunc. Coulomb operator")
     982            0 :             WRITE (iw, '(T3,A,T66,F14.3)') "ERI operator cutoff radius (au)", eri_rcut
     983              : 
     984              :          CASE (eri_operator_lr_trunc)
     985            2 :             WRITE (iw, '(T3,A,T53,A)') "ERI operator", "Longrange truncated Coulomb"
     986            2 :             IF (.NOT. ex_rcut) CALL cp_abort(__LOCATION__, &
     987            0 :                                              "Cutoff radius not specified for trunc. longrange operator")
     988            2 :             WRITE (iw, '(T3,A,T66,F14.3)') "ERI operator cutoff radius (au)", eri_rcut
     989            2 :             IF (.NOT. ex_omega) CALL cp_abort(__LOCATION__, &
     990            0 :                                               "LR truncated operator requires OMEGA to be explicitly set")
     991            2 :             WRITE (iw, '(T3,A,T66,F14.3)') "ERI operator parameter OMEGA", eri_op_omega
     992            2 :             IF (eri_op_omega < 0.01_dp) THEN
     993            0 :                CPABORT("LR truncated operator requires OMEGA >= 0.01 to be stable")
     994              :             END IF
     995              : 
     996              :          CASE DEFAULT
     997           54 :             CPABORT("Unknown ERI operator")
     998              : 
     999              :          END SELECT
    1000              : 
    1001           54 :          WRITE (iw, '(T3,A,T68,E12.4)') "Accuracy of ERIs", eri_eps_int
    1002          216 :          WRITE (iw, '(T3,A,T71,3I3)') "Periodicity", active_space_env%eri%periodicity(1:3)
    1003              : 
    1004              :          ! TODO: should be moved after ERI calculation, as it depends on screening
    1005           54 :          IF (nspins < 2) THEN
    1006           45 :             WRITE (iw, '(T3,A,T68,I12)') "Total Number of ERI", (nmo_active**4)/8
    1007              :          ELSE
    1008            9 :             WRITE (iw, '(T3,A,T68,I12)') "Total Number of ERI (aa|aa)", (nmo_active**4)/8
    1009            9 :             WRITE (iw, '(T3,A,T68,I12)') "Total Number of ERI (bb|bb)", (nmo_active**4)/8
    1010            9 :             WRITE (iw, '(T3,A,T68,I12)') "Total Number of ERI (aa|bb)", (nmo_active**4)/4
    1011              :          END IF
    1012              :       END IF
    1013              : 
    1014              :       ! allocate container for integrals (CSR matrix)
    1015          108 :       CALL get_qs_env(qs_env, para_env=para_env)
    1016          108 :       m = (nspins*(nspins + 1))/2
    1017              :       ! With ROHF/ROKS, we need ERIs from only a single set of orbitals
    1018          108 :       IF (dft_control%roks) m = 1
    1019          460 :       ALLOCATE (active_space_env%eri%eri(m))
    1020          244 :       DO i = 1, m
    1021          136 :          CALL get_mo_set(active_space_env%mos_active(1), nmo=nmo)
    1022          136 :          ALLOCATE (active_space_env%eri%eri(i)%csr_mat)
    1023          136 :          eri_mat => active_space_env%eri%eri(i)%csr_mat
    1024          136 :          IF (i == 1) THEN
    1025          108 :             n1 = nmo
    1026          108 :             n2 = nmo
    1027           28 :          ELSE IF (i == 2) THEN
    1028           14 :             n1 = nmo
    1029           14 :             n2 = nmo
    1030              :          ELSE
    1031           14 :             n1 = nmo
    1032           14 :             n2 = nmo
    1033              :          END IF
    1034          136 :          nn1 = (n1*(n1 + 1))/2
    1035          136 :          nn2 = (n2*(n2 + 1))/2
    1036          136 :          CALL dbcsr_csr_create(eri_mat, nn1, nn2, 0_int_8, 0, 0, para_env%get_handle())
    1037          380 :          active_space_env%eri%norb = nmo
    1038              :       END DO
    1039              : 
    1040          108 :       SELECT CASE (eri_method)
    1041              :       CASE (eri_method_full_gpw, eri_method_gpw_ht)
    1042          108 :          CALL section_vals_val_get(as_input, "ERI_GPW%EPS_GRID", r_val=eri_eps_grid)
    1043          108 :          active_space_env%eri%eri_gpw%eps_grid = eri_eps_grid
    1044          108 :          CALL section_vals_val_get(as_input, "ERI_GPW%EPS_FILTER", r_val=eri_eps_filter)
    1045          108 :          active_space_env%eri%eri_gpw%eps_filter = eri_eps_filter
    1046          108 :          CALL section_vals_val_get(as_input, "ERI_GPW%CUTOFF", r_val=eri_gpw_cutoff)
    1047          108 :          active_space_env%eri%eri_gpw%cutoff = eri_gpw_cutoff
    1048          108 :          CALL section_vals_val_get(as_input, "ERI_GPW%REL_CUTOFF", r_val=eri_rel_cutoff)
    1049          108 :          active_space_env%eri%eri_gpw%rel_cutoff = eri_rel_cutoff
    1050          108 :          CALL section_vals_val_get(as_input, "ERI_GPW%PRINT_LEVEL", i_val=eri_print)
    1051          108 :          active_space_env%eri%eri_gpw%print_level = eri_print
    1052          108 :          CALL section_vals_val_get(as_input, "ERI_GPW%STORE_WFN", l_val=store_wfn)
    1053          108 :          active_space_env%eri%eri_gpw%store_wfn = store_wfn
    1054          108 :          CALL section_vals_val_get(as_input, "ERI_GPW%GROUP_SIZE", i_val=group_size)
    1055          108 :          active_space_env%eri%eri_gpw%group_size = group_size
    1056              :          ! Always redo Poisson solver for now
    1057          108 :          active_space_env%eri%eri_gpw%redo_poisson = .TRUE.
    1058              :          ! active_space_env%eri%eri_gpw%redo_poisson = (ex_operator .OR. ex_perd)
    1059          108 :          IF (iw > 0) THEN
    1060           54 :             WRITE (iw, '(/,T2,A,T71,F10.1)') "ERI_GPW| Energy cutoff [Ry]", eri_gpw_cutoff
    1061           54 :             WRITE (iw, '(T2,A,T71,F10.1)') "ERI_GPW| Relative energy cutoff [Ry]", eri_rel_cutoff
    1062              :          END IF
    1063              :          !
    1064              :          CALL calculate_eri_gpw(active_space_env%mos_active, active_space_env%active_orbitals, active_space_env%eri, qs_env, iw, &
    1065          108 :                                 dft_control%roks)
    1066              :          !
    1067              :       CASE DEFAULT
    1068          108 :          CPABORT("Unknown ERI method")
    1069              :       END SELECT
    1070          108 :       IF (iw > 0) THEN
    1071          122 :          DO isp = 1, SIZE(active_space_env%eri%eri)
    1072           68 :             eri_mat => active_space_env%eri%eri(isp)%csr_mat
    1073              :             nze_percentage = 100.0_dp*(REAL(eri_mat%nze_total, KIND=dp) &
    1074           68 :                                        /REAL(eri_mat%nrows_total, KIND=dp))/REAL(eri_mat%ncols_total, KIND=dp)
    1075           68 :             WRITE (iw, '(/,T2,A,I2,T30,A,T68,I12)') "ERI_GPW| Spinmatrix:", isp, &
    1076          136 :                "Number of  CSR non-zero elements:", eri_mat%nze_total
    1077           68 :             WRITE (iw, '(T2,A,I2,T30,A,T68,F12.4)') "ERI_GPW| Spinmatrix:", isp, &
    1078          136 :                "Percentage CSR non-zero elements:", nze_percentage
    1079           68 :             WRITE (iw, '(T2,A,I2,T30,A,T68,I12)') "ERI_GPW| Spinmatrix:", isp, &
    1080          136 :                "nrows_total", eri_mat%nrows_total
    1081           68 :             WRITE (iw, '(T2,A,I2,T30,A,T68,I12)') "ERI_GPW| Spinmatrix:", isp, &
    1082          136 :                "ncols_total", eri_mat%ncols_total
    1083           68 :             WRITE (iw, '(T2,A,I2,T30,A,T68,I12)') "ERI_GPW| Spinmatrix:", isp, &
    1084          190 :                "nrows_local", eri_mat%nrows_local
    1085              :          END DO
    1086           54 :          CALL m_flush(iw)
    1087              :       END IF
    1088          108 :       CALL para_env%sync()
    1089              : 
    1090              :       ! set the reference active space density matrix
    1091          108 :       nspins = active_space_env%nspins
    1092          450 :       ALLOCATE (active_space_env%p_active(nspins))
    1093          234 :       DO isp = 1, nspins
    1094          126 :          mo_set => active_space_env%mos_active(isp)
    1095          126 :          CALL get_mo_set(mo_set, mo_coeff=mo_coeff, nmo=nmo)
    1096          234 :          CALL create_subspace_matrix(mo_coeff, active_space_env%p_active(isp), nmo)
    1097              :       END DO
    1098            0 :       SELECT CASE (mselect)
    1099              :       CASE DEFAULT
    1100            0 :          CPABORT("Unknown orbital selection method")
    1101              :       CASE (casci_canonical, manual_selection)
    1102          108 :          focc = 2.0_dp
    1103          108 :          IF (nspins == 2) focc = 1.0_dp
    1104          234 :          DO isp = 1, nspins
    1105          126 :             fmat => active_space_env%p_active(isp)
    1106          126 :             CALL cp_fm_set_all(fmat, alpha=0.0_dp)
    1107          126 :             IF (nspins == 2) THEN
    1108           36 :                IF (isp == 1) THEN
    1109           18 :                   nel = (active_space_env%nelec_active + active_space_env%multiplicity - 1)/2
    1110              :                ELSE
    1111           18 :                   nel = (active_space_env%nelec_active - active_space_env%multiplicity + 1)/2
    1112              :                END IF
    1113              :             ELSE
    1114           90 :                nel = active_space_env%nelec_active
    1115              :             END IF
    1116          612 :             DO i = 1, nmo_active
    1117          378 :                m = active_space_env%active_orbitals(i, isp)
    1118          378 :                fel = MIN(focc, REAL(nel, KIND=dp))
    1119          378 :                CALL cp_fm_set_element(fmat, m, m, fel)
    1120          378 :                nel = nel - NINT(fel)
    1121          504 :                nel = MAX(nel, 0)
    1122              :             END DO
    1123              :          END DO
    1124              :       CASE (wannier_projection)
    1125            0 :          CPABORT("NOT IMPLEMENTED")
    1126              :       CASE (mao_projection)
    1127          108 :          CPABORT("NOT IMPLEMENTED")
    1128              :       END SELECT
    1129              : 
    1130              :       ! compute alpha-beta overlap matrix in case of spin-polarized calculation
    1131          108 :       CALL calculate_spin_pol_overlap(active_space_env%mos_active, qs_env, active_space_env)
    1132              : 
    1133              :       ! figure out if we have a new xc section for the AS
    1134          108 :       xc_section => section_vals_get_subs_vals(input, "DFT%ACTIVE_SPACE%XC")
    1135          108 :       explicit = .FALSE.
    1136          108 :       IF (ASSOCIATED(xc_section)) CALL section_vals_get(xc_section, explicit=explicit)
    1137              : 
    1138              :       ! rebuild KS matrix if needed
    1139          108 :       IF (explicit) THEN
    1140              :          ! release the hfx data if it was part of the SCF functional
    1141            2 :          IF (ASSOCIATED(qs_env%x_data)) CALL hfx_release(qs_env%x_data)
    1142              :          ! also release the admm environment in case we are using admm
    1143            2 :          IF (ASSOCIATED(qs_env%admm_env)) CALL admm_env_release(qs_env%admm_env)
    1144              : 
    1145              :          CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, qs_kind_set=qs_kind_set, &
    1146            2 :                          particle_set=particle_set, cell=cell, ks_env=ks_env)
    1147            2 :          IF (dft_control%do_admm) THEN
    1148            0 :             basis_type = 'AUX_FIT'
    1149              :          ELSE
    1150            2 :             basis_type = 'ORB'
    1151              :          END IF
    1152            2 :          hfx_section => section_vals_get_subs_vals(xc_section, "HF")
    1153              :          CALL hfx_create(qs_env%x_data, para_env, hfx_section, atomic_kind_set, &
    1154              :                          qs_kind_set, particle_set, dft_control, cell, orb_basis=basis_type, &
    1155            2 :                          nelectron_total=nelec_total)
    1156              : 
    1157            2 :          qs_env%requires_matrix_vxc = .TRUE.  ! needs to be set only once
    1158              : 
    1159              :          ! a bit of a hack: this forces a new re-init of HFX
    1160            2 :          CALL set_ks_env(ks_env, s_mstruct_changed=.TRUE.)
    1161              :          CALL qs_ks_build_kohn_sham_matrix(qs_env, calculate_forces=.FALSE., &
    1162              :                                            just_energy=.FALSE., &
    1163            2 :                                            ext_xc_section=xc_section)
    1164              :          ! we need to reset it to false
    1165            2 :          CALL set_ks_env(ks_env, s_mstruct_changed=.FALSE.)
    1166              :       ELSE
    1167          106 :          xc_section => section_vals_get_subs_vals(input, "DFT%XC")
    1168              :       END IF
    1169              :       ! set the xc_section
    1170          108 :       active_space_env%xc_section => xc_section
    1171              : 
    1172          108 :       CALL get_qs_env(qs_env, energy=energy)
    1173              :       ! transform KS/Fock, Vxc and Hcore to AS MO basis
    1174          108 :       CALL calculate_operators(active_space_env%mos_active, qs_env, active_space_env)
    1175              :       ! set the reference energy in the active space
    1176          108 :       active_space_env%energy_ref = energy%total
    1177              :       ! calculate inactive energy and embedding potential
    1178          108 :       CALL subspace_fock_matrix(active_space_env, dft_control%roks)
    1179              : 
    1180              :       ! associate the active space environment with the qs environment
    1181          108 :       CALL set_qs_env(qs_env, active_space=active_space_env)
    1182              : 
    1183              :       ! Perform the embedding calculation when an active-space solver is specified
    1184          108 :       CALL section_vals_val_get(as_input, "AS_SOLVER", i_val=as_solver)
    1185          102 :       SELECT CASE (as_solver)
    1186              :       CASE (no_solver)
    1187          102 :          IF (iw > 0) THEN
    1188           51 :             WRITE (iw, '(/,T3,A)') "No active space solver specified, skipping embedding calculation"
    1189           51 :             CALL m_flush(iw)
    1190              :          END IF
    1191          102 :          CALL para_env%sync()
    1192              :       CASE (qiskit_solver)
    1193            0 :          CALL rsdft_embedding(qs_env, active_space_env, as_input)
    1194            0 :          CALL qs_scf_compute_properties(qs_env, wf_type="MC-DFT", do_mp2=.FALSE.)
    1195              :       CASE (fci_solver)
    1196            6 :          CALL local_fci_embedding(qs_env, active_space_env, as_input)
    1197            6 :          CALL qs_scf_compute_properties(qs_env, wf_type="MC-DFT", do_mp2=.FALSE.)
    1198              :       CASE DEFAULT
    1199          108 :          CPABORT("Unknown active space solver")
    1200              :       END SELECT
    1201              : 
    1202              :       ! Output a FCIDUMP file if requested
    1203          108 :       IF (active_space_env%fcidump) CALL fcidump(active_space_env, as_input, dft_control%roks)
    1204              : 
    1205              :       ! Output the inactive and active orbitals in FCIDUMP order as a Molden file if requested
    1206          108 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, as_input, "MOLDEN"), cp_p_file)) THEN
    1207            2 :          CALL write_active_space_molden(qs_env, active_space_env, as_input)
    1208              :       END IF
    1209              : 
    1210              :       ! Output a QCSchema file if requested
    1211          108 :       IF (active_space_env%qcschema) THEN
    1212            6 :          CALL qcschema_env_create(qcschema_env, qs_env)
    1213            6 :          CALL qcschema_to_hdf5(qcschema_env, active_space_env%qcschema_filename)
    1214            6 :          CALL qcschema_env_release(qcschema_env)
    1215              :       END IF
    1216              : 
    1217          108 :       IF (iw > 0) THEN
    1218              :          WRITE (iw, '(/,T2,A)') &
    1219           54 :             '!-------------------- End of Active Space Interface --------------------------!'
    1220           54 :          CALL m_flush(iw)
    1221              :       END IF
    1222          108 :       CALL para_env%sync()
    1223              : 
    1224          108 :       CALL timestop(handle)
    1225              : 
    1226       117312 :    END SUBROUTINE active_space_main
    1227              : 
    1228              : ! **************************************************************************************************
    1229              : !> \brief Makes sure that the SCF orbitals used for the orbital selection are canonical. Orbitals
    1230              : !>        of a diagonalization SCF are left unchanged; non-canonical orbitals (OT) are rotated in
    1231              : !>        place once, separately within the occupied and the virtual orbitals (determinant
    1232              : !>        unchanged), together with the DBCSR copy and the OT orbital derivatives, so that later
    1233              : !>        users of the SCF orbitals see the same orbitals. The orbitals are left untouched for
    1234              : !>        k-points and ROKS (diagonalization only) and for orbitals localized on the fly in OT
    1235              : !>        (ON_THE_FLY_LOC), where MANUAL indices refer to the localized orbitals.
    1236              : !> \param qs_env the QS environment
    1237              : !> \param mo_set the SCF orbitals of one spin
    1238              : !> \param ks_matrix Kohn-Sham or Fock matrix of that spin
    1239              : !> \param ispin spin index
    1240              : !> \param manual MANUAL orbital selection (else CANONICAL)
    1241              : !> \param do_kpoints k-point calculation
    1242              : !> \param iw output unit (> 0 on the I/O node)
    1243              : ! **************************************************************************************************
    1244          126 :    SUBROUTINE ensure_canonical_orbitals(qs_env, mo_set, ks_matrix, ispin, manual, do_kpoints, iw)
    1245              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1246              :       TYPE(mo_set_type), INTENT(INOUT)                   :: mo_set
    1247              :       TYPE(dbcsr_type), POINTER                          :: ks_matrix
    1248              :       INTEGER, INTENT(IN)                                :: ispin
    1249              :       LOGICAL, INTENT(IN)                                :: manual, do_kpoints
    1250              :       INTEGER, INTENT(IN)                                :: iw
    1251              : 
    1252              :       LOGICAL                                            :: on_the_fly_loc, rotated
    1253              :       REAL(KIND=dp)                                      :: eps_canonical, max_offdiag
    1254          126 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: energies
    1255          126 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: mo_derivs
    1256              :       TYPE(dbcsr_type), POINTER                          :: mo_deriv
    1257              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1258              :       TYPE(scf_control_type), POINTER                    :: scf_control
    1259              :       TYPE(section_vals_type), POINTER                   :: input
    1260              : 
    1261              :       ! k-point SCF and ROKS use diagonalization; ROKS orbitals are canonical with respect to the
    1262              :       ! ROKS Fock matrix and not to the spin Fock matrices, so the test below does not apply
    1263          116 :       IF (do_kpoints) RETURN
    1264          124 :       NULLIFY (dft_control, input, mo_derivs, mo_deriv, scf_control)
    1265              :       CALL get_qs_env(qs_env, dft_control=dft_control, scf_control=scf_control, input=input, &
    1266          124 :                       mo_derivs=mo_derivs)
    1267          124 :       IF (dft_control%roks) RETURN
    1268              : 
    1269              :       ! a converged diagonalization SCF leaves off-diagonal elements of the order of EPS_SCF
    1270          116 :       eps_canonical = MAX(1.0E-4_dp, 100.0_dp*scf_control%eps_scf)
    1271          116 :       IF (mo_set%use_mo_coeff_b) CALL copy_dbcsr_to_fm(mo_set%mo_coeff_b, mo_set%mo_coeff)
    1272          348 :       ALLOCATE (energies(mo_set%nmo))
    1273          116 :       CALL calculate_orbital_fock_elements(mo_set%mo_coeff, ks_matrix, energies, max_offdiag)
    1274          116 :       DEALLOCATE (energies)
    1275          116 :       IF (max_offdiag <= eps_canonical) THEN
    1276          156 :          IF (iw > 0) WRITE (iw, '(/,T3,A,I0,A,ES9.2,A)') "SCF orbitals of spin ", ispin, &
    1277          104 :             " are canonical (max |<i|F|j>| = ", max_offdiag, ")"
    1278          104 :          RETURN
    1279              :       END IF
    1280              : 
    1281           12 :       on_the_fly_loc = .FALSE.
    1282           12 :       IF (scf_control%use_ot) CALL section_vals_val_get(input, "DFT%SCF%OT%ON_THE_FLY_LOC", l_val=on_the_fly_loc)
    1283           12 :       IF (on_the_fly_loc) THEN
    1284            2 :          IF (.NOT. manual) THEN
    1285              :             CALL cp_abort(__LOCATION__, &
    1286              :                           "ORBITAL_SELECTION CANONICAL needs canonical orbitals, but the "// &
    1287              :                           "SCF orbitals are localized (ON_THE_FLY_LOC). Use ORBITAL_SELECTION MANUAL "// &
    1288            0 :                           "to select localized orbitals, or switch off ON_THE_FLY_LOC.")
    1289              :          END IF
    1290            3 :          IF (iw > 0) WRITE (iw, '(/,T3,A,I0,A)') "SCF orbitals of spin ", ispin, &
    1291            2 :             " are localized (ON_THE_FLY_LOC): ACTIVE_ORBITAL_INDICES refer to the localized orbitals"
    1292            2 :          RETURN
    1293              :       END IF
    1294              : 
    1295           10 :       IF (ASSOCIATED(mo_derivs)) THEN
    1296           10 :          IF (SIZE(mo_derivs) >= ispin) mo_deriv => mo_derivs(ispin)%matrix
    1297              :       END IF
    1298           10 :       CALL make_mo_set_canonical(mo_set, ks_matrix, eps_canonical, rotated, max_offdiag, mo_deriv)
    1299           10 :       IF (iw > 0) THEN
    1300            5 :          WRITE (iw, '(/,T3,A,I0,A,ES9.2,A)') "SCF orbitals of spin ", ispin, &
    1301           10 :             " are not canonical (max |<i|F|j>| = ", max_offdiag, ")"
    1302            5 :          WRITE (iw, '(T3,A)') "Rotated into canonical orbitals, separately for occupied and virtual orbitals"
    1303              :       END IF
    1304              : 
    1305          366 :    END SUBROUTINE ensure_canonical_orbitals
    1306              : 
    1307              : ! **************************************************************************************************
    1308              : !> \brief Preconditioner (FULL_SINGLE_INVERSE) for the OT eigensolver that computes the virtual
    1309              : !>        orbitals not available from the SCF; without it the eigensolver hardly converges.
    1310              : !> \param preconditioner the preconditioner, not associated if no virtual orbitals are needed
    1311              : !> \param mo_set the SCF orbitals of one spin
    1312              : !> \param ks_matrix Kohn-Sham or Fock matrix of that spin
    1313              : !> \param s_matrix overlap matrix
    1314              : !> \param nmo_virtual number of virtual orbitals to compute
    1315              : !> \param para_env ...
    1316              : !> \param blacs_env ...
    1317              : ! **************************************************************************************************
    1318          126 :    SUBROUTINE virtual_orbital_preconditioner(preconditioner, mo_set, ks_matrix, s_matrix, nmo_virtual, &
    1319              :                                              para_env, blacs_env)
    1320              :       TYPE(preconditioner_type), POINTER                 :: preconditioner
    1321              :       TYPE(mo_set_type), INTENT(IN)                      :: mo_set
    1322              :       TYPE(dbcsr_type), POINTER                          :: ks_matrix, s_matrix
    1323              :       INTEGER, INTENT(IN)                                :: nmo_virtual
    1324              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1325              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    1326              : 
    1327          126 :       NULLIFY (preconditioner)
    1328          126 :       IF (nmo_virtual <= 0) RETURN
    1329           16 :       ALLOCATE (preconditioner)
    1330            4 :       CALL init_preconditioner(preconditioner, para_env=para_env, blacs_env=blacs_env)
    1331              :       CALL make_preconditioner(preconditioner, precon_type=ot_precond_full_single_inverse, &
    1332              :                                solver_type=ot_precond_solver_default, matrix_h=ks_matrix, &
    1333              :                                matrix_s=s_matrix, convert_precond_to_dbcsr=.TRUE., &
    1334            4 :                                mo_set=mo_set, energy_gap=0.2_dp)
    1335              : 
    1336              :    END SUBROUTINE virtual_orbital_preconditioner
    1337              : 
    1338              : ! **************************************************************************************************
    1339              : !> \brief Warns if active and non-active orbitals are degenerate, i.e. if the active space
    1340              : !>        splits a set of degenerate orbitals. The orbitals of such a set are only defined up
    1341              : !>        to rotations within the set, so the active space is not uniquely defined.
    1342              : !> \param active_space_env the active space environment
    1343              : !> \param mos the SCF orbitals with their eigenvalues
    1344              : ! **************************************************************************************************
    1345          108 :    SUBROUTINE check_active_space_degeneracy(active_space_env, mos)
    1346              :       TYPE(active_space_type), POINTER                   :: active_space_env
    1347              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mos
    1348              : 
    1349              :       REAL(KIND=dp), PARAMETER                           :: eps_degenerate = 1.0E-5_dp
    1350              : 
    1351              :       CHARACTER(LEN=200)                                 :: message
    1352              :       INTEGER                                            :: first_active, first_other, ispin, mspin, &
    1353              :                                                             nmo, npairs
    1354          108 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigenvalues
    1355              : 
    1356          234 :       DO ispin = 1, SIZE(active_space_env%active_orbitals, 2)
    1357          126 :          mspin = MIN(ispin, SIZE(mos))
    1358          126 :          CALL get_mo_set(mos(mspin), nmo=nmo, eigenvalues=eigenvalues)
    1359              :          ! no orbital energies available
    1360          126 :          IF (.NOT. ASSOCIATED(eigenvalues)) CYCLE
    1361          134 :          IF (ALL(ABS(eigenvalues(1:nmo)) < EPSILON(1.0_dp))) CYCLE
    1362              :          CALL find_degenerate_splits(eigenvalues(1:nmo), active_space_env%active_orbitals(:, ispin), &
    1363          124 :                                      eps_degenerate, npairs, first_active, first_other)
    1364          358 :          IF (npairs > 0) THEN
    1365              :             WRITE (message, '(A,I0,A,I0,A,I0,A,I0,A)') &
    1366            0 :                "The active space splits a set of degenerate orbitals: active orbital ", first_active, &
    1367            0 :                " and inactive/virtual orbital ", first_other, " (spin ", ispin, ", ", npairs, &
    1368            0 :                " degenerate pairs in total)."
    1369            0 :             CPWARN(TRIM(message))
    1370              :          END IF
    1371              :       END DO
    1372              : 
    1373          108 :    END SUBROUTINE check_active_space_degeneracy
    1374              : 
    1375              : ! **************************************************************************************************
    1376              : !> \brief Writes the orbitals of the active space Hamiltonian to a Molden file: the inactive
    1377              : !>        orbitals first, then the active orbitals in the order of the active orbital list,
    1378              : !>        i.e. the orbital order of the FCIDUMP file.
    1379              : !> \param qs_env the QS environment
    1380              : !> \param active_space_env the active space environment
    1381              : !> \param as_input the ACTIVE_SPACE input section
    1382              : ! **************************************************************************************************
    1383            2 :    SUBROUTINE write_active_space_molden(qs_env, active_space_env, as_input)
    1384              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1385              :       TYPE(active_space_type), POINTER                   :: active_space_env
    1386              :       TYPE(section_vals_type), POINTER                   :: as_input
    1387              : 
    1388              :       INTEGER                                            :: i, iorb, ispin, m, nao, nmo_active, &
    1389              :                                                             nmo_inactive, nmo_out, nspins
    1390              :       REAL(KIND=dp)                                      :: maxocc
    1391              :       TYPE(cell_type), POINTER                           :: cell
    1392              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
    1393              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff_active, mo_coeff_inactive
    1394            2 :       TYPE(mo_set_type), ALLOCATABLE, DIMENSION(:)       :: mos_out
    1395            2 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1396            2 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1397              :       TYPE(section_vals_type), POINTER                   :: molden_section
    1398              : 
    1399            2 :       NULLIFY (cell, fm_struct, mo_coeff_active, mo_coeff_inactive, particle_set, qs_kind_set)
    1400            2 :       CALL get_qs_env(qs_env, cell=cell, particle_set=particle_set, qs_kind_set=qs_kind_set)
    1401            2 :       molden_section => section_vals_get_subs_vals(as_input, "MOLDEN")
    1402              : 
    1403            2 :       nspins = SIZE(active_space_env%mos_active)
    1404            2 :       nmo_active = SIZE(active_space_env%active_orbitals, 1)
    1405            2 :       nmo_inactive = SIZE(active_space_env%inactive_orbitals, 1)
    1406            2 :       nmo_out = nmo_inactive + nmo_active
    1407            8 :       ALLOCATE (mos_out(nspins))
    1408            4 :       DO ispin = 1, nspins
    1409              :          CALL get_mo_set(active_space_env%mos_active(ispin), nao=nao, maxocc=maxocc, &
    1410            2 :                          mo_coeff=mo_coeff_active)
    1411            2 :          CALL get_mo_set(active_space_env%mos_inactive(ispin), mo_coeff=mo_coeff_inactive)
    1412            2 :          CALL allocate_mo_set(mos_out(ispin), nao, nmo_out, 0, 0.0_dp, maxocc, 0.0_dp)
    1413              :          CALL cp_fm_struct_create(fm_struct, nrow_global=nao, ncol_global=nmo_out, &
    1414            2 :                                   template_fmstruct=mo_coeff_active%matrix_struct)
    1415            2 :          CALL init_mo_set(mos_out(ispin), fm_struct=fm_struct, name="active space orbitals")
    1416            2 :          CALL cp_fm_struct_release(fm_struct)
    1417              :          ! the MO sets of the active space store each orbital in the column of its MO index
    1418            6 :          DO i = 1, nmo_inactive
    1419            4 :             m = active_space_env%inactive_orbitals(i, ispin)
    1420            4 :             CALL cp_fm_to_fm(mo_coeff_inactive, mos_out(ispin)%mo_coeff, 1, m, i)
    1421            4 :             mos_out(ispin)%eigenvalues(i) = active_space_env%mos_inactive(ispin)%eigenvalues(m)
    1422            6 :             mos_out(ispin)%occupation_numbers(i) = active_space_env%mos_inactive(ispin)%occupation_numbers(m)
    1423              :          END DO
    1424           18 :          DO i = 1, nmo_active
    1425           12 :             m = active_space_env%active_orbitals(i, ispin)
    1426           12 :             iorb = nmo_inactive + i
    1427           12 :             CALL cp_fm_to_fm(mo_coeff_active, mos_out(ispin)%mo_coeff, 1, m, iorb)
    1428           12 :             mos_out(ispin)%eigenvalues(iorb) = active_space_env%mos_active(ispin)%eigenvalues(m)
    1429           14 :             mos_out(ispin)%occupation_numbers(iorb) = active_space_env%mos_active(ispin)%occupation_numbers(m)
    1430              :          END DO
    1431              :       END DO
    1432              : 
    1433            2 :       CALL write_mos_molden(mos_out, qs_kind_set, particle_set, molden_section, cell=cell)
    1434              : 
    1435            4 :       DO ispin = 1, nspins
    1436            4 :          CALL deallocate_mo_set(mos_out(ispin))
    1437              :       END DO
    1438            2 :       DEALLOCATE (mos_out)
    1439              : 
    1440            2 :    END SUBROUTINE write_active_space_molden
    1441              : 
    1442              : ! **************************************************************************************************
    1443              : !> \brief computes the alpha-beta overlap within the active subspace
    1444              : !> \param mos the molecular orbital set within the active subspace
    1445              : !> \param qs_env ...
    1446              : !> \param active_space_env ...
    1447              : !> \par History
    1448              : !>      04.2016 created [JGH]
    1449              : ! **************************************************************************************************
    1450          108 :    SUBROUTINE calculate_spin_pol_overlap(mos, qs_env, active_space_env)
    1451              : 
    1452              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mos
    1453              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1454              :       TYPE(active_space_type), POINTER                   :: active_space_env
    1455              : 
    1456              :       CHARACTER(len=*), PARAMETER :: routineN = 'calculate_spin_pol_overlap'
    1457              : 
    1458              :       INTEGER                                            :: handle, nmo, nspins
    1459              :       LOGICAL                                            :: do_kpoints
    1460              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff_a, mo_coeff_b
    1461          108 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: s_matrix
    1462          108 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: s_matrix_kp
    1463              : 
    1464          108 :       CALL timeset(routineN, handle)
    1465              : 
    1466          108 :       nspins = active_space_env%nspins
    1467              : 
    1468              :       ! overlap in AO
    1469          108 :       IF (nspins > 1) THEN
    1470           18 :          CALL get_qs_env(qs_env, do_kpoints=do_kpoints)
    1471           18 :          IF (do_kpoints) THEN
    1472            0 :             CALL get_qs_env(qs_env, matrix_s_kp=s_matrix_kp)
    1473            0 :             s_matrix => s_matrix_kp(:, 1)
    1474              :          ELSE
    1475           18 :             CALL get_qs_env(qs_env, matrix_s=s_matrix)
    1476              :          END IF
    1477           36 :          ALLOCATE (active_space_env%sab_sub(1))
    1478              : 
    1479           18 :          CALL get_mo_set(mo_set=mos(1), mo_coeff=mo_coeff_a, nmo=nmo)
    1480           18 :          CALL get_mo_set(mo_set=mos(2), mo_coeff=mo_coeff_b, nmo=nmo)
    1481           18 :          CALL subspace_operator(mo_coeff_a, nmo, s_matrix(1)%matrix, active_space_env%sab_sub(1), mo_coeff_b)
    1482              :       END IF
    1483              : 
    1484          108 :       CALL timestop(handle)
    1485              : 
    1486          108 :    END SUBROUTINE calculate_spin_pol_overlap
    1487              : 
    1488              : ! **************************************************************************************************
    1489              : !> \brief computes the one-electron operators in the subspace of the provided orbital set
    1490              : !> \param mos the molecular orbital set within the active subspace
    1491              : !> \param qs_env ...
    1492              : !> \param active_space_env ...
    1493              : !> \par History
    1494              : !>      04.2016 created [JGH]
    1495              : ! **************************************************************************************************
    1496          130 :    SUBROUTINE calculate_operators(mos, qs_env, active_space_env)
    1497              : 
    1498              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mos
    1499              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1500              :       TYPE(active_space_type), POINTER                   :: active_space_env
    1501              : 
    1502              :       CHARACTER(len=*), PARAMETER :: routineN = 'calculate_operators'
    1503              : 
    1504              :       INTEGER                                            :: handle, ispin, nmo, nspins
    1505              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
    1506          130 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: h_matrix, ks_matrix
    1507              : 
    1508          130 :       CALL timeset(routineN, handle)
    1509              : 
    1510          130 :       nspins = active_space_env%nspins
    1511              : 
    1512              :       ! Kohn-Sham / Fock operator
    1513          130 :       CALL cp_fm_release(active_space_env%ks_sub)
    1514          130 :       CALL get_qs_env(qs_env, matrix_ks_kp=ks_matrix)
    1515          552 :       ALLOCATE (active_space_env%ks_sub(nspins))
    1516          292 :       DO ispin = 1, nspins
    1517          162 :          CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff, nmo=nmo)
    1518          292 :          CALL subspace_operator(mo_coeff, nmo, ks_matrix(ispin, 1)%matrix, active_space_env%ks_sub(ispin))
    1519              :       END DO
    1520              : 
    1521              :       ! Core Hamiltonian
    1522          130 :       CALL cp_fm_release(active_space_env%h_sub)
    1523              : 
    1524          130 :       NULLIFY (h_matrix)
    1525          130 :       CALL get_qs_env(qs_env=qs_env, matrix_h_kp=h_matrix)
    1526          422 :       ALLOCATE (active_space_env%h_sub(nspins))
    1527          292 :       DO ispin = 1, nspins
    1528          162 :          CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff, nmo=nmo)
    1529          292 :          CALL subspace_operator(mo_coeff, nmo, h_matrix(1, 1)%matrix, active_space_env%h_sub(ispin))
    1530              :       END DO
    1531              : 
    1532          130 :       CALL timestop(handle)
    1533              : 
    1534          130 :    END SUBROUTINE calculate_operators
    1535              : 
    1536              : ! **************************************************************************************************
    1537              : !> \brief computes a one-electron operator in the subspace of the provided orbital set
    1538              : !> \param mo_coeff the orbital coefficient matrix
    1539              : !> \param nmo the number of subspace orbitals
    1540              : !> \param op_matrix operator matrix in AO basis
    1541              : !> \param op_sub operator in orbital basis
    1542              : !> \param mo_coeff_b the beta orbital coefficients
    1543              : !> \par History
    1544              : !>      04.2016 created [JGH]
    1545              : ! **************************************************************************************************
    1546          684 :    SUBROUTINE subspace_operator(mo_coeff, nmo, op_matrix, op_sub, mo_coeff_b)
    1547              : 
    1548              :       TYPE(cp_fm_type), INTENT(IN)                       :: mo_coeff
    1549              :       INTEGER, INTENT(IN)                                :: nmo
    1550              :       TYPE(dbcsr_type), POINTER                          :: op_matrix
    1551              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: op_sub
    1552              :       TYPE(cp_fm_type), INTENT(IN), OPTIONAL             :: mo_coeff_b
    1553              : 
    1554              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'subspace_operator'
    1555              : 
    1556              :       INTEGER                                            :: handle, ncol, nrow
    1557              :       TYPE(cp_fm_type)                                   :: vectors
    1558              : 
    1559          342 :       CALL timeset(routineN, handle)
    1560              : 
    1561          342 :       CALL cp_fm_get_info(matrix=mo_coeff, ncol_global=ncol, nrow_global=nrow)
    1562          342 :       CPASSERT(nmo <= ncol)
    1563              : 
    1564          342 :       IF (nmo > 0) THEN
    1565          342 :          CALL cp_fm_create(vectors, mo_coeff%matrix_struct, "vectors")
    1566          342 :          CALL create_subspace_matrix(mo_coeff, op_sub, nmo)
    1567              : 
    1568          342 :          IF (PRESENT(mo_coeff_b)) THEN
    1569              :             ! if beta orbitals are present, compute the cross alpha_beta term
    1570           18 :             CALL cp_dbcsr_sm_fm_multiply(op_matrix, mo_coeff_b, vectors, nmo)
    1571              :          ELSE
    1572              :             ! otherwise the same spin, whatever that is
    1573          324 :             CALL cp_dbcsr_sm_fm_multiply(op_matrix, mo_coeff, vectors, nmo)
    1574              :          END IF
    1575              : 
    1576          342 :          CALL parallel_gemm('T', 'N', nmo, nmo, nrow, 1.0_dp, mo_coeff, vectors, 0.0_dp, op_sub)
    1577          342 :          CALL cp_fm_release(vectors)
    1578              :       END IF
    1579              : 
    1580          342 :       CALL timestop(handle)
    1581              : 
    1582          342 :    END SUBROUTINE subspace_operator
    1583              : 
    1584              : ! **************************************************************************************************
    1585              : !> \brief creates a matrix of subspace size
    1586              : !> \param orbitals the orbital coefficient matrix
    1587              : !> \param op_sub operator in orbital basis
    1588              : !> \param n the number of orbitals
    1589              : !> \par History
    1590              : !>      04.2016 created [JGH]
    1591              : ! **************************************************************************************************
    1592          468 :    SUBROUTINE create_subspace_matrix(orbitals, op_sub, n)
    1593              : 
    1594              :       TYPE(cp_fm_type), INTENT(IN)                       :: orbitals
    1595              :       TYPE(cp_fm_type), INTENT(OUT)                      :: op_sub
    1596              :       INTEGER, INTENT(IN)                                :: n
    1597              : 
    1598              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
    1599              : 
    1600          468 :       IF (n > 0) THEN
    1601              : 
    1602          468 :          NULLIFY (fm_struct)
    1603              :          CALL cp_fm_struct_create(fm_struct, nrow_global=n, ncol_global=n, &
    1604              :                                   para_env=orbitals%matrix_struct%para_env, &
    1605          468 :                                   context=orbitals%matrix_struct%context)
    1606          468 :          CALL cp_fm_create(op_sub, fm_struct, name="Subspace operator")
    1607          468 :          CALL cp_fm_struct_release(fm_struct)
    1608              : 
    1609              :       END IF
    1610              : 
    1611          468 :    END SUBROUTINE create_subspace_matrix
    1612              : 
    1613              : ! **************************************************************************************************
    1614              : !> \brief computes the electron repulsion integrals using the GPW technology
    1615              : !> \param mos the molecular orbital set within the active subspace
    1616              : !> \param orbitals ...
    1617              : !> \param eri_env ...
    1618              : !> \param qs_env ...
    1619              : !> \param iw ...
    1620              : !> \param restricted ...
    1621              : !> \par History
    1622              : !>      04.2016 created [JGH]
    1623              : ! **************************************************************************************************
    1624          108 :    SUBROUTINE calculate_eri_gpw(mos, orbitals, eri_env, qs_env, iw, restricted)
    1625              : 
    1626              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mos
    1627              :       INTEGER, DIMENSION(:, :), POINTER                  :: orbitals
    1628              :       TYPE(eri_type)                                     :: eri_env
    1629              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1630              :       INTEGER, INTENT(IN)                                :: iw
    1631              :       LOGICAL, INTENT(IN)                                :: restricted
    1632              : 
    1633              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'calculate_eri_gpw'
    1634              : 
    1635              :       INTEGER :: col_local, color, handle, i1, i2, i3, i4, i_multigrid, icount2, intcount, isp, &
    1636              :          isp1, isp2, ispin, iwa1, iwa12, iwa2, iwb1, iwb12, iwb2, iwbs, iwbt, iwfn, n_multigrid, &
    1637              :          ncol_global, ncol_local, nmm, nmo, nmo1, nmo2, nrow_global, nrow_local, nspins, &
    1638              :          number_of_subgroups, nx, row_local, stored_integrals
    1639          108 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: eri_index
    1640          108 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
    1641              :       LOGICAL                                            :: print1, print2, &
    1642              :                                                             skip_load_balance_distributed
    1643              :       REAL(KIND=dp)                                      :: dvol, erint, pair_int, &
    1644              :                                                             progression_factor, rc, rsize, t1, t2
    1645          108 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eri
    1646          108 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    1647              :       TYPE(cell_type), POINTER                           :: cell
    1648              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env, blacs_env_sub
    1649              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
    1650          108 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: fm_matrix_pq_rnu, fm_matrix_pq_rs, &
    1651          108 :                                                             fm_mo_coeff_as
    1652              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
    1653              :       TYPE(dbcsr_p_type)                                 :: mat_munu
    1654          108 :       TYPE(dbcsr_type), ALLOCATABLE, DIMENSION(:)        :: matrix_pq_rnu, mo_coeff_as
    1655              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1656              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1657              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    1658          108 :          POINTER                                         :: sab_orb_sub
    1659          108 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1660              :       TYPE(pw_c1d_gs_type)                               :: pot_g, rho_g
    1661              :       TYPE(pw_env_type), POINTER                         :: pw_env_sub
    1662              :       TYPE(pw_poisson_type), POINTER                     :: poisson_env
    1663              :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
    1664              :       TYPE(pw_r3d_rs_type)                               :: rho_r, wfn_r
    1665              :       TYPE(pw_r3d_rs_type), ALLOCATABLE, &
    1666          108 :          DIMENSION(:, :), TARGET                         :: wfn_a
    1667              :       TYPE(pw_r3d_rs_type), POINTER                      :: wfn1, wfn2, wfn3, wfn4
    1668              :       TYPE(qs_control_type), POINTER                     :: qs_control, qs_control_old
    1669          108 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1670              :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
    1671              :       TYPE(task_list_type), POINTER                      :: task_list_sub
    1672              : 
    1673          108 :       CALL timeset(routineN, handle)
    1674              : 
    1675          108 :       IF (iw > 0) t1 = m_walltime()
    1676              : 
    1677              :       ! print levels
    1678          204 :       SELECT CASE (eri_env%eri_gpw%print_level)
    1679              :       CASE (silent_print_level)
    1680           96 :          print1 = .FALSE.
    1681           96 :          print2 = .FALSE.
    1682              :       CASE (low_print_level)
    1683            6 :          print1 = .FALSE.
    1684            6 :          print2 = .FALSE.
    1685              :       CASE (medium_print_level)
    1686            6 :          print1 = .TRUE.
    1687            6 :          print2 = .FALSE.
    1688              :       CASE (high_print_level)
    1689            0 :          print1 = .TRUE.
    1690            0 :          print2 = .TRUE.
    1691              :       CASE (debug_print_level)
    1692            0 :          print1 = .TRUE.
    1693          108 :          print2 = .TRUE.
    1694              :       CASE DEFAULT
    1695              :          ! do nothing
    1696              :       END SELECT
    1697              : 
    1698              :       ! Check the input group
    1699          108 :       CALL get_qs_env(qs_env, para_env=para_env, blacs_env=blacs_env)
    1700          108 :       IF (eri_env%eri_gpw%group_size < 1) eri_env%eri_gpw%group_size = para_env%num_pe
    1701          108 :       IF (MOD(para_env%num_pe, eri_env%eri_gpw%group_size) /= 0) THEN
    1702            0 :          CPABORT("Group size must be a divisor of the total number of processes!")
    1703              :       END IF
    1704              :       ! Create a new para_env or reuse the old one
    1705          108 :       IF (eri_env%eri_gpw%group_size == para_env%num_pe) THEN
    1706          102 :          eri_env%para_env_sub => para_env
    1707          102 :          CALL eri_env%para_env_sub%retain()
    1708          102 :          blacs_env_sub => blacs_env
    1709          102 :          CALL blacs_env_sub%retain()
    1710          102 :          number_of_subgroups = 1
    1711          102 :          color = 0
    1712              :       ELSE
    1713            6 :          number_of_subgroups = para_env%num_pe/eri_env%eri_gpw%group_size
    1714            6 :          color = para_env%mepos/eri_env%eri_gpw%group_size
    1715            6 :          ALLOCATE (eri_env%para_env_sub)
    1716            6 :          CALL eri_env%para_env_sub%from_split(para_env, color)
    1717            6 :          NULLIFY (blacs_env_sub)
    1718            6 :          CALL cp_blacs_env_create(blacs_env_sub, eri_env%para_env_sub, BLACS_GRID_SQUARE, .TRUE.)
    1719              :       END IF
    1720          108 :       CALL eri_env%comm_exchange%from_split(para_env, eri_env%para_env_sub%mepos)
    1721              : 
    1722              :       ! This should be done differently! Copied from MP2 code
    1723          108 :       CALL get_qs_env(qs_env, dft_control=dft_control)
    1724          432 :       ALLOCATE (qs_control)
    1725          108 :       qs_control_old => dft_control%qs_control
    1726          108 :       qs_control = qs_control_old
    1727          108 :       dft_control%qs_control => qs_control
    1728          108 :       progression_factor = qs_control%progression_factor
    1729          108 :       n_multigrid = SIZE(qs_control%e_cutoff)
    1730          108 :       nspins = SIZE(mos)
    1731              :       ! In case of ROHF/ROKS, we assume the orbital coefficients in both spin channels to be the same
    1732              :       ! and save operations by calculating ERIs from only one spin channel
    1733          108 :       IF (restricted) nspins = 1
    1734              :       ! Allocate new cutoffs (just in private qs_control, not in qs_control_old)
    1735          324 :       ALLOCATE (qs_control%e_cutoff(n_multigrid))
    1736              : 
    1737          108 :       qs_control%cutoff = eri_env%eri_gpw%cutoff*0.5_dp
    1738          108 :       qs_control%e_cutoff(1) = qs_control%cutoff
    1739          432 :       DO i_multigrid = 2, n_multigrid
    1740              :          qs_control%e_cutoff(i_multigrid) = qs_control%e_cutoff(i_multigrid - 1) &
    1741          432 :                                             /progression_factor
    1742              :       END DO
    1743          108 :       qs_control%relative_cutoff = eri_env%eri_gpw%rel_cutoff*0.5_dp
    1744              : 
    1745              :       ! For now, we will distribute neighbor lists etc. within the global communicator
    1746          108 :       CALL get_qs_env(qs_env, ks_env=ks_env)
    1747              :       CALL create_mat_munu(mat_munu, qs_env, eri_env%eri_gpw%eps_grid, blacs_env_sub, sab_orb_sub=sab_orb_sub, &
    1748          108 :                            do_alloc_blocks_from_nbl=.TRUE., dbcsr_sym_type=dbcsr_type_symmetric)
    1749          108 :       CALL dbcsr_set(mat_munu%matrix, 0.0_dp)
    1750              : 
    1751              :       ! Generate the appropriate pw_env
    1752          108 :       NULLIFY (pw_env_sub)
    1753          108 :       CALL pw_env_create(pw_env_sub)
    1754          108 :       CALL pw_env_rebuild(pw_env_sub, qs_env, external_para_env=eri_env%para_env_sub)
    1755          108 :       CALL pw_env_get(pw_env_sub, auxbas_pw_pool=auxbas_pw_pool, poisson_env=poisson_env)
    1756              : 
    1757              :       ! TODO: maybe we can let `pw_env_rebuild` do what we manually overwrite here?
    1758          108 :       IF (eri_env%eri_gpw%redo_poisson) THEN
    1759              :          ! We need to rebuild the Poisson solver on the fly
    1760          432 :          IF (SUM(eri_env%periodicity) /= 0) THEN
    1761           10 :             poisson_env%parameters%solver = pw_poisson_periodic
    1762              :          ELSE
    1763           98 :             poisson_env%parameters%solver = pw_poisson_analytic
    1764              :          END IF
    1765          432 :          poisson_env%parameters%periodic = eri_env%periodicity
    1766              : 
    1767              :          ! Rebuilds the poisson green (influence) function according
    1768              :          ! to the poisson solver and parameters set so far.
    1769              :          ! Also sets the variable poisson_env%rebuild to .FALSE.
    1770          108 :          CALL pw_poisson_rebuild(poisson_env)
    1771              : 
    1772              :          ! set the cutoff radius for the Greens function in case we use ANALYTIC Poisson solver
    1773          108 :          CALL get_qs_env(qs_env, cell=cell)
    1774          108 :          rc = cell%hmat(1, 1)
    1775          432 :          DO iwa1 = 1, 3
    1776              :             ! TODO: I think this is not the largest possible radius inscribed in the cell
    1777          432 :             rc = MIN(rc, 0.5_dp*cell%hmat(iwa1, iwa1))
    1778              :          END DO
    1779          108 :          poisson_env%green_fft%radius = rc
    1780              : 
    1781              :          ! Overwrite the Greens function with the one we want
    1782          108 :          CALL pw_eri_green_create(poisson_env%green_fft, eri_env)
    1783              : 
    1784          108 :          IF (iw > 0) THEN
    1785           54 :             CALL get_qs_env(qs_env, cell=cell)
    1786          432 :             IF (SUM(cell%perd) /= SUM(eri_env%periodicity)) THEN
    1787            0 :                IF (SUM(eri_env%periodicity) /= 0) THEN
    1788              :                   WRITE (UNIT=iw, FMT="(/,T2,A,T51,A30)") &
    1789            0 :                      "ERI_GPW| Switching Poisson solver to", "PERIODIC"
    1790              :                ELSE
    1791              :                   WRITE (UNIT=iw, FMT="(/,T2,A,T51,A30)") &
    1792            0 :                      "ERI_GPW| Switching Poisson solver to", "ANALYTIC"
    1793              :                END IF
    1794              :             END IF
    1795              :             ! print out the Greens function to check it matches the Poisson solver
    1796           59 :             SELECT CASE (poisson_env%green_fft%method)
    1797              :             CASE (PERIODIC3D)
    1798              :                WRITE (UNIT=iw, FMT="(T2,A,T51,A30)") &
    1799            5 :                   "ERI_GPW| Poisson Greens function", "PERIODIC"
    1800              :             CASE (ANALYTIC0D)
    1801              :                WRITE (UNIT=iw, FMT="(T2,A,T51,A30)") &
    1802           49 :                   "ERI_GPW| Poisson Greens function", "ANALYTIC"
    1803           49 :                WRITE (UNIT=iw, FMT="(T2,A,T71,F10.4)") "ERI_GPW| Poisson cutoff radius", &
    1804           98 :                   poisson_env%green_fft%radius*angstrom
    1805              :             CASE DEFAULT
    1806           54 :                CPABORT("Wrong Greens function setup")
    1807              :             END SELECT
    1808              :          END IF
    1809              :       END IF
    1810              : 
    1811          784 :       ALLOCATE (mo_coeff_as(nspins), fm_mo_coeff_as(nspins))
    1812          230 :       DO ispin = 1, nspins
    1813          366 :          BLOCK
    1814          122 :             REAL(KIND=dp), DIMENSION(:, :), ALLOCATABLE :: C, C_active
    1815              :             INTEGER :: nmo
    1816          122 :             TYPE(group_dist_d1_type) :: gd_array
    1817              :             TYPE(cp_fm_type), POINTER :: mo_coeff
    1818          122 :             CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, nmo=nmo)
    1819          122 :             CALL grep_rows_in_subgroups(para_env, eri_env%para_env_sub, mo_coeff, gd_array, C)
    1820              : 
    1821          488 :             ALLOCATE (C_active(SIZE(C, 1), SIZE(orbitals, 1)))
    1822          488 :             DO i1 = 1, SIZE(orbitals, 1)
    1823         2386 :                C_active(:, i1) = C(:, orbitals(i1, ispin))
    1824              :             END DO
    1825              :             CALL build_dbcsr_from_rows(eri_env%para_env_sub, mo_coeff_as(ispin), &
    1826          122 :                                        C_active, mat_munu%matrix, gd_array, eri_env%eri_gpw%eps_filter)
    1827          122 :             CALL release_group_dist(gd_array)
    1828          488 :             DEALLOCATE (C, C_active)
    1829              :          END BLOCK
    1830              : 
    1831          122 :          CALL dbcsr_get_info(mo_coeff_as(ispin), nfullrows_total=nrow_global, nfullcols_total=ncol_global)
    1832              : 
    1833          122 :          NULLIFY (fm_struct)
    1834              :          CALL cp_fm_struct_create(fm_struct, context=blacs_env_sub, para_env=eri_env%para_env_sub, &
    1835          122 :                                   nrow_global=nrow_global, ncol_global=ncol_global)
    1836          122 :          CALL cp_fm_create(fm_mo_coeff_as(ispin), fm_struct)
    1837          122 :          CALL cp_fm_struct_release(fm_struct)
    1838              : 
    1839          352 :          CALL copy_dbcsr_to_fm(mo_coeff_as(ispin), fm_mo_coeff_as(ispin))
    1840              :       END DO
    1841              : 
    1842          108 :       IF (eri_env%method == eri_method_gpw_ht) THEN
    1843              :          ! We need a task list
    1844           16 :          NULLIFY (task_list_sub)
    1845           16 :          skip_load_balance_distributed = dft_control%qs_control%skip_load_balance_distributed
    1846           16 :          CALL allocate_task_list(task_list_sub)
    1847              :          CALL generate_qs_task_list(ks_env, task_list_sub, basis_type="ORB", &
    1848              :                                     reorder_rs_grid_ranks=.TRUE., &
    1849              :                                     skip_load_balance_distributed=skip_load_balance_distributed, &
    1850           16 :                                     pw_env_external=pw_env_sub, sab_orb_external=sab_orb_sub)
    1851              : 
    1852              :          ! Create sparse matrices carrying the matrix products, Code borrowed from the MP2 GPW method
    1853              :          ! Create equal distributions for them (no sparsity present)
    1854              :          ! We use the routines from mp2 suggesting that one may replicate the grids later for better performance
    1855          112 :          ALLOCATE (matrix_pq_rnu(nspins), fm_matrix_pq_rnu(nspins), fm_matrix_pq_rs(nspins))
    1856           32 :          DO ispin = 1, nspins
    1857           16 :             CALL dbcsr_create(matrix_pq_rnu(ispin), template=mo_coeff_as(ispin))
    1858           16 :             CALL dbcsr_set(matrix_pq_rnu(ispin), 0.0_dp)
    1859              : 
    1860           16 :             CALL dbcsr_get_info(matrix_pq_rnu(ispin), nfullrows_total=nrow_global, nfullcols_total=ncol_global)
    1861              : 
    1862           16 :             NULLIFY (fm_struct)
    1863              :             CALL cp_fm_struct_create(fm_struct, context=blacs_env_sub, para_env=eri_env%para_env_sub, &
    1864           16 :                                      nrow_global=nrow_global, ncol_global=ncol_global)
    1865           16 :             CALL cp_fm_create(fm_matrix_pq_rnu(ispin), fm_struct)
    1866           16 :             CALL cp_fm_struct_release(fm_struct)
    1867              : 
    1868           16 :             NULLIFY (fm_struct)
    1869              :             CALL cp_fm_struct_create(fm_struct, context=blacs_env_sub, para_env=eri_env%para_env_sub, &
    1870           16 :                                      nrow_global=ncol_global, ncol_global=ncol_global)
    1871           16 :             CALL cp_fm_create(fm_matrix_pq_rs(ispin), fm_struct)
    1872           48 :             CALL cp_fm_struct_release(fm_struct)
    1873              :          END DO
    1874              : 
    1875              :          ! Copy the active space of the MOs into DBCSR matrices
    1876              :       END IF
    1877              : 
    1878          108 :       CALL auxbas_pw_pool%create_pw(wfn_r)
    1879          108 :       CALL auxbas_pw_pool%create_pw(rho_g)
    1880              :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set, cell=cell, &
    1881          108 :                       particle_set=particle_set, atomic_kind_set=atomic_kind_set)
    1882              : 
    1883              :       ! pre-calculate wavefunctions on reals space grid
    1884          108 :       nspins = SIZE(mos)
    1885              :       ! In case of ROHF/ROKS, we assume the orbital coefficients in both spin channels to be the same
    1886              :       ! and save operations by calculating ERIs from only one spin channel
    1887              :       IF (restricted) nspins = 1
    1888          108 :       IF (eri_env%eri_gpw%store_wfn) THEN
    1889              :          ! pre-calculate wavefunctions on reals space grid
    1890           96 :          rsize = 0.0_dp
    1891           96 :          nmo = 0
    1892          206 :          DO ispin = 1, nspins
    1893          110 :             CALL get_mo_set(mo_set=mos(ispin), nmo=nx)
    1894          110 :             nmo = MAX(nmo, nx)
    1895          536 :             rsize = REAL(SIZE(wfn_r%array), KIND=dp)*nx
    1896              :          END DO
    1897           96 :          IF (print1 .AND. iw > 0) THEN
    1898            3 :             rsize = rsize*8._dp/1000000._dp
    1899            3 :             WRITE (iw, "(T2,'ERI_GPW|',' Store active orbitals on real space grid ',T66,F12.3,' MB')") rsize
    1900              :          END IF
    1901          944 :          ALLOCATE (wfn_a(nmo, nspins))
    1902          206 :          DO ispin = 1, nspins
    1903          110 :             CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff, nmo=nmo)
    1904          548 :             DO i1 = 1, SIZE(orbitals, 1)
    1905          342 :                iwfn = orbitals(i1, ispin)
    1906          342 :                CALL auxbas_pw_pool%create_pw(wfn_a(iwfn, ispin))
    1907              :                CALL calculate_wavefunction(mo_coeff, iwfn, wfn_a(iwfn, ispin), rho_g, atomic_kind_set, &
    1908          342 :                                            qs_kind_set, cell, dft_control, particle_set, pw_env_sub)
    1909          452 :                IF (print2 .AND. iw > 0) THEN
    1910            0 :                   WRITE (iw, "(T2,'ERI_GPW|',' Orbital stored ',I4,'  Spin ',i1)") iwfn, ispin
    1911              :                END IF
    1912              :             END DO
    1913              :          END DO
    1914              :       ELSE
    1915              :          ! Even if we do not store all WFNs, we still need containers for the functions to store
    1916           12 :          ALLOCATE (wfn1, wfn2)
    1917           12 :          CALL auxbas_pw_pool%create_pw(wfn1)
    1918           12 :          CALL auxbas_pw_pool%create_pw(wfn2)
    1919           12 :          IF (eri_env%method /= eri_method_gpw_ht) THEN
    1920            6 :             ALLOCATE (wfn3, wfn4)
    1921            6 :             CALL auxbas_pw_pool%create_pw(wfn3)
    1922            6 :             CALL auxbas_pw_pool%create_pw(wfn4)
    1923              :          END IF
    1924              :       END IF
    1925              : 
    1926              :       ! get some of the grids ready
    1927          108 :       CALL auxbas_pw_pool%create_pw(rho_r)
    1928          108 :       CALL auxbas_pw_pool%create_pw(pot_g)
    1929              : 
    1930              :       ! run the FFT once, to set up buffers and to take into account the memory
    1931          108 :       CALL pw_zero(rho_r)
    1932          108 :       CALL pw_transfer(rho_r, rho_g)
    1933          108 :       dvol = rho_r%pw_grid%dvol
    1934              : 
    1935          108 :       IF (iw > 0) THEN
    1936           54 :          CALL m_flush(iw)
    1937              :       END IF
    1938              :       ! calculate the integrals
    1939          108 :       stored_integrals = 0
    1940          230 :       DO isp1 = 1, nspins
    1941          122 :          CALL get_mo_set(mo_set=mos(isp1), nmo=nmo1)
    1942          122 :          nmm = (nmo1*(nmo1 + 1))/2
    1943          596 :          DO i1 = 1, SIZE(orbitals, 1)
    1944          366 :             iwa1 = orbitals(i1, isp1)
    1945          366 :             IF (eri_env%eri_gpw%store_wfn) THEN
    1946          342 :                wfn1 => wfn_a(iwa1, isp1)
    1947              :             ELSE
    1948              :                CALL calculate_wavefunction(fm_mo_coeff_as(isp1), iwa1, wfn1, rho_g, atomic_kind_set, &
    1949           24 :                                            qs_kind_set, cell, dft_control, particle_set, pw_env_sub)
    1950              :             END IF
    1951         1334 :             DO i2 = i1, SIZE(orbitals, 1)
    1952          846 :                iwa2 = orbitals(i2, isp1)
    1953          846 :                iwa12 = csr_idx_to_combined(iwa1, iwa2, nmo1)
    1954              :                ! Skip calculation directly if the pair is not part of our subgroup
    1955          846 :                IF (MOD(iwa12 - 1, eri_env%comm_exchange%num_pe) /= eri_env%comm_exchange%mepos) CYCLE
    1956          837 :                iwa12 = (iwa12 - 1)/eri_env%comm_exchange%num_pe + 1
    1957          837 :                IF (eri_env%eri_gpw%store_wfn) THEN
    1958          807 :                   wfn2 => wfn_a(iwa2, isp1)
    1959              :                ELSE
    1960              :                   CALL calculate_wavefunction(fm_mo_coeff_as(isp1), iwa2, wfn2, rho_g, atomic_kind_set, &
    1961           30 :                                               qs_kind_set, cell, dft_control, particle_set, pw_env_sub)
    1962              :                END IF
    1963              :                ! calculate charge distribution and potential
    1964          837 :                CALL pw_zero(rho_r)
    1965          837 :                CALL pw_multiply(rho_r, wfn1, wfn2)
    1966          837 :                CALL pw_transfer(rho_r, rho_g)
    1967          837 :                CALL pw_poisson_solve(poisson_env, rho_g, pair_int, pot_g)
    1968              : 
    1969              :                ! screening using pair_int
    1970          837 :                IF (pair_int < eri_env%eps_integral) CYCLE
    1971          837 :                CALL pw_transfer(pot_g, rho_r)
    1972              :                !
    1973         2040 :                IF (eri_env%method == eri_method_gpw_ht) THEN
    1974           56 :                   CALL pw_scale(rho_r, dvol)
    1975          112 :                   DO isp2 = isp1, nspins
    1976           56 :                      CALL get_mo_set(mo_set=mos(isp2), nmo=nmo2)
    1977           56 :                      nx = (nmo2*(nmo2 + 1))/2
    1978          280 :                      ALLOCATE (eri(nx), eri_index(nx))
    1979           56 :                      CALL dbcsr_set(mat_munu%matrix, 0.0_dp)
    1980              :                      CALL integrate_v_rspace(rho_r, hmat=mat_munu, qs_env=qs_env, &
    1981              :                                              calculate_forces=.FALSE., compute_tau=.FALSE., gapw=.FALSE., &
    1982           56 :                                              pw_env_external=pw_env_sub, task_list_external=task_list_sub)
    1983              : 
    1984              :                      CALL dbcsr_multiply("N", "N", 1.0_dp, mat_munu%matrix, mo_coeff_as(isp2), &
    1985           56 :                                          0.0_dp, matrix_pq_rnu(isp2), filter_eps=eri_env%eri_gpw%eps_filter)
    1986           56 :                      CALL copy_dbcsr_to_fm(matrix_pq_rnu(isp2), fm_matrix_pq_rnu(isp2))
    1987              : 
    1988           56 :                      CALL cp_fm_get_info(fm_matrix_pq_rnu(isp2), ncol_global=ncol_global, nrow_global=nrow_global)
    1989              : 
    1990              :                      CALL parallel_gemm("T", "N", ncol_global, ncol_global, nrow_global, 0.5_dp, &
    1991              :                                         fm_matrix_pq_rnu(isp2), fm_mo_coeff_as(isp2), &
    1992           56 :                                         0.0_dp, fm_matrix_pq_rs(isp2))
    1993              :                      CALL parallel_gemm("T", "N", ncol_global, ncol_global, nrow_global, 0.5_dp, &
    1994              :                                         fm_mo_coeff_as(isp2), fm_matrix_pq_rnu(isp2), &
    1995           56 :                                         1.0_dp, fm_matrix_pq_rs(isp2))
    1996              : 
    1997              :                      CALL cp_fm_get_info(fm_matrix_pq_rs(isp2), ncol_local=ncol_local, nrow_local=nrow_local, &
    1998           56 :                                          col_indices=col_indices, row_indices=row_indices)
    1999              : 
    2000           56 :                      icount2 = 0
    2001          208 :                      DO col_local = 1, ncol_local
    2002          152 :                         iwb1 = orbitals(col_indices(col_local), isp2)
    2003          152 :                         IF (isp1 == isp2 .AND. iwb1 < iwa1) CYCLE
    2004          366 :                         DO row_local = 1, nrow_local
    2005          190 :                            iwb2 = orbitals(row_indices(row_local), isp2)
    2006          190 :                            IF (iwb2 < iwb1) CYCLE
    2007          114 :                            IF (isp1 == isp2 .AND. iwa1 == iwb1 .AND. iwb2 < iwa2) CYCLE
    2008              : 
    2009           97 :                            iwb12 = csr_idx_to_combined(iwb1, iwb2, nmo2)
    2010           97 :                            erint = fm_matrix_pq_rs(isp2)%local_data(row_local, col_local)
    2011          249 :                            IF (ABS(erint) > eri_env%eps_integral) THEN
    2012           90 :                               icount2 = icount2 + 1
    2013           90 :                               eri(icount2) = erint
    2014           90 :                               eri_index(icount2) = iwb12
    2015              :                            END IF
    2016              :                         END DO
    2017              :                      END DO
    2018           56 :                      stored_integrals = stored_integrals + icount2
    2019              :                      !
    2020           56 :                      isp = (isp1 - 1)*isp2 + (isp2 - isp1 + 1)
    2021           56 :                      CALL update_csr_matrix(eri_env%eri(isp)%csr_mat, icount2, eri, eri_index, iwa12)
    2022              :                      !
    2023          280 :                      DEALLOCATE (eri, eri_index)
    2024              :                   END DO
    2025          781 :                ELSE IF (eri_env%method == eri_method_full_gpw) THEN
    2026         1636 :                   DO isp2 = isp1, nspins
    2027          855 :                      CALL get_mo_set(mo_set=mos(isp2), nmo=nmo2)
    2028          855 :                      nx = (nmo2*(nmo2 + 1))/2
    2029         4275 :                      ALLOCATE (eri(nx), eri_index(nx))
    2030          855 :                      icount2 = 0
    2031          855 :                      iwbs = 1
    2032          855 :                      IF (isp1 == isp2) iwbs = i1
    2033          855 :                      isp = (isp1 - 1)*isp2 + (isp2 - isp1 + 1)
    2034         3578 :                      DO i3 = iwbs, SIZE(orbitals, 1)
    2035         2723 :                         iwb1 = orbitals(i3, isp2)
    2036         2723 :                         IF (eri_env%eri_gpw%store_wfn) THEN
    2037         2698 :                            wfn3 => wfn_a(iwb1, isp2)
    2038              :                         ELSE
    2039              :                            CALL calculate_wavefunction(fm_mo_coeff_as(isp1), iwb1, wfn3, rho_g, atomic_kind_set, &
    2040           25 :                                                        qs_kind_set, cell, dft_control, particle_set, pw_env_sub)
    2041              :                         END IF
    2042         2723 :                         CALL pw_zero(wfn_r)
    2043         2723 :                         CALL pw_multiply(wfn_r, rho_r, wfn3)
    2044         2723 :                         iwbt = i3
    2045         2723 :                         IF (isp1 == isp2 .AND. i1 == i3) iwbt = i2
    2046         9392 :                         DO i4 = iwbt, SIZE(orbitals, 1)
    2047         5814 :                            iwb2 = orbitals(i4, isp2)
    2048         5814 :                            IF (eri_env%eri_gpw%store_wfn) THEN
    2049         5784 :                               wfn4 => wfn_a(iwb2, isp2)
    2050              :                            ELSE
    2051              :                               CALL calculate_wavefunction(fm_mo_coeff_as(isp1), iwb2, wfn4, rho_g, atomic_kind_set, &
    2052           30 :                                                           qs_kind_set, cell, dft_control, particle_set, pw_env_sub)
    2053              :                            END IF
    2054              :                            ! We reduce the amount of communication by collecting the local sums first and sum globally later
    2055         5814 :                            erint = pw_integral_ab(wfn_r, wfn4, local_only=.TRUE.)
    2056         5814 :                            icount2 = icount2 + 1
    2057         5814 :                            eri(icount2) = erint
    2058         8537 :                            eri_index(icount2) = csr_idx_to_combined(iwb1, iwb2, nmo2)
    2059              :                         END DO
    2060              :                      END DO
    2061              :                      ! Now, we sum the integrals globally
    2062          855 :                      CALL eri_env%para_env_sub%sum(eri)
    2063              :                      ! and we reorder the integrals to prevent storing too small integrals
    2064          855 :                      intcount = 0
    2065          855 :                      icount2 = 0
    2066              :                      iwbs = 1
    2067              :                      IF (isp1 == isp2) iwbs = i1
    2068          855 :                      isp = (isp1 - 1)*isp2 + (isp2 - isp1 + 1)
    2069         3578 :                      DO i3 = iwbs, SIZE(orbitals, 1)
    2070         2723 :                         iwb1 = orbitals(i3, isp2)
    2071         2723 :                         iwbt = i3
    2072         2723 :                         IF (isp1 == isp2 .AND. i1 == i3) iwbt = i2
    2073         9392 :                         DO i4 = iwbt, SIZE(orbitals, 1)
    2074         5814 :                            iwb2 = orbitals(i4, isp2)
    2075         5814 :                            intcount = intcount + 1
    2076         5814 :                            erint = eri(intcount)
    2077         8537 :                            IF (ABS(erint) > eri_env%eps_integral) THEN
    2078         5138 :                               IF (MOD(intcount, eri_env%para_env_sub%num_pe) == eri_env%para_env_sub%mepos) THEN
    2079         2571 :                                  icount2 = icount2 + 1
    2080         2571 :                                  eri(icount2) = erint
    2081         2571 :                                  eri_index(icount2) = eri_index(intcount)
    2082              :                               END IF
    2083              :                            END IF
    2084              :                         END DO
    2085              :                      END DO
    2086          855 :                      stored_integrals = stored_integrals + icount2
    2087              :                      !
    2088          855 :                      CALL update_csr_matrix(eri_env%eri(isp)%csr_mat, icount2, eri, eri_index, iwa12)
    2089              :                      !
    2090         2491 :                      DEALLOCATE (eri, eri_index)
    2091              :                   END DO
    2092              :                ELSE
    2093            0 :                   CPABORT("Unknown option")
    2094              :                END IF
    2095              :             END DO
    2096              :          END DO
    2097              :       END DO
    2098              : 
    2099          108 :       IF (print1 .AND. iw > 0) THEN
    2100            3 :          WRITE (iw, "(T2,'ERI_GPW|',' Number of Integrals stored locally',T71,I10)") stored_integrals
    2101              :       END IF
    2102              : 
    2103          108 :       IF (eri_env%eri_gpw%store_wfn) THEN
    2104          206 :          DO ispin = 1, nspins
    2105          548 :             DO i1 = 1, SIZE(orbitals, 1)
    2106          342 :                iwfn = orbitals(i1, ispin)
    2107          452 :                CALL wfn_a(iwfn, ispin)%release()
    2108              :             END DO
    2109              :          END DO
    2110           96 :          DEALLOCATE (wfn_a)
    2111              :       ELSE
    2112           12 :          CALL wfn1%release()
    2113           12 :          CALL wfn2%release()
    2114           12 :          DEALLOCATE (wfn1, wfn2)
    2115           12 :          IF (eri_env%method /= eri_method_gpw_ht) THEN
    2116            6 :             CALL wfn3%release()
    2117            6 :             CALL wfn4%release()
    2118            6 :             DEALLOCATE (wfn3, wfn4)
    2119              :          END IF
    2120              :       END IF
    2121          108 :       CALL auxbas_pw_pool%give_back_pw(wfn_r)
    2122          108 :       CALL auxbas_pw_pool%give_back_pw(rho_g)
    2123          108 :       CALL auxbas_pw_pool%give_back_pw(rho_r)
    2124          108 :       CALL auxbas_pw_pool%give_back_pw(pot_g)
    2125              : 
    2126          108 :       IF (eri_env%method == eri_method_gpw_ht) THEN
    2127           32 :          DO ispin = 1, nspins
    2128           16 :             CALL dbcsr_release(mo_coeff_as(ispin))
    2129           16 :             CALL dbcsr_release(matrix_pq_rnu(ispin))
    2130           16 :             CALL cp_fm_release(fm_matrix_pq_rnu(ispin))
    2131           32 :             CALL cp_fm_release(fm_matrix_pq_rs(ispin))
    2132              :          END DO
    2133           16 :          DEALLOCATE (matrix_pq_rnu, fm_matrix_pq_rnu, fm_matrix_pq_rs)
    2134           16 :          CALL deallocate_task_list(task_list_sub)
    2135              :       END IF
    2136          230 :       DO ispin = 1, nspins
    2137          122 :          CALL dbcsr_release(mo_coeff_as(ispin))
    2138          230 :          CALL cp_fm_release(fm_mo_coeff_as(ispin))
    2139              :       END DO
    2140          108 :       DEALLOCATE (mo_coeff_as, fm_mo_coeff_as)
    2141          108 :       CALL release_neighbor_list_sets(sab_orb_sub)
    2142          108 :       CALL cp_blacs_env_release(blacs_env_sub)
    2143          108 :       CALL dbcsr_release(mat_munu%matrix)
    2144          108 :       DEALLOCATE (mat_munu%matrix)
    2145          108 :       CALL pw_env_release(pw_env_sub)
    2146              :       ! Return to the old qs_control
    2147          108 :       dft_control%qs_control => qs_control_old
    2148          108 :       DEALLOCATE (qs_control%e_cutoff)
    2149          108 :       DEALLOCATE (qs_control)
    2150              : 
    2151              :       ! print out progress
    2152          108 :       IF (iw > 0) THEN
    2153           54 :          t2 = m_walltime()
    2154           54 :          WRITE (iw, '(/,T2,A,T66,F14.2)') "ERI_GPW| ERI calculation took (sec)", t2 - t1
    2155           54 :          CALL m_flush(iw)
    2156              :       END IF
    2157              : 
    2158          108 :       CALL timestop(handle)
    2159              : 
    2160          216 :    END SUBROUTINE calculate_eri_gpw
    2161              : 
    2162              : ! **************************************************************************************************
    2163              : !> \brief Sets the Green's function for the ERI calculation. Here we deal with the G=0 case!
    2164              : !> \param green ...
    2165              : !> \param eri_env ...
    2166              : !> \par History
    2167              : !>      04.2016 created [JGH]
    2168              : !>      08.2025 added support for the LR truncation [SB]
    2169              : ! **************************************************************************************************
    2170          108 :    SUBROUTINE pw_eri_green_create(green, eri_env)
    2171              : 
    2172              :       TYPE(greens_fn_type), INTENT(INOUT)                :: green
    2173              :       TYPE(eri_type)                                     :: eri_env
    2174              : 
    2175              :       COMPLEX(KIND=dp)                                   :: erf_fac_p, z_p
    2176              :       INTEGER                                            :: ig
    2177              :       REAL(KIND=dp)                                      :: cossin_fac, ea, erfcos_fac, exp_prefac, &
    2178              :                                                             g, G0, g2, g3d, ga, Ginf, omega, &
    2179              :                                                             omega2, Rc, Rc2
    2180              : 
    2181              :       ! initialize influence function
    2182              :       ASSOCIATE (gf => green%influence_fn, grid => green%influence_fn%pw_grid)
    2183          118 :          SELECT CASE (green%method)
    2184              :          CASE (PERIODIC3D)
    2185              : 
    2186          114 :             SELECT CASE (eri_env%operator)
    2187              :             CASE (eri_operator_coulomb)
    2188       786435 :                DO ig = grid%first_gne0, grid%ngpts_cut_local
    2189       786429 :                   g2 = grid%gsq(ig)
    2190       786435 :                   gf%array(ig) = fourpi/g2
    2191              :                END DO
    2192            6 :                IF (grid%have_g0) gf%array(1) = 0.0_dp
    2193              : 
    2194              :             CASE (eri_operator_yukawa)
    2195            0 :                CALL cp_warn(__LOCATION__, "Yukawa operator has not been tested")
    2196            0 :                omega2 = eri_env%omega**2
    2197            0 :                DO ig = grid%first_gne0, grid%ngpts_cut_local
    2198            0 :                   g2 = grid%gsq(ig)
    2199            0 :                   gf%array(ig) = fourpi/(omega2 + g2)
    2200              :                END DO
    2201            0 :                IF (grid%have_g0) gf%array(1) = fourpi/omega2
    2202              : 
    2203              :             CASE (eri_operator_erf)
    2204            0 :                omega2 = eri_env%omega**2
    2205            0 :                DO ig = grid%first_gne0, grid%ngpts_cut_local
    2206            0 :                   g2 = grid%gsq(ig)
    2207            0 :                   gf%array(ig) = fourpi/g2*EXP(-0.25_dp*g2/omega2)
    2208              :                END DO
    2209            0 :                IF (grid%have_g0) gf%array(1) = 0.0_dp
    2210              : 
    2211              :             CASE (eri_operator_erfc)
    2212            0 :                omega2 = eri_env%omega**2
    2213            0 :                DO ig = grid%first_gne0, grid%ngpts_cut_local
    2214            0 :                   g2 = grid%gsq(ig)
    2215            0 :                   gf%array(ig) = fourpi/g2*(1.0_dp - EXP(-0.25_dp*g2/omega2))
    2216              :                END DO
    2217            0 :                IF (grid%have_g0) gf%array(1) = pi/omega2
    2218              : 
    2219              :             CASE (eri_operator_trunc)
    2220            0 :                Rc = eri_env%cutoff_radius
    2221            0 :                DO ig = grid%first_gne0, grid%ngpts_cut_local
    2222            0 :                   g2 = grid%gsq(ig)
    2223            0 :                   g = SQRT(g2)
    2224              :                   ! Taylor expansion around zero
    2225            0 :                   IF (g*Rc >= 0.005_dp) THEN
    2226            0 :                      gf%array(ig) = fourpi/g2*(1.0_dp - COS(g*Rc))
    2227              :                   ELSE
    2228            0 :                      gf%array(ig) = fourpi/g2*(g*Rc)**2/2.0_dp*(1.0_dp - (g*Rc)**2/12.0_dp)
    2229              :                   END IF
    2230              :                END DO
    2231            0 :                IF (grid%have_g0) gf%array(1) = twopi*Rc**2
    2232              : 
    2233              :             CASE (eri_operator_lr_trunc)
    2234            4 :                omega = eri_env%omega
    2235            4 :                omega2 = omega**2
    2236            4 :                Rc = eri_env%cutoff_radius
    2237            4 :                Rc2 = Rc**2
    2238            4 :                G0 = 0.001_dp ! threshold for the G=0 case
    2239            4 :                Ginf = 20.0_dp  ! threshold for the Taylor exapnsion arounf G=∞
    2240       843752 :                DO ig = grid%first_gne0, grid%ngpts_cut_local
    2241       843748 :                   g2 = grid%gsq(ig)
    2242       843748 :                   g = SQRT(g2)
    2243       843752 :                   IF (g <= 2.0_dp*G0) THEN
    2244              :                      gf%array(ig) = -pi/omega2*erf(omega*Rc) &
    2245              :                                     + twopi*Rc2*erf(omega*Rc) &
    2246            0 :                                     + 2*rootpi*Rc*EXP(-omega2*Rc2)/omega
    2247       843748 :                   ELSE IF (g >= 2.0_dp*Ginf*omega) THEN
    2248              :                      ! exponential prefactor
    2249         1488 :                      exp_prefac = EXP(-omega2*Rc2)/(rootpi*(omega2*Rc2 + 0.25_dp*g2/omega2))
    2250              :                      ! cos sin factor
    2251         1488 :                      cossin_fac = omega*Rc*COS(g*Rc) - 0.5_dp*g/omega*SIN(g*Rc)
    2252              :                      ! real erf term with cosine
    2253         1488 :                      erfcos_fac = ERF(omega*Rc)*COS(g*Rc)
    2254              :                      ! Combine terms
    2255         1488 :                      gf%array(ig) = fourpi/g2*(-exp_prefac*cossin_fac - erfcos_fac)
    2256              :                   ELSE
    2257              :                      ! exponential prefactor
    2258       842260 :                      exp_prefac = twopi/g2*EXP(-0.25_dp*g2/omega2)
    2259              :                      ! Compute complex arguments for erf
    2260       842260 :                      z_p = CMPLX(omega*Rc, 0.5_dp*g/omega, kind=dp)
    2261              :                      ! Evaluate complex error functions
    2262       842260 :                      erf_fac_p = 2.0_dp*REAL(erfz_fast(z_p))
    2263              :                      ! Real erf term with cosine
    2264       842260 :                      erfcos_fac = fourpi/g2*ERF(omega*Rc)*COS(g*Rc)
    2265              :                      ! Combine terms
    2266       842260 :                      gf%array(ig) = exp_prefac*erf_fac_p - erfcos_fac
    2267              :                   END IF
    2268              :                END DO
    2269            4 :                IF (grid%have_g0) THEN
    2270              :                   gf%array(1) = -pi/omega2*ERF(omega*Rc) &
    2271              :                                 + twopi*Rc2*ERF(omega*Rc) &
    2272            2 :                                 + 2*rootpi*Rc*EXP(-omega2*Rc2)/omega
    2273              :                END IF
    2274              : 
    2275              :             CASE DEFAULT
    2276           10 :                CPABORT("Please specify a valid operator for the periodic Poisson solver")
    2277              :             END SELECT
    2278              : 
    2279              :             ! The analytic Poisson solver simply limits the domain of integration
    2280              :             ! of the Fourier transform to a sphere of radius Rc, rather than integrating
    2281              :             ! over all space (-∞,∞)
    2282              :          CASE (ANALYTIC0D)
    2283              : 
    2284          180 :             SELECT CASE (eri_env%operator)
    2285              :                ! This is identical to the truncated Coulomb operator integrated
    2286              :                ! over all space, when the truncation radius is equal to the radius of
    2287              :                ! the Poisson solver
    2288              :             CASE (eri_operator_coulomb, eri_operator_trunc)
    2289           82 :                IF (eri_env%operator == eri_operator_coulomb) THEN
    2290           82 :                   Rc = green%radius
    2291              :                ELSE
    2292            0 :                   Rc = eri_env%cutoff_radius
    2293              :                END IF
    2294     24981734 :                DO ig = grid%first_gne0, grid%ngpts_cut_local
    2295     24981652 :                   g2 = grid%gsq(ig)
    2296     24981652 :                   g = SQRT(g2)
    2297              :                   ! Taylor expansion around zero
    2298     24981734 :                   IF (g*Rc >= 0.005_dp) THEN
    2299     24981652 :                      gf%array(ig) = fourpi/g2*(1.0_dp - COS(g*Rc))
    2300              :                   ELSE
    2301            0 :                      gf%array(ig) = fourpi/g2*(g*Rc)**2/2.0_dp*(1.0_dp - (g*Rc)**2/12.0_dp)
    2302              :                   END IF
    2303              :                END DO
    2304           82 :                IF (grid%have_g0) gf%array(1) = twopi*Rc**2
    2305              : 
    2306              :                ! Not tested
    2307              :             CASE (eri_operator_yukawa)
    2308            0 :                CALL cp_warn(__LOCATION__, "Yukawa operator has not been tested")
    2309            0 :                Rc = green%radius
    2310            0 :                omega = eri_env%omega
    2311            0 :                ea = EXP(-omega*Rc)
    2312            0 :                DO ig = grid%first_gne0, grid%ngpts_cut_local
    2313            0 :                   g2 = grid%gsq(ig)
    2314            0 :                   g = SQRT(g2)
    2315            0 :                   g3d = fourpi/(omega**2 + g2)
    2316            0 :                   gf%array(ig) = g3d*(1.0_dp - ea*(COS(g*Rc) + omega/g*SIN(g*Rc)))
    2317              :                END DO
    2318            0 :                IF (grid%have_g0) gf%array(1) = fourpi/(omega**2)*(1.0_dp - ea*(1.0_dp + omega*Rc))
    2319              : 
    2320              :                ! Long-range Coulomb
    2321              :                ! TODO: this should be equivalent to LR truncated Coulomb from above!
    2322              :             CASE (eri_operator_erf, eri_operator_lr_trunc)
    2323           16 :                IF (eri_env%operator == eri_operator_erf) THEN
    2324           16 :                   Rc = green%radius
    2325              :                ELSE
    2326            0 :                   Rc = eri_env%cutoff_radius
    2327              :                END IF
    2328           16 :                omega2 = eri_env%omega**2
    2329      1728008 :                DO ig = grid%first_gne0, grid%ngpts_cut_local
    2330      1727992 :                   g2 = grid%gsq(ig)
    2331      1727992 :                   g = SQRT(g2)
    2332      1727992 :                   ga = -0.25_dp*g2/omega2
    2333      1728008 :                   gf%array(ig) = fourpi/g2*EXP(ga)*(1.0_dp - COS(g*Rc))
    2334              :                END DO
    2335           16 :                IF (grid%have_g0) gf%array(1) = twopi*Rc**2
    2336              : 
    2337              :                ! Short-range Coulomb
    2338              :                ! TODO: this should actually be properly derived and see whether it is correct
    2339              :             CASE (eri_operator_erfc)
    2340              :                CALL cp_warn(__LOCATION__, &
    2341            0 :                             "Short-range Coulomb operator may be incorrect with ANALYTIC0D Poisson solver")
    2342            0 :                Rc = green%radius
    2343            0 :                omega2 = eri_env%omega**2
    2344            0 :                DO ig = grid%first_gne0, grid%ngpts_cut_local
    2345            0 :                   g2 = grid%gsq(ig)
    2346            0 :                   g = SQRT(g2)
    2347            0 :                   ga = -0.25_dp*g2/omega2
    2348            0 :                   gf%array(ig) = fourpi/g2*(1.0_dp - EXP(ga))*(1.0_dp - COS(g*Rc))
    2349              :                END DO
    2350            0 :                IF (grid%have_g0) gf%array(1) = pi/omega2
    2351              : 
    2352              :             CASE DEFAULT
    2353           98 :                CPABORT("Unsupported operator")
    2354              :             END SELECT
    2355              : 
    2356              :          CASE DEFAULT
    2357          108 :             CPABORT("Unsupported Poisson solver")
    2358              :          END SELECT
    2359              :       END ASSOCIATE
    2360              : 
    2361          108 :    END SUBROUTINE pw_eri_green_create
    2362              : 
    2363              : ! **************************************************************************************************
    2364              : !> \brief Adds data for a new row to the csr matrix
    2365              : !> \param csr_mat ...
    2366              : !> \param nnz ...
    2367              : !> \param rdat ...
    2368              : !> \param rind ...
    2369              : !> \param irow ...
    2370              : !> \par History
    2371              : !>      04.2016 created [JGH]
    2372              : ! **************************************************************************************************
    2373          911 :    SUBROUTINE update_csr_matrix(csr_mat, nnz, rdat, rind, irow)
    2374              : 
    2375              :       TYPE(dbcsr_csr_type), INTENT(INOUT)                :: csr_mat
    2376              :       INTEGER, INTENT(IN)                                :: nnz
    2377              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: rdat
    2378              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: rind
    2379              :       INTEGER, INTENT(IN)                                :: irow
    2380              : 
    2381              :       INTEGER                                            :: k, nrow, nze, nze_new
    2382              : 
    2383          911 :       IF (irow /= 0) THEN
    2384          911 :          nze = csr_mat%nze_local
    2385          911 :          nze_new = nze + nnz
    2386              :          ! values
    2387          911 :          CALL reallocate(csr_mat%nzval_local%r_dp, 1, nze_new)
    2388         3572 :          csr_mat%nzval_local%r_dp(nze + 1:nze_new) = rdat(1:nnz)
    2389              :          ! col indices
    2390          911 :          CALL reallocate(csr_mat%colind_local, 1, nze_new)
    2391         3572 :          csr_mat%colind_local(nze + 1:nze_new) = rind(1:nnz)
    2392              :          ! rows
    2393          911 :          nrow = csr_mat%nrows_local
    2394          911 :          CALL reallocate(csr_mat%rowptr_local, 1, irow + 1)
    2395         2426 :          csr_mat%rowptr_local(nrow + 1:irow) = nze + 1
    2396          911 :          csr_mat%rowptr_local(irow + 1) = nze_new + 1
    2397              :          ! nzerow
    2398          911 :          CALL reallocate(csr_mat%nzerow_local, 1, irow)
    2399         2426 :          DO k = nrow + 1, irow
    2400         2426 :             csr_mat%nzerow_local(k) = csr_mat%rowptr_local(k + 1) - csr_mat%rowptr_local(k)
    2401              :          END DO
    2402          911 :          csr_mat%nrows_local = irow
    2403          911 :          csr_mat%nze_local = csr_mat%nze_local + nnz
    2404              :       END IF
    2405          911 :       csr_mat%nze_total = csr_mat%nze_total + nnz
    2406          911 :       csr_mat%has_indices = .TRUE.
    2407              : 
    2408          911 :    END SUBROUTINE update_csr_matrix
    2409              : 
    2410              : ! **************************************************************************************************
    2411              : !> \brief Computes and prints the active orbitals on Cube Files
    2412              : !> \param input ...
    2413              : !> \param qs_env the qs_env in which the qs_env lives
    2414              : !> \param mos ...
    2415              : ! **************************************************************************************************
    2416            4 :    SUBROUTINE print_orbital_cubes(input, qs_env, mos)
    2417              :       TYPE(section_vals_type), POINTER                   :: input
    2418              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2419              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mos
    2420              : 
    2421              :       CHARACTER(LEN=default_path_length)                 :: filebody, filename, title
    2422              :       INTEGER                                            :: i, imo, isp, nmo, str(3), unit_nr
    2423            4 :       INTEGER, DIMENSION(:), POINTER                     :: alist, blist, istride
    2424              :       LOGICAL                                            :: do_mo, explicit_a, explicit_b
    2425            4 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    2426              :       TYPE(cell_type), POINTER                           :: cell
    2427              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
    2428              :       TYPE(dft_control_type), POINTER                    :: dft_control
    2429              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2430              :       TYPE(particle_list_type), POINTER                  :: particles
    2431            4 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    2432              :       TYPE(pw_c1d_gs_type)                               :: wf_g
    2433              :       TYPE(pw_env_type), POINTER                         :: pw_env
    2434              :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
    2435              :       TYPE(pw_r3d_rs_type)                               :: wf_r
    2436            4 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    2437              :       TYPE(qs_subsys_type), POINTER                      :: subsys
    2438              :       TYPE(section_vals_type), POINTER                   :: dft_section, scf_input
    2439              : 
    2440            4 :       CALL section_vals_val_get(input, "FILENAME", c_val=filebody)
    2441            4 :       CALL section_vals_val_get(input, "STRIDE", i_vals=istride)
    2442            4 :       IF (SIZE(istride) == 1) THEN
    2443           16 :          str(1:3) = istride(1)
    2444            0 :       ELSE IF (SIZE(istride) == 3) THEN
    2445            0 :          str(1:3) = istride(1:3)
    2446              :       ELSE
    2447            0 :          CPABORT("STRIDE arguments inconsistent")
    2448              :       END IF
    2449            4 :       CALL section_vals_val_get(input, "ALIST", i_vals=alist, explicit=explicit_a)
    2450            4 :       CALL section_vals_val_get(input, "BLIST", i_vals=blist, explicit=explicit_b)
    2451              : 
    2452              :       CALL get_qs_env(qs_env=qs_env, &
    2453              :                       dft_control=dft_control, &
    2454              :                       para_env=para_env, &
    2455              :                       subsys=subsys, &
    2456              :                       atomic_kind_set=atomic_kind_set, &
    2457              :                       qs_kind_set=qs_kind_set, &
    2458              :                       cell=cell, &
    2459              :                       particle_set=particle_set, &
    2460              :                       pw_env=pw_env, &
    2461            4 :                       input=scf_input)
    2462              : 
    2463            4 :       CALL qs_subsys_get(subsys, particles=particles)
    2464              :       !
    2465            4 :       CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
    2466            4 :       CALL auxbas_pw_pool%create_pw(wf_r)
    2467            4 :       CALL auxbas_pw_pool%create_pw(wf_g)
    2468              :       !
    2469            4 :       dft_section => section_vals_get_subs_vals(scf_input, "DFT")
    2470              :       !
    2471            8 :       DO isp = 1, SIZE(mos)
    2472            4 :          CALL get_mo_set(mo_set=mos(isp), mo_coeff=mo_coeff, nmo=nmo)
    2473              : 
    2474            4 :          IF (SIZE(mos) > 1) THEN
    2475            0 :             SELECT CASE (isp)
    2476              :             CASE (1)
    2477              :                CALL write_mo_set_to_output_unit(mos(isp), qs_kind_set, particle_set, &
    2478            0 :                                                 dft_section, 4, 0, final_mos=.TRUE., spin="ALPHA")
    2479              :             CASE (2)
    2480              :                CALL write_mo_set_to_output_unit(mos(isp), qs_kind_set, particle_set, &
    2481            0 :                                                 dft_section, 4, 0, final_mos=.TRUE., spin="BETA")
    2482              :             CASE DEFAULT
    2483            0 :                CPABORT("Invalid spin")
    2484              :             END SELECT
    2485              :          ELSE
    2486              :             CALL write_mo_set_to_output_unit(mos(isp), qs_kind_set, particle_set, &
    2487            4 :                                              dft_section, 4, 0, final_mos=.TRUE.)
    2488              :          END IF
    2489              : 
    2490           44 :          DO imo = 1, nmo
    2491           32 :             IF (isp == 1 .AND. explicit_a) THEN
    2492           32 :                IF (alist(1) == -1) THEN
    2493              :                   do_mo = .TRUE.
    2494              :                ELSE
    2495           32 :                   do_mo = .FALSE.
    2496          128 :                   DO i = 1, SIZE(alist)
    2497          128 :                      IF (imo == alist(i)) do_mo = .TRUE.
    2498              :                   END DO
    2499              :                END IF
    2500            0 :             ELSE IF (isp == 2 .AND. explicit_b) THEN
    2501            0 :                IF (blist(1) == -1) THEN
    2502              :                   do_mo = .TRUE.
    2503              :                ELSE
    2504            0 :                   do_mo = .FALSE.
    2505            0 :                   DO i = 1, SIZE(blist)
    2506            0 :                      IF (imo == blist(i)) do_mo = .TRUE.
    2507              :                   END DO
    2508              :                END IF
    2509              :             ELSE
    2510              :                do_mo = .TRUE.
    2511              :             END IF
    2512           32 :             IF (.NOT. do_mo) CYCLE
    2513              :             CALL calculate_wavefunction(mo_coeff, imo, wf_r, wf_g, atomic_kind_set, &
    2514           12 :                                         qs_kind_set, cell, dft_control, particle_set, pw_env)
    2515           12 :             IF (para_env%is_source()) THEN
    2516            6 :                WRITE (filename, '(A,A1,I4.4,A1,I1.1,A)') TRIM(filebody), "_", imo, "_", isp, ".cube"
    2517            6 :                CALL open_file(filename, unit_number=unit_nr, file_status="UNKNOWN", file_action="WRITE")
    2518            6 :                WRITE (title, *) "Active Orbital ", imo, " spin ", isp
    2519              :             ELSE
    2520            6 :                unit_nr = -1
    2521              :             END IF
    2522           12 :             CALL cp_pw_to_cube(wf_r, unit_nr, title, particles=particles, stride=istride)
    2523           16 :             IF (para_env%is_source()) THEN
    2524           26 :                CALL close_file(unit_nr)
    2525              :             END IF
    2526              :          END DO
    2527              :       END DO
    2528              : 
    2529            4 :       CALL auxbas_pw_pool%give_back_pw(wf_r)
    2530            4 :       CALL auxbas_pw_pool%give_back_pw(wf_g)
    2531              : 
    2532            4 :    END SUBROUTINE print_orbital_cubes
    2533              : 
    2534              : ! **************************************************************************************************
    2535              : !> \brief Writes a FCIDUMP file
    2536              : !> \param active_space_env ...
    2537              : !> \param as_input ...
    2538              : !> \param restricted ...
    2539              : !> \par History
    2540              : !>      04.2016 created [JGH]
    2541              : ! **************************************************************************************************
    2542          104 :    SUBROUTINE fcidump(active_space_env, as_input, restricted)
    2543              : 
    2544              :       TYPE(active_space_type), POINTER                   :: active_space_env
    2545              :       TYPE(section_vals_type), POINTER                   :: as_input
    2546              :       LOGICAL, INTENT(IN)                                :: restricted
    2547              : 
    2548              :       INTEGER                                            :: i, i1, i2, i3, i4, isym, iw, m1, m2, &
    2549              :                                                             ms2, nmo, norb, nspins
    2550              :       REAL(KIND=dp)                                      :: checksum, esub
    2551          104 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: fmat
    2552              :       TYPE(cp_logger_type), POINTER                      :: logger
    2553              :       TYPE(eri_fcidump_checksum)                         :: eri_checksum
    2554              : 
    2555          104 :       checksum = 0.0_dp
    2556              : 
    2557          208 :       logger => cp_get_default_logger()
    2558              :       iw = cp_print_key_unit_nr(logger, as_input, "FCIDUMP", &
    2559          104 :                                 extension=".fcidump", file_status="REPLACE", file_action="WRITE", file_form="FORMATTED")
    2560              :       !
    2561          104 :       nspins = active_space_env%nspins
    2562          104 :       norb = SIZE(active_space_env%active_orbitals, 1)
    2563          104 :       ms2 = active_space_env%multiplicity - 1
    2564          104 :       IF (nspins == 1 .OR. restricted) THEN
    2565              :          ! Closed shell or restricted open-shell
    2566              :          ASSOCIATE (nelec => active_space_env%nelec_active)
    2567              : 
    2568           92 :             IF (iw > 0) THEN
    2569           46 :                WRITE (iw, "(A,A,I4,A,I4,A,I2,A)") "&FCI", " NORB=", norb, ",NELEC=", nelec, ",MS2=", ms2, ","
    2570           46 :                isym = 1
    2571          187 :                WRITE (iw, "(A,1000(I1,','))") "  ORBSYM=", (isym, i=1, norb)
    2572           46 :                isym = 0
    2573           46 :                WRITE (iw, "(A,I1,A)") "  ISYM=", isym, ","
    2574           46 :                IF (restricted) WRITE (iw, "(A,I1,A)") "  UHF=", 0, ","
    2575           46 :                WRITE (iw, "(A)") " /"
    2576              :             END IF
    2577              :             !
    2578              :             ! Print integrals: ERI
    2579              :             CALL active_space_env%eri%eri_foreach(1, active_space_env%active_orbitals, &
    2580           92 :                                                   eri_fcidump_print(iw, 1, 1), 1, 1)
    2581           92 :             CALL eri_checksum%set(1, 1)
    2582           92 :             CALL active_space_env%eri%eri_foreach(1, active_space_env%active_orbitals, eri_checksum, 1, 1)
    2583              : 
    2584              :             ! Print integrals: Fij
    2585              :             ! replicate Fock matrix
    2586           92 :             nmo = active_space_env%eri%norb
    2587          368 :             ALLOCATE (fmat(nmo, nmo))
    2588           92 :             CALL replicate_and_symmetrize_matrix(nmo, active_space_env%fock_sub(1), fmat)
    2589           92 :             IF (iw > 0) THEN
    2590           46 :                i3 = 0; i4 = 0
    2591          187 :                DO m1 = 1, SIZE(active_space_env%active_orbitals, 1)
    2592          141 :                   i1 = active_space_env%active_orbitals(m1, 1)
    2593          526 :                   DO m2 = m1, SIZE(active_space_env%active_orbitals, 1)
    2594          339 :                      i2 = active_space_env%active_orbitals(m2, 1)
    2595          339 :                      checksum = checksum + ABS(fmat(i1, i2))
    2596          480 :                      WRITE (iw, "(ES23.16,4I4)") fmat(i1, i2), m1, m2, i3, i4
    2597              :                   END DO
    2598              :                END DO
    2599              :             END IF
    2600           92 :             DEALLOCATE (fmat)
    2601              :             ! Print energy
    2602           92 :             esub = active_space_env%energy_inactive
    2603           92 :             i1 = 0; i2 = 0; i3 = 0; i4 = 0
    2604           92 :             checksum = checksum + ABS(esub)
    2605          184 :             IF (iw > 0) WRITE (iw, "(ES23.16,4I4)") esub, i1, i2, i3, i4
    2606              :          END ASSOCIATE
    2607              : 
    2608              :       ELSE
    2609              :          ASSOCIATE (nelec => active_space_env%nelec_active)
    2610              : 
    2611           12 :             IF (iw > 0) THEN
    2612            6 :                WRITE (iw, "(A,A,I4,A,I4,A,I2,A)") "&FCI", " NORB=", norb, ",NELEC=", nelec, ",MS2=", ms2, ","
    2613            6 :                isym = 1
    2614           21 :                WRITE (iw, "(A,1000(I1,','))") "  ORBSYM=", (isym, i=1, norb)
    2615            6 :                isym = 0
    2616            6 :                WRITE (iw, "(A,I1,A)") "  ISYM=", isym, ","
    2617            6 :                WRITE (iw, "(A,I1,A)") "  UHF=", 1, ","
    2618            6 :                WRITE (iw, "(A)") " /"
    2619              :             END IF
    2620              :             !
    2621              :             ! Print integrals: ERI
    2622              :             ! alpha-alpha
    2623              :             CALL active_space_env%eri%eri_foreach(1, active_space_env%active_orbitals, &
    2624           12 :                                                   eri_fcidump_print(iw, 1, 1), 1, 1)
    2625           12 :             CALL eri_checksum%set(1, 1)
    2626           12 :             CALL active_space_env%eri%eri_foreach(1, active_space_env%active_orbitals, eri_checksum, 1, 1)
    2627              :             ! alpha-beta
    2628              :             CALL active_space_env%eri%eri_foreach(2, active_space_env%active_orbitals, &
    2629           12 :                                                   eri_fcidump_print(iw, 1, norb + 1), 1, 2)
    2630           12 :             CALL eri_checksum%set(1, norb + 1)
    2631           12 :             CALL active_space_env%eri%eri_foreach(2, active_space_env%active_orbitals, eri_checksum, 1, 2)
    2632              :             ! beta-beta
    2633              :             CALL active_space_env%eri%eri_foreach(3, active_space_env%active_orbitals, &
    2634           12 :                                                   eri_fcidump_print(iw, norb + 1, norb + 1), 2, 2)
    2635           12 :             CALL eri_checksum%set(norb + 1, norb + 1)
    2636           12 :             CALL active_space_env%eri%eri_foreach(3, active_space_env%active_orbitals, eri_checksum, 2, 2)
    2637              :             ! Print integrals: Fij
    2638              :             ! alpha
    2639           12 :             nmo = active_space_env%eri%norb
    2640           48 :             ALLOCATE (fmat(nmo, nmo))
    2641           12 :             CALL replicate_and_symmetrize_matrix(nmo, active_space_env%fock_sub(1), fmat)
    2642           12 :             IF (iw > 0) THEN
    2643            6 :                i3 = 0; i4 = 0
    2644           21 :                DO m1 = 1, norb
    2645           15 :                   i1 = active_space_env%active_orbitals(m1, 1)
    2646           48 :                   DO m2 = m1, norb
    2647           27 :                      i2 = active_space_env%active_orbitals(m2, 1)
    2648           27 :                      checksum = checksum + ABS(fmat(i1, i2))
    2649           42 :                      WRITE (iw, "(ES23.16,4I4)") fmat(i1, i2), m1, m2, i3, i4
    2650              :                   END DO
    2651              :                END DO
    2652              :             END IF
    2653           12 :             DEALLOCATE (fmat)
    2654              :             ! beta
    2655           36 :             ALLOCATE (fmat(nmo, nmo))
    2656           12 :             CALL replicate_and_symmetrize_matrix(nmo, active_space_env%fock_sub(2), fmat)
    2657           12 :             IF (iw > 0) THEN
    2658            6 :                i3 = 0; i4 = 0
    2659           21 :                DO m1 = 1, SIZE(active_space_env%active_orbitals, 1)
    2660           15 :                   i1 = active_space_env%active_orbitals(m1, 2)
    2661           48 :                   DO m2 = m1, SIZE(active_space_env%active_orbitals, 1)
    2662           27 :                      i2 = active_space_env%active_orbitals(m2, 2)
    2663           27 :                      checksum = checksum + ABS(fmat(i1, i2))
    2664           42 :                      WRITE (iw, "(ES23.16,4I4)") fmat(i1, i2), m1 + norb, m2 + norb, i3, i4
    2665              :                   END DO
    2666              :                END DO
    2667              :             END IF
    2668           12 :             DEALLOCATE (fmat)
    2669              :             ! Print energy
    2670           12 :             esub = active_space_env%energy_inactive
    2671           12 :             i1 = 0; i2 = 0; i3 = 0; i4 = 0
    2672           12 :             checksum = checksum + ABS(esub)
    2673           24 :             IF (iw > 0) WRITE (iw, "(ES23.16,4I4)") esub, i1, i2, i3, i4
    2674              :          END ASSOCIATE
    2675              :       END IF
    2676              :       !
    2677          104 :       CALL cp_print_key_finished_output(iw, logger, as_input, "FCIDUMP")
    2678              : 
    2679              :       !>>
    2680          104 :       iw = cp_logger_get_default_io_unit(logger)
    2681          104 :       IF (iw > 0) WRITE (iw, '(T4,A,T66,F12.8)') "FCIDUMP| Checksum:", eri_checksum%checksum + checksum
    2682              :       !<<
    2683              : 
    2684          208 :    END SUBROUTINE fcidump
    2685              : 
    2686              : ! **************************************************************************************************
    2687              : !> \brief replicate and symmetrize a matrix
    2688              : !> \param norb the number of orbitals
    2689              : !> \param distributed_matrix ...
    2690              : !> \param replicated_matrix ...
    2691              : ! **************************************************************************************************
    2692          440 :    SUBROUTINE replicate_and_symmetrize_matrix(norb, distributed_matrix, replicated_matrix)
    2693              :       INTEGER, INTENT(IN)                                :: norb
    2694              :       TYPE(cp_fm_type), INTENT(IN)                       :: distributed_matrix
    2695              :       REAL(dp), DIMENSION(:, :), INTENT(INOUT)           :: replicated_matrix
    2696              : 
    2697              :       INTEGER                                            :: i1, i2
    2698              :       REAL(dp)                                           :: mval
    2699              : 
    2700        10520 :       replicated_matrix(:, :) = 0.0_dp
    2701         2182 :       DO i1 = 1, norb
    2702         7222 :          DO i2 = i1, norb
    2703         5040 :             CALL cp_fm_get_element(distributed_matrix, i1, i2, mval)
    2704         5040 :             replicated_matrix(i1, i2) = mval
    2705         6782 :             replicated_matrix(i2, i1) = mval
    2706              :          END DO
    2707              :       END DO
    2708          440 :    END SUBROUTINE replicate_and_symmetrize_matrix
    2709              : 
    2710              : ! **************************************************************************************************
    2711              : !> \brief Calculates active space Fock matrix and inactive energy
    2712              : !> \param active_space_env ...
    2713              : !> \param restricted ...
    2714              : !> \par History
    2715              : !>      06.2016 created [JGH]
    2716              : ! **************************************************************************************************
    2717          130 :    SUBROUTINE subspace_fock_matrix(active_space_env, restricted)
    2718              : 
    2719              :       TYPE(active_space_type), POINTER                   :: active_space_env
    2720              :       LOGICAL, INTENT(IN)                                :: restricted
    2721              : 
    2722              :       INTEGER                                            :: i1, i2, is, norb, nspins
    2723              :       REAL(KIND=dp)                                      :: eeri, eref, esub, mval
    2724          130 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: ks_a_mat, ks_a_ref, ks_b_mat, ks_b_ref, &
    2725          130 :                                                             ks_mat, ks_ref, p_a_mat, p_b_mat, p_mat
    2726              :       TYPE(cp_fm_type), POINTER                          :: matrix, mo_coef
    2727              :       TYPE(dbcsr_csr_type), POINTER                      :: eri, eri_aa, eri_ab, eri_bb
    2728              : 
    2729          130 :       eref = active_space_env%energy_ref
    2730          130 :       nspins = active_space_env%nspins
    2731              : 
    2732          130 :       IF (nspins == 1) THEN
    2733           98 :          CALL get_mo_set(active_space_env%mos_active(1), nmo=norb, mo_coeff=mo_coef)
    2734              :          !
    2735              :          ! Loop over ERI, calculate subspace HF energy and Fock matrix
    2736              :          !
    2737              :          ! replicate KS, Core, and P matrices
    2738          784 :          ALLOCATE (ks_mat(norb, norb), ks_ref(norb, norb), p_mat(norb, norb))
    2739           98 :          ks_ref = 0.0_dp
    2740              : 
    2741              :          ! ks_mat contains the KS/Fock matrix (of full density) projected onto the AS MO subspace (f_ref in eq. 19)
    2742           98 :          CALL replicate_and_symmetrize_matrix(norb, active_space_env%ks_sub(1), ks_mat)
    2743           98 :          CALL replicate_and_symmetrize_matrix(norb, active_space_env%p_active(1), p_mat)
    2744              : 
    2745              :          ! compute ks_ref = V_H[rho^A] + V_HFX[rho^A]
    2746           98 :          eri => active_space_env%eri%eri(1)%csr_mat
    2747              :          CALL build_subspace_fock_matrix(active_space_env%active_orbitals, eri, p_mat, ks_ref, &
    2748           98 :                                          active_space_env%eri%comm_exchange)
    2749              : 
    2750              :          ! compute eeri = E_H[rho^A] + E_HFX[rho^A] as
    2751              :          ! eeri = 1/2 * (SUM_pq (V_H[rho^A] + V_HFX[rho^A])_pq * D^A_pq)
    2752         2542 :          eeri = 0.5_dp*SUM(ks_ref*p_mat)
    2753              : 
    2754              :          ! now calculate the inactive energy acoording to eq. 19, that is
    2755              :          ! esub = E^I = E_ref - f_ref .* D^A + E_H[rho^A] + E_HFX[rho^A]
    2756              :          ! where f^ref = ks_mat, which is the KS/Fock matrix in MO basis, transformed previously
    2757              :          ! and is equal to ks_mat = h^0 + V_core + V_H[rho] + V_HFX[rho]
    2758         2542 :          esub = eref - SUM(ks_mat(1:norb, 1:norb)*p_mat(1:norb, 1:norb)) + eeri
    2759              : 
    2760              :          ! reuse ks_mat to store f^I = f^ref - (V_H[rho^A] + V_HFX[rho^A]) according to eq. 20
    2761         2542 :          ks_mat(1:norb, 1:norb) = ks_mat(1:norb, 1:norb) - ks_ref(1:norb, 1:norb)
    2762              :          ! this is now the embedding potential for the AS calculation!
    2763              : 
    2764           98 :          active_space_env%energy_inactive = esub
    2765              : 
    2766           98 :          CALL cp_fm_release(active_space_env%fock_sub)
    2767          392 :          ALLOCATE (active_space_env%fock_sub(nspins))
    2768          196 :          DO is = 1, nspins
    2769           98 :             matrix => active_space_env%ks_sub(is)
    2770              :             CALL cp_fm_create(active_space_env%fock_sub(is), matrix%matrix_struct, &
    2771          196 :                               name="Active Fock operator")
    2772              :          END DO
    2773           98 :          matrix => active_space_env%fock_sub(1)
    2774          594 :          DO i1 = 1, norb
    2775         2542 :             DO i2 = 1, norb
    2776         2046 :                mval = ks_mat(i1, i2)
    2777         2444 :                CALL cp_fm_set_element(matrix, i1, i2, mval)
    2778              :             END DO
    2779              :          END DO
    2780              :       ELSE
    2781              : 
    2782           32 :          CALL get_mo_set(active_space_env%mos_active(1), nmo=norb)
    2783              :          !
    2784              :          ! Loop over ERI, calculate subspace HF energy and Fock matrix
    2785              :          !
    2786              :          ! replicate KS, Core, and P matrices
    2787              :          ALLOCATE (ks_a_mat(norb, norb), ks_b_mat(norb, norb), &
    2788              :               &    ks_a_ref(norb, norb), ks_b_ref(norb, norb), &
    2789          448 :               &     p_a_mat(norb, norb), p_b_mat(norb, norb))
    2790           32 :          ks_a_ref(:, :) = 0.0_dp; ks_b_ref(:, :) = 0.0_dp
    2791              : 
    2792           32 :          CALL replicate_and_symmetrize_matrix(norb, active_space_env%p_active(1), p_a_mat)
    2793           32 :          CALL replicate_and_symmetrize_matrix(norb, active_space_env%p_active(2), p_b_mat)
    2794           32 :          CALL replicate_and_symmetrize_matrix(norb, active_space_env%ks_sub(1), ks_a_mat)
    2795           32 :          CALL replicate_and_symmetrize_matrix(norb, active_space_env%ks_sub(2), ks_b_mat)
    2796              :          !
    2797              :          !
    2798           32 :          IF (restricted) THEN
    2799              :             ! In the restricted case, we use the same ERIs for each spin channel
    2800           12 :             eri_aa => active_space_env%eri%eri(1)%csr_mat
    2801              :             CALL build_subspace_spin_fock_matrix(active_space_env%active_orbitals, eri_aa, eri_aa, p_a_mat, p_b_mat, ks_a_ref, &
    2802              :                                                  tr_mixed_eri=.FALSE., comm_exchange=active_space_env%eri%comm_exchange, &
    2803           12 :                                                  restricted=restricted)
    2804              :             CALL build_subspace_spin_fock_matrix(active_space_env%active_orbitals, eri_aa, eri_aa, p_b_mat, p_a_mat, ks_b_ref, &
    2805              :                                                  tr_mixed_eri=.TRUE., comm_exchange=active_space_env%eri%comm_exchange, &
    2806           12 :                                                  restricted=restricted)
    2807              :          ELSE
    2808           20 :             eri_aa => active_space_env%eri%eri(1)%csr_mat
    2809           20 :             eri_ab => active_space_env%eri%eri(2)%csr_mat
    2810           20 :             eri_bb => active_space_env%eri%eri(3)%csr_mat
    2811              :             CALL build_subspace_spin_fock_matrix(active_space_env%active_orbitals, eri_aa, eri_ab, p_a_mat, p_b_mat, ks_a_ref, &
    2812              :                                                  tr_mixed_eri=.FALSE., comm_exchange=active_space_env%eri%comm_exchange, &
    2813           20 :                                                  restricted=restricted)
    2814              :             CALL build_subspace_spin_fock_matrix(active_space_env%active_orbitals, eri_bb, eri_ab, p_b_mat, p_a_mat, ks_b_ref, &
    2815              :                                                  tr_mixed_eri=.TRUE., comm_exchange=active_space_env%eri%comm_exchange, &
    2816           20 :                                                  restricted=restricted)
    2817              :          END IF
    2818              :          !
    2819              :          ! calculate energy
    2820           32 :          eeri = 0.0_dp
    2821         1336 :          eeri = 0.5_dp*(SUM(ks_a_ref*p_a_mat) + SUM(ks_b_ref*p_b_mat))
    2822         1336 :          esub = eref - SUM(ks_a_mat*p_a_mat) - SUM(ks_b_mat*p_b_mat) + eeri
    2823          668 :          ks_a_mat(:, :) = ks_a_mat(:, :) - ks_a_ref(:, :)
    2824          668 :          ks_b_mat(:, :) = ks_b_mat(:, :) - ks_b_ref(:, :)
    2825              :          !
    2826           32 :          active_space_env%energy_inactive = esub
    2827              :          !
    2828           32 :          CALL cp_fm_release(active_space_env%fock_sub)
    2829          160 :          ALLOCATE (active_space_env%fock_sub(nspins))
    2830           96 :          DO is = 1, nspins
    2831           64 :             matrix => active_space_env%ks_sub(is)
    2832              :             CALL cp_fm_create(active_space_env%fock_sub(is), matrix%matrix_struct, &
    2833           96 :                               name="Active Fock operator")
    2834              :          END DO
    2835              : 
    2836           32 :          matrix => active_space_env%fock_sub(1)
    2837          156 :          DO i1 = 1, norb
    2838          668 :             DO i2 = 1, norb
    2839          512 :                mval = ks_a_mat(i1, i2)
    2840          636 :                CALL cp_fm_set_element(matrix, i1, i2, mval)
    2841              :             END DO
    2842              :          END DO
    2843           32 :          matrix => active_space_env%fock_sub(2)
    2844          188 :          DO i1 = 1, norb
    2845          668 :             DO i2 = 1, norb
    2846          512 :                mval = ks_b_mat(i1, i2)
    2847          636 :                CALL cp_fm_set_element(matrix, i1, i2, mval)
    2848              :             END DO
    2849              :          END DO
    2850              : 
    2851              :       END IF
    2852              : 
    2853          130 :    END SUBROUTINE subspace_fock_matrix
    2854              : 
    2855              : ! **************************************************************************************************
    2856              : !> \brief build subspace fockian
    2857              : !> \param active_orbitals the active orbital indices
    2858              : !> \param eri two electon integrals in MO
    2859              : !> \param p_mat density matrix
    2860              : !> \param ks_ref fockian matrix
    2861              : !> \param comm_exchange ...
    2862              : ! **************************************************************************************************
    2863           98 :    SUBROUTINE build_subspace_fock_matrix(active_orbitals, eri, p_mat, ks_ref, comm_exchange)
    2864              :       INTEGER, DIMENSION(:, :), INTENT(IN)               :: active_orbitals
    2865              :       TYPE(dbcsr_csr_type), INTENT(IN)                   :: eri
    2866              :       REAL(dp), DIMENSION(:, :), INTENT(IN)              :: p_mat
    2867              :       REAL(dp), DIMENSION(:, :), INTENT(INOUT)           :: ks_ref
    2868              :       TYPE(mp_comm_type), INTENT(IN)                     :: comm_exchange
    2869              : 
    2870              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_subspace_fock_matrix'
    2871              : 
    2872              :       INTEGER                                            :: handle, i1, i12, i12l, i2, i3, i34, &
    2873              :                                                             i34l, i4, irptr, m1, m2, nindex, &
    2874              :                                                             nmo_total, norb
    2875              :       REAL(dp)                                           :: erint
    2876              :       TYPE(mp_comm_type)                                 :: mp_group
    2877              : 
    2878           98 :       CALL timeset(routineN, handle)
    2879              : 
    2880              :       ! Nothing to do
    2881           98 :       norb = SIZE(active_orbitals, 1)
    2882           98 :       nmo_total = SIZE(p_mat, 1)
    2883           98 :       nindex = (nmo_total*(nmo_total + 1))/2
    2884           98 :       CALL mp_group%set_handle(eri%mp_group%get_handle())
    2885          424 :       DO m1 = 1, norb
    2886          326 :          i1 = active_orbitals(m1, 1)
    2887         1264 :          DO m2 = m1, norb
    2888          840 :             i2 = active_orbitals(m2, 1)
    2889          840 :             i12 = csr_idx_to_combined(i1, i2, nmo_total)
    2890         1166 :             IF (MOD(i12 - 1, comm_exchange%num_pe) == comm_exchange%mepos) THEN
    2891          831 :                i12l = (i12 - 1)/comm_exchange%num_pe + 1
    2892          831 :                irptr = eri%rowptr_local(i12l) - 1
    2893         3486 :                DO i34l = 1, eri%nzerow_local(i12l)
    2894         2655 :                   i34 = eri%colind_local(irptr + i34l)
    2895         2655 :                   CALL csr_idx_from_combined(i34, nmo_total, i3, i4)
    2896         2655 :                   erint = eri%nzval_local%r_dp(irptr + i34l)
    2897              :                   ! Coulomb
    2898         2655 :                   ks_ref(i1, i2) = ks_ref(i1, i2) + erint*p_mat(i3, i4)
    2899         2655 :                   IF (i3 /= i4) THEN
    2900         1614 :                      ks_ref(i1, i2) = ks_ref(i1, i2) + erint*p_mat(i3, i4)
    2901              :                   END IF
    2902         2655 :                   IF (i12 /= i34) THEN
    2903         2235 :                      ks_ref(i3, i4) = ks_ref(i3, i4) + erint*p_mat(i1, i2)
    2904         2235 :                      IF (i1 /= i2) THEN
    2905         1617 :                         ks_ref(i3, i4) = ks_ref(i3, i4) + erint*p_mat(i1, i2)
    2906              :                      END IF
    2907              :                   END IF
    2908              :                   ! Exchange
    2909         2655 :                   erint = -0.5_dp*erint
    2910         2655 :                   ks_ref(i1, i3) = ks_ref(i1, i3) + erint*p_mat(i2, i4)
    2911         2655 :                   IF (i1 /= i2) THEN
    2912         1874 :                      ks_ref(i2, i3) = ks_ref(i2, i3) + erint*p_mat(i1, i4)
    2913              :                   END IF
    2914         2655 :                   IF (i3 /= i4) THEN
    2915         1614 :                      ks_ref(i1, i4) = ks_ref(i1, i4) + erint*p_mat(i2, i3)
    2916              :                   END IF
    2917         2655 :                   IF (i1 /= i2 .AND. i3 /= i4) THEN
    2918         1253 :                      ks_ref(i2, i4) = ks_ref(i2, i4) + erint*p_mat(i1, i3)
    2919              :                   END IF
    2920              :                   ! The stored integral represents both orders of unequal orbital pairs.
    2921         6141 :                   IF (i12 /= i34) THEN
    2922         2235 :                      ks_ref(i3, i1) = ks_ref(i3, i1) + erint*p_mat(i4, i2)
    2923         2235 :                      IF (i1 /= i2) THEN
    2924         1617 :                         ks_ref(i3, i2) = ks_ref(i3, i2) + erint*p_mat(i4, i1)
    2925              :                      END IF
    2926         2235 :                      IF (i3 /= i4) THEN
    2927         1357 :                         ks_ref(i4, i1) = ks_ref(i4, i1) + erint*p_mat(i3, i2)
    2928              :                      END IF
    2929         2235 :                      IF (i1 /= i2 .AND. i3 /= i4) THEN
    2930          996 :                         ks_ref(i4, i2) = ks_ref(i4, i2) + erint*p_mat(i3, i1)
    2931              :                      END IF
    2932              :                   END IF
    2933              :                END DO
    2934              :             END IF
    2935              :          END DO
    2936              :       END DO
    2937              :       !
    2938          424 :       DO m1 = 1, norb
    2939          326 :          i1 = active_orbitals(m1, 1)
    2940         1264 :          DO m2 = m1, norb
    2941          840 :             i2 = active_orbitals(m2, 1)
    2942         1166 :             ks_ref(i2, i1) = ks_ref(i1, i2)
    2943              :          END DO
    2944              :       END DO
    2945         4986 :       CALL mp_group%sum(ks_ref)
    2946              : 
    2947           98 :       CALL timestop(handle)
    2948              : 
    2949           98 :    END SUBROUTINE build_subspace_fock_matrix
    2950              : 
    2951              : ! **************************************************************************************************
    2952              : !> \brief build subspace fockian for unrestricted spins
    2953              : !> \param active_orbitals the active orbital indices
    2954              : !> \param eri_aa two electon integrals in MO with parallel spins
    2955              : !> \param eri_ab two electon integrals in MO with anti-parallel spins
    2956              : !> \param p_a_mat density matrix for up-spin
    2957              : !> \param p_b_mat density matrix for down-spin
    2958              : !> \param ks_a_ref fockian matrix for up-spin
    2959              : !> \param tr_mixed_eri boolean to indicate Coulomb interaction alignment
    2960              : !> \param comm_exchange ...
    2961              : !> \param restricted use the common, eightfold-symmetric ERIs for both spin densities
    2962              : ! **************************************************************************************************
    2963           64 :    SUBROUTINE build_subspace_spin_fock_matrix(active_orbitals, eri_aa, eri_ab, p_a_mat, p_b_mat, ks_a_ref, tr_mixed_eri, &
    2964              :                                               comm_exchange, restricted)
    2965              :       INTEGER, DIMENSION(:, :), INTENT(IN)               :: active_orbitals
    2966              :       TYPE(dbcsr_csr_type), INTENT(IN)                   :: eri_aa, eri_ab
    2967              :       REAL(dp), DIMENSION(:, :), INTENT(IN)              :: p_a_mat, p_b_mat
    2968              :       REAL(dp), DIMENSION(:, :), INTENT(INOUT)           :: ks_a_ref
    2969              :       LOGICAL, INTENT(IN)                                :: tr_mixed_eri
    2970              :       TYPE(mp_comm_type), INTENT(IN)                     :: comm_exchange
    2971              :       LOGICAL, INTENT(IN)                                :: restricted
    2972              : 
    2973              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_subspace_spin_fock_matrix'
    2974              : 
    2975              :       INTEGER                                            :: handle, i1, i12, i12l, i2, i3, i34, &
    2976              :                                                             i34l, i4, irptr, m1, m2, nindex, &
    2977              :                                                             nmo_total, norb, spin1, spin2
    2978              :       REAL(dp)                                           :: erint, p12, p34
    2979              :       TYPE(mp_comm_type)                                 :: mp_group
    2980              : 
    2981           64 :       CALL timeset(routineN, handle)
    2982              : 
    2983           64 :       norb = SIZE(active_orbitals, 1)
    2984           64 :       nmo_total = SIZE(p_a_mat, 1)
    2985           64 :       nindex = (nmo_total*(nmo_total + 1))/2
    2986           64 :       IF (tr_mixed_eri) THEN
    2987              :          spin1 = 2
    2988           64 :          spin2 = 1
    2989              :       ELSE
    2990           32 :          spin1 = 1
    2991           32 :          spin2 = 2
    2992              :       END IF
    2993          276 :       DO m1 = 1, norb
    2994          212 :          i1 = active_orbitals(m1, spin1)
    2995          756 :          DO m2 = m1, norb
    2996          480 :             i2 = active_orbitals(m2, spin1)
    2997          480 :             i12 = csr_idx_to_combined(i1, i2, nmo_total)
    2998          692 :             IF (MOD(i12 - 1, comm_exchange%num_pe) == comm_exchange%mepos) THEN
    2999          480 :                i12l = (i12 - 1)/comm_exchange%num_pe + 1
    3000          480 :                irptr = eri_aa%rowptr_local(i12l) - 1
    3001         1631 :                DO i34l = 1, eri_aa%nzerow_local(i12l)
    3002         1151 :                   i34 = eri_aa%colind_local(irptr + i34l)
    3003         1151 :                   CALL csr_idx_from_combined(i34, nmo_total, i3, i4)
    3004         1151 :                   erint = eri_aa%nzval_local%r_dp(irptr + i34l)
    3005              :                   ! Coulomb
    3006         1151 :                   p12 = p_a_mat(i1, i2)
    3007         1151 :                   p34 = p_a_mat(i3, i4)
    3008         1151 :                   IF (restricted) THEN
    3009          560 :                      p12 = p12 + p_b_mat(i1, i2)
    3010          560 :                      p34 = p34 + p_b_mat(i3, i4)
    3011              :                   END IF
    3012         1151 :                   IF (i1 /= i2) p12 = 2.0_dp*p12
    3013         1151 :                   IF (i3 /= i4) p34 = 2.0_dp*p34
    3014              :                   !F_ij += (ij|kl)*d_kl
    3015         1151 :                   ks_a_ref(i1, i2) = ks_a_ref(i1, i2) + erint*p34
    3016         1151 :                   IF (i12 /= i34) THEN
    3017              :                      !F_kl += (ij|kl)*d_ij
    3018          911 :                      ks_a_ref(i3, i4) = ks_a_ref(i3, i4) + erint*p12
    3019              :                   END IF
    3020              :                   ! Exchange
    3021         1151 :                   erint = -1.0_dp*erint
    3022              :                   !F_ik -= (ij|kl)*d_jl
    3023         1151 :                   ks_a_ref(i1, i3) = ks_a_ref(i1, i3) + erint*p_a_mat(i2, i4)
    3024         1151 :                   IF (i1 /= i2) THEN
    3025              :                      !F_jk -= (ij|kl)*d_il
    3026          705 :                      ks_a_ref(i2, i3) = ks_a_ref(i2, i3) + erint*p_a_mat(i1, i4)
    3027              :                   END IF
    3028         1151 :                   IF (i3 /= i4) THEN
    3029              :                      !F_il -= (ij|kl)*d_jk
    3030          628 :                      ks_a_ref(i1, i4) = ks_a_ref(i1, i4) + erint*p_a_mat(i2, i3)
    3031              :                   END IF
    3032         1151 :                   IF (i1 /= i2 .AND. i3 /= i4) THEN
    3033              :                      !F_jl -= (ij|kl)*d_ik
    3034          422 :                      ks_a_ref(i2, i4) = ks_a_ref(i2, i4) + erint*p_a_mat(i1, i3)
    3035              :                   END IF
    3036         2782 :                   IF (i12 /= i34) THEN
    3037          911 :                      ks_a_ref(i3, i1) = ks_a_ref(i3, i1) + erint*p_a_mat(i4, i2)
    3038          911 :                      IF (i1 /= i2) THEN
    3039          571 :                         ks_a_ref(i3, i2) = ks_a_ref(i3, i2) + erint*p_a_mat(i4, i1)
    3040              :                      END IF
    3041          911 :                      IF (i3 /= i4) THEN
    3042          494 :                         ks_a_ref(i4, i1) = ks_a_ref(i4, i1) + erint*p_a_mat(i3, i2)
    3043              :                      END IF
    3044          911 :                      IF (i1 /= i2 .AND. i3 /= i4) THEN
    3045          288 :                         ks_a_ref(i4, i2) = ks_a_ref(i4, i2) + erint*p_a_mat(i3, i1)
    3046              :                      END IF
    3047              :                   END IF
    3048              :                END DO
    3049              :             END IF
    3050              :          END DO
    3051              :       END DO
    3052              :       !
    3053              : 
    3054              :       ! Shared-orbital Coulomb contributions from both spins were included above.
    3055           64 :       IF (.NOT. restricted) THEN
    3056          164 :          DO m1 = 1, norb
    3057          124 :             i1 = active_orbitals(m1, 1)
    3058          432 :             DO m2 = m1, norb
    3059          268 :                i2 = active_orbitals(m2, 1)
    3060          268 :                i12 = csr_idx_to_combined(i1, i2, nmo_total)
    3061          392 :                IF (MOD(i12 - 1, comm_exchange%num_pe) == comm_exchange%mepos) THEN
    3062          268 :                   i12l = (i12 - 1)/comm_exchange%num_pe + 1
    3063          268 :                   irptr = eri_ab%rowptr_local(i12l) - 1
    3064         1310 :                   DO i34l = 1, eri_ab%nzerow_local(i12l)
    3065         1042 :                      i34 = eri_ab%colind_local(irptr + i34l)
    3066         1042 :                      CALL csr_idx_from_combined(i34, nmo_total, i3, i4)
    3067         1042 :                      erint = eri_ab%nzval_local%r_dp(irptr + i34l)
    3068              :                      ! Coulomb
    3069         1310 :                      IF (tr_mixed_eri) THEN
    3070              :                         !F_kl += (kl beta|ij alpha )*d_alpha_ij
    3071          521 :                         ks_a_ref(i3, i4) = ks_a_ref(i3, i4) + erint*p_b_mat(i1, i2)
    3072          521 :                         IF (i1 /= i2) ks_a_ref(i3, i4) = ks_a_ref(i3, i4) + erint*p_b_mat(i1, i2)
    3073              :                      ELSE
    3074              :                         !F_ij += (ij alpha|kl beta )*d_beta_kl
    3075          521 :                         ks_a_ref(i1, i2) = ks_a_ref(i1, i2) + erint*p_b_mat(i3, i4)
    3076          521 :                         IF (i3 /= i4) ks_a_ref(i1, i2) = ks_a_ref(i1, i2) + erint*p_b_mat(i3, i4)
    3077              :                      END IF
    3078              :                   END DO
    3079              :                END IF
    3080              :             END DO
    3081              :          END DO
    3082              :       END IF
    3083              :       !
    3084          276 :       DO m1 = 1, norb
    3085          212 :          i1 = active_orbitals(m1, spin1)
    3086          756 :          DO m2 = m1, norb
    3087          480 :             i2 = active_orbitals(m2, spin1)
    3088          692 :             ks_a_ref(i2, i1) = ks_a_ref(i1, i2)
    3089              :          END DO
    3090              :       END DO
    3091           64 :       CALL mp_group%set_handle(eri_aa%mp_group%get_handle())
    3092         2608 :       CALL mp_group%sum(ks_a_ref)
    3093              : 
    3094           64 :       CALL timestop(handle)
    3095              : 
    3096           64 :    END SUBROUTINE build_subspace_spin_fock_matrix
    3097              : 
    3098              : ! **************************************************************************************************
    3099              : !> \brief Creates a local basis
    3100              : !> \param pro_basis_set ...
    3101              : !> \param zval ...
    3102              : !> \param ishell ...
    3103              : !> \param nshell ...
    3104              : !> \param lnam ...
    3105              : !> \par History
    3106              : !>      05.2016 created [JGH]
    3107              : ! **************************************************************************************************
    3108            0 :    SUBROUTINE create_pro_basis(pro_basis_set, zval, ishell, nshell, lnam)
    3109              :       TYPE(gto_basis_set_type), POINTER                  :: pro_basis_set
    3110              :       INTEGER, INTENT(IN)                                :: zval, ishell
    3111              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: nshell
    3112              :       CHARACTER(len=*), DIMENSION(:), INTENT(IN)         :: lnam
    3113              : 
    3114            0 :       CHARACTER(len=6), DIMENSION(:), POINTER            :: sym
    3115              :       INTEGER                                            :: i, l, nj
    3116              :       INTEGER, DIMENSION(4, 7)                           :: ne
    3117            0 :       INTEGER, DIMENSION(:), POINTER                     :: lq, nq
    3118            0 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: zet
    3119              :       TYPE(sto_basis_set_type), POINTER                  :: sto_basis_set
    3120              : 
    3121            0 :       CPASSERT(.NOT. ASSOCIATED(pro_basis_set))
    3122            0 :       NULLIFY (sto_basis_set)
    3123              : 
    3124              :       ! electronic configuration
    3125            0 :       ne = 0
    3126            0 :       DO l = 1, 4 !lq(1)+1
    3127            0 :          nj = 2*(l - 1) + 1
    3128            0 :          DO i = l, 7 ! nq(1)
    3129            0 :             ne(l, i) = ptable(zval)%e_conv(l - 1) - 2*nj*(i - l)
    3130            0 :             ne(l, i) = MAX(ne(l, i), 0)
    3131            0 :             ne(l, i) = MIN(ne(l, i), 2*nj)
    3132              :          END DO
    3133              :       END DO
    3134            0 :       ALLOCATE (nq(ishell), lq(ishell), zet(ishell), sym(ishell))
    3135            0 :       DO i = 1, ishell
    3136            0 :          nq(i) = nshell(i)
    3137            0 :          SELECT CASE (lnam(i))
    3138              :          CASE ('S', 's')
    3139            0 :             lq(i) = 0
    3140              :          CASE ('P', 'p')
    3141            0 :             lq(i) = 1
    3142              :          CASE ('D', 'd')
    3143            0 :             lq(i) = 2
    3144              :          CASE ('F', 'f')
    3145            0 :             lq(i) = 3
    3146              :          CASE DEFAULT
    3147            0 :             CPABORT("Wrong l QN")
    3148              :          END SELECT
    3149            0 :          sym(i) = lnam(i)
    3150            0 :          zet(i) = srules(zval, ne, nq(1), lq(1))
    3151              :       END DO
    3152            0 :       CALL allocate_sto_basis_set(sto_basis_set)
    3153            0 :       CALL set_sto_basis_set(sto_basis_set, nshell=1, nq=nq, lq=lq, zet=zet, symbol=sym)
    3154            0 :       CALL create_gto_from_sto_basis(sto_basis_set, pro_basis_set, 6)
    3155            0 :       pro_basis_set%norm_type = 2
    3156            0 :       CALL init_orb_basis_set(pro_basis_set)
    3157            0 :       CALL deallocate_sto_basis_set(sto_basis_set)
    3158              : 
    3159            0 :    END SUBROUTINE create_pro_basis
    3160              : 
    3161              : ! **************************************************************************************************
    3162              : !> \brief Update the density matrix in AO basis with the active density contribution
    3163              : !> \param active_space_env the active space environment
    3164              : !> \param rho_ao the density matrix in AO basis
    3165              : ! **************************************************************************************************
    3166           22 :    SUBROUTINE update_density_ao(active_space_env, rho_ao)
    3167              :       TYPE(active_space_type), POINTER                   :: active_space_env
    3168              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: rho_ao
    3169              : 
    3170              :       INTEGER                                            :: ispin, nao, nmo, nspins
    3171              :       TYPE(cp_fm_type)                                   :: R, U
    3172              :       TYPE(cp_fm_type), POINTER                          :: C_active, p_active_mo
    3173              :       TYPE(dbcsr_type), POINTER                          :: p_inactive_ao
    3174           22 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos_active
    3175              : 
    3176              :       ! Transform the AS density matrix P_MO to the atomic orbital basis,
    3177              :       ! this is simply C * P_MO * C^T
    3178           22 :       nspins = active_space_env%nspins
    3179           22 :       mos_active => active_space_env%mos_active
    3180           58 :       DO ispin = 1, nspins
    3181              :          ! size of p_inactive_ao is (nao x nao)
    3182           36 :          p_inactive_ao => active_space_env%pmat_inactive(ispin)%matrix
    3183              : 
    3184              :          ! copy p_inactive_ao to rho_ao
    3185           36 :          CALL dbcsr_copy(rho_ao(ispin)%matrix, p_inactive_ao)
    3186              : 
    3187              :          ! size of p_active_mo is (nmo x nmo)
    3188           36 :          p_active_mo => active_space_env%p_active(ispin)
    3189              : 
    3190              :          ! calculate R = p_mo
    3191           36 :          CALL cp_fm_create(R, p_active_mo%matrix_struct)
    3192           36 :          CALL cp_fm_to_fm(p_active_mo, R)
    3193              : 
    3194              :          ! calculate U = C * p_mo
    3195           36 :          CALL get_mo_set(mos_active(ispin), mo_coeff=C_active, nao=nao, nmo=nmo)
    3196           36 :          CALL cp_fm_create(U, C_active%matrix_struct)
    3197           36 :          CALL parallel_gemm("N", "N", nao, nmo, nmo, 1.0_dp, C_active, R, 0.0_dp, U)
    3198              : 
    3199              :          CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=rho_ao(ispin)%matrix, &
    3200           36 :                                     matrix_v=U, matrix_g=C_active, ncol=nmo, alpha=1.0_dp)
    3201              : 
    3202           36 :          CALL cp_fm_release(R)
    3203          130 :          CALL cp_fm_release(U)
    3204              :       END DO
    3205              : 
    3206           22 :    END SUBROUTINE update_density_ao
    3207              : 
    3208              : ! **************************************************************************************************
    3209              : !> \brief Print each value on the master node
    3210              : !> \param this object reference
    3211              : !> \param i i-index
    3212              : !> \param j j-index
    3213              : !> \param k k-index
    3214              : !> \param l l-index
    3215              : !> \param val value of the integral at (i,j,k.l)
    3216              : !> \return always true to dump all integrals
    3217              : ! **************************************************************************************************
    3218         4792 :    LOGICAL FUNCTION eri_fcidump_print_func(this, i, j, k, l, val) RESULT(cont)
    3219              :       CLASS(eri_fcidump_print), INTENT(inout) :: this
    3220              :       INTEGER, INTENT(in)                     :: i, j, k, l
    3221              :       REAL(KIND=dp), INTENT(in)               :: val
    3222              : 
    3223              :       ! write to the actual file only on the master
    3224         4792 :       IF (this%unit_nr > 0) THEN
    3225         2396 :          WRITE (this%unit_nr, "(ES23.16,4I4)") val, i + this%bra_start - 1, j + this%bra_start - 1, &
    3226         4792 :               &                                     k + this%ket_start - 1, l + this%ket_start - 1
    3227              :       END IF
    3228              : 
    3229         4792 :       cont = .TRUE.
    3230         4792 :    END FUNCTION eri_fcidump_print_func
    3231              : 
    3232              : ! **************************************************************************************************
    3233              : !> \brief checksum each value on the master node
    3234              : !> \param this object reference
    3235              : !> \param i i-index
    3236              : !> \param j j-index
    3237              : !> \param k k-index
    3238              : !> \param l l-index
    3239              : !> \param val value of the integral at (i,j,k.l)
    3240              : !> \return always true to dump all integrals
    3241              : ! **************************************************************************************************
    3242         4792 :    LOGICAL FUNCTION eri_fcidump_checksum_func(this, i, j, k, l, val) RESULT(cont)
    3243              :       CLASS(eri_fcidump_checksum), INTENT(inout) :: this
    3244              :       INTEGER, INTENT(in)                     :: i, j, k, l
    3245              :       REAL(KIND=dp), INTENT(in)               :: val
    3246              :       MARK_USED(i)
    3247              :       MARK_USED(j)
    3248              :       MARK_USED(k)
    3249              :       MARK_USED(l)
    3250              : 
    3251         4792 :       this%checksum = this%checksum + ABS(val)
    3252              : 
    3253         4792 :       cont = .TRUE.
    3254         4792 :    END FUNCTION eri_fcidump_checksum_func
    3255              : 
    3256              : ! **************************************************************************************************
    3257              : !> \brief Compute and print the AS rdm and the natural orbitals occupation numbers
    3258              : !> \param active_space_env active space environment
    3259              : !> \param iw output unit
    3260              : !> \author Stefano Battaglia
    3261              : ! **************************************************************************************************
    3262            6 :    SUBROUTINE print_pmat_noon(active_space_env, iw)
    3263              :       TYPE(active_space_type), POINTER                   :: active_space_env
    3264              :       INTEGER                                            :: iw
    3265              : 
    3266              :       INTEGER                                            :: i1, i2, ii, ispin, jm, m1, m2, &
    3267              :                                                             nmo_active, nspins
    3268            6 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: noon, pmat
    3269              :       TYPE(cp_fm_type), POINTER                          :: p_active
    3270              : 
    3271            6 :       nspins = active_space_env%nspins
    3272            6 :       nmo_active = active_space_env%nmo_active
    3273              : 
    3274           24 :       ALLOCATE (noon(nmo_active, nspins))
    3275           24 :       ALLOCATE (pmat(nmo_active, nmo_active))
    3276              : 
    3277           16 :       DO ispin = 1, nspins
    3278           10 :          p_active => active_space_env%p_active(ispin)
    3279           54 :          noon(:, ispin) = 0.0_dp
    3280           10 :          pmat = 0.0_dp
    3281              : 
    3282           54 :          DO i1 = 1, nmo_active
    3283           44 :             m1 = active_space_env%active_orbitals(i1, ispin)
    3284          254 :             DO i2 = 1, nmo_active
    3285          200 :                m2 = active_space_env%active_orbitals(i2, ispin)
    3286          244 :                CALL cp_fm_get_element(p_active, m1, m2, pmat(i1, i2))
    3287              :             END DO
    3288              :          END DO
    3289              : 
    3290           10 :          IF (iw > 0) THEN
    3291            5 :             WRITE (iw, '(/,T3,A,I2,A)') "Active space density matrix for spin ", ispin
    3292           27 :             DO i1 = 1, nmo_active
    3293           49 :                DO ii = 1, nmo_active, 8
    3294           22 :                   jm = MIN(7, nmo_active - ii)
    3295          144 :                   WRITE (iw, '(T3,6(F9.4))') (pmat(i1, ii + i2), i2=0, jm)
    3296              :                END DO
    3297              :             END DO
    3298              :          END IF
    3299              : 
    3300              :          ! diagonalize the density matrix
    3301           10 :          CALL diamat_all(pmat, noon(:, ispin))
    3302              : 
    3303           16 :          IF (iw > 0) THEN
    3304            5 :             WRITE (iw, '(/,T3,A,I2,A)') "Natural orbitals occupation numbers for spin ", ispin
    3305           10 :             DO i1 = 1, nmo_active, 8
    3306            5 :                jm = MIN(7, nmo_active - i1)
    3307              :                ! noons are stored in ascending order, so reverse-print them
    3308           32 :                WRITE (iw, '(T3,6(F9.4))') (noon(nmo_active - i1 - i2 + 1, ispin), i2=0, jm)
    3309              :             END DO
    3310              :          END IF
    3311              : 
    3312              :       END DO
    3313              : 
    3314            6 :       DEALLOCATE (noon)
    3315            6 :       DEALLOCATE (pmat)
    3316              : 
    3317            6 :    END SUBROUTINE print_pmat_noon
    3318              : 
    3319              : ! **************************************************************************************************
    3320              : !> \brief Run range-separated DFT embedding with the local FCI active-space solver.
    3321              : !> \param qs_env Quickstep environment
    3322              : !> \param active_space_env active-space environment
    3323              : !> \param as_input ACTIVE_SPACE input section
    3324              : ! **************************************************************************************************
    3325            6 :    SUBROUTINE local_fci_embedding(qs_env, active_space_env, as_input)
    3326              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    3327              :       TYPE(active_space_type), POINTER                   :: active_space_env
    3328              :       TYPE(section_vals_type), POINTER                   :: as_input
    3329              : 
    3330              :       CHARACTER(len=*), PARAMETER :: routineN = 'local_fci_embedding'
    3331              : 
    3332              :       INTEGER                                            :: handle, iter, iw, max_iter
    3333              :       LOGICAL                                            :: converged, do_scf_embedding
    3334              :       REAL(KIND=dp)                                      :: delta_E, energy_corr, energy_new, &
    3335              :                                                             energy_old, energy_scf, eps_iter, t1, &
    3336              :                                                             t2
    3337            6 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: p_act_mo_a, p_act_mo_b
    3338              :       TYPE(cp_logger_type), POINTER                      :: logger
    3339            6 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: rho_ao
    3340              :       TYPE(dft_control_type), POINTER                    :: dft_control
    3341              :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos_active
    3342              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    3343              :       TYPE(qs_energy_type), POINTER                      :: energy
    3344              :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
    3345              :       TYPE(qs_rho_type), POINTER                         :: rho
    3346              : 
    3347            6 :       CALL timeset(routineN, handle)
    3348              : 
    3349            6 :       t1 = m_walltime()
    3350            6 :       logger => cp_get_default_logger()
    3351            6 :       iw = cp_logger_get_default_io_unit(logger)
    3352              : 
    3353            6 :       CALL get_qs_env(qs_env, para_env=para_env, dft_control=dft_control)
    3354              : 
    3355            6 :       CALL section_vals_val_get(as_input, "SCF_EMBEDDING", l_val=do_scf_embedding)
    3356            6 :       active_space_env%do_scf_embedding = do_scf_embedding
    3357            6 :       CALL section_vals_val_get(as_input, "MAX_ITER", i_val=max_iter)
    3358            6 :       IF (max_iter < 0) CPABORT("Specify a non-negative number of max iterations.")
    3359            6 :       CALL section_vals_val_get(as_input, "EPS_ITER", r_val=eps_iter)
    3360            6 :       IF (eps_iter < 0.0_dp) CPABORT("Specify a non-negative convergence threshold.")
    3361              : 
    3362            6 :       CALL get_qs_env(qs_env, rho=rho, energy=energy, ks_env=ks_env)
    3363            6 :       CALL qs_rho_get(rho, rho_ao=rho_ao)
    3364              : 
    3365            6 :       IF (iw > 0) THEN
    3366              :          WRITE (UNIT=iw, FMT="(/,T2,A,/)") &
    3367            3 :             "RANGE-SEPARATED DFT EMBEDDING WITH LIBFCI SOLVER"
    3368            3 :          WRITE (iw, '(T3,A,T68,I12)') "Max. iterations", max_iter
    3369            3 :          WRITE (iw, '(T3,A,T68,E12.4)') "Conv. threshold", eps_iter
    3370            3 :          WRITE (iw, '(T3,A,T68,A)') "Density mixer", TRIM(active_space_mixing_label(active_space_env))
    3371            3 :          WRITE (iw, '(T3,A,T66,F14.2)') "Mixing alpha", active_space_env%alpha
    3372              :          WRITE (UNIT=iw, FMT="(/,T3,A,T11,A,T21,A,T34,A,T55,A,T75,A,/,T3,A)") &
    3373            3 :             "Iter", "Update", "Time", "Corr. energy", "Total energy", "Change", REPEAT("-", 78)
    3374              :       END IF
    3375              : 
    3376            6 :       iter = 0
    3377            6 :       converged = .FALSE.
    3378            6 :       energy_scf = active_space_env%energy_ref
    3379            6 :       energy_new = energy_scf
    3380            6 :       mos_active => active_space_env%mos_active
    3381              : 
    3382           22 :       DO WHILE (iter < max_iter)
    3383           22 :          iter = iter + 1
    3384              : 
    3385           22 :          IF (active_space_env%nspins == 2) THEN
    3386           14 :             CALL solve_active_space_fci(active_space_env, para_env, p_act_mo_a, p_act_mo_b)
    3387           14 :             active_space_env%energy_total = active_space_env%energy_inactive + active_space_env%energy_active
    3388           14 :             CALL update_active_density(p_act_mo_a, active_space_env, p_act_mo_b)
    3389           14 :             DEALLOCATE (p_act_mo_a, p_act_mo_b)
    3390              :          ELSE
    3391            8 :             CALL solve_active_space_fci(active_space_env, para_env, p_act_mo_a)
    3392            8 :             active_space_env%energy_total = active_space_env%energy_inactive + active_space_env%energy_active
    3393            8 :             CALL update_active_density(p_act_mo_a, active_space_env)
    3394            8 :             DEALLOCATE (p_act_mo_a)
    3395              :          END IF
    3396              : 
    3397           22 :          energy_old = energy_new
    3398           22 :          energy_new = active_space_env%energy_total
    3399           22 :          energy_corr = energy_new - energy_scf
    3400           22 :          delta_E = energy_new - energy_old
    3401              : 
    3402           22 :          t2 = t1
    3403           22 :          t1 = m_walltime()
    3404           22 :          IF (iw > 0) THEN
    3405              :             WRITE (UNIT=iw, &
    3406              :                    FMT="(T3,I4,T11,A,T19,F6.1,T28,F18.10,T49,F18.10,T70,ES11.2)") &
    3407           11 :                iter, TRIM(active_space_mixing_label(active_space_env)), &
    3408           22 :                t1 - t2, energy_corr, energy_new, delta_E
    3409           11 :             CALL m_flush(iw)
    3410              :          END IF
    3411              : 
    3412           22 :          CALL update_density_ao(active_space_env, rho_ao)
    3413           22 :          CALL qs_rho_update_rho(rho, qs_env=qs_env)
    3414           22 :          CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
    3415           22 :          CALL evaluate_core_matrix_traces(qs_env)
    3416              :          CALL qs_ks_build_kohn_sham_matrix(qs_env, calculate_forces=.FALSE., &
    3417              :                                            just_energy=.FALSE., &
    3418           22 :                                            ext_xc_section=active_space_env%xc_section)
    3419              : 
    3420           22 :          active_space_env%energy_ref = energy%total
    3421           22 :          CALL calculate_operators(mos_active, qs_env, active_space_env)
    3422           22 :          CALL subspace_fock_matrix(active_space_env, dft_control%roks)
    3423              : 
    3424           22 :          IF (.NOT. active_space_env%do_scf_embedding) THEN
    3425            0 :             IF (iw > 0) THEN
    3426              :                WRITE (UNIT=iw, FMT="(/,T3,A,I5,A)") &
    3427            0 :                   "*** one-shot embedding correction finished ***"
    3428              :             END IF
    3429              :             converged = .TRUE.
    3430              :             EXIT
    3431           22 :          ELSE IF (ABS(delta_E) <= eps_iter) THEN
    3432            6 :             IF (iw > 0) THEN
    3433              :                WRITE (UNIT=iw, FMT="(/,T3,A,I5,A)") &
    3434            3 :                   "*** rs-DFT embedding run converged in ", iter, " iteration(s) ***"
    3435              :             END IF
    3436              :             converged = .TRUE.
    3437              :             EXIT
    3438              :          END IF
    3439              :       END DO
    3440              : 
    3441              :       IF (.NOT. converged) THEN
    3442            0 :          IF (iw > 0) THEN
    3443              :             WRITE (UNIT=iw, FMT="(/,T3,A,I5,A)") &
    3444            0 :                "*** rs-DFT embedding did not converged after ", iter, " iteration(s) ***"
    3445              :          END IF
    3446              :       END IF
    3447              : 
    3448            6 :       energy%total = active_space_env%energy_total
    3449              : 
    3450            6 :       IF (iw > 0) THEN
    3451              :          WRITE (UNIT=iw, FMT="(/,T3,A)") &
    3452            3 :             "Final energy contributions:"
    3453              :          WRITE (UNIT=iw, FMT="(T6,A,T56,F20.10)") &
    3454            3 :             "Inactive energy:", active_space_env%energy_inactive
    3455              :          WRITE (UNIT=iw, FMT="(T6,A,T56,F20.10)") &
    3456            3 :             "Active energy:", active_space_env%energy_active
    3457              :          WRITE (UNIT=iw, FMT="(T6,A,T56,F20.10)") &
    3458            3 :             "Correlation energy:", energy_corr
    3459              :          WRITE (UNIT=iw, FMT="(T6,A,T56,F20.10)") &
    3460            3 :             "Total rs-DFT energy:", active_space_env%energy_total
    3461              :       END IF
    3462              : 
    3463            6 :       CALL print_pmat_noon(active_space_env, iw)
    3464            6 :       CALL para_env%sync()
    3465            6 :       CALL timestop(handle)
    3466              : 
    3467           12 :    END SUBROUTINE local_fci_embedding
    3468              : 
    3469              : ! **************************************************************************************************
    3470              : !> \brief ...
    3471              : !> \param qs_env ...
    3472              : !> \param active_space_env ...
    3473              : !> \param as_input ...
    3474              : ! **************************************************************************************************
    3475            0 :    SUBROUTINE rsdft_embedding(qs_env, active_space_env, as_input)
    3476              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    3477              :       TYPE(active_space_type), POINTER                   :: active_space_env
    3478              :       TYPE(section_vals_type), POINTER                   :: as_input
    3479              : 
    3480              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'rsdft_embedding'
    3481              :       INTEGER                                            :: handle
    3482              : 
    3483              : #ifdef __NO_SOCKETS
    3484              :       CALL timeset(routineN, handle)
    3485              :       CPABORT("CP2K was compiled with the __NO_SOCKETS option!")
    3486              :       MARK_USED(qs_env)
    3487              :       MARK_USED(active_space_env)
    3488              :       MARK_USED(as_input)
    3489              : #else
    3490              : 
    3491              :       INTEGER                                            :: iw, client_fd, socket_fd, iter, max_iter
    3492              :       LOGICAL                                            :: converged, do_scf_embedding, ionode
    3493              :       REAL(KIND=dp)                                      :: delta_E, energy_corr, energy_new, &
    3494              :                                                             energy_old, energy_scf, eps_iter, t1, t2
    3495              :       TYPE(cp_logger_type), POINTER                      :: logger
    3496            0 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: rho_ao
    3497              :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos_active
    3498              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    3499              :       TYPE(qs_energy_type), POINTER                      :: energy
    3500              :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
    3501              :       TYPE(qs_rho_type), POINTER                         :: rho
    3502              :       TYPE(dft_control_type), POINTER                    :: dft_control
    3503              : 
    3504            0 :       CALL timeset(routineN, handle)
    3505              : 
    3506            0 :       t1 = m_walltime()
    3507              : 
    3508            0 :       logger => cp_get_default_logger()
    3509            0 :       iw = cp_logger_get_default_io_unit(logger)
    3510              : 
    3511            0 :       CALL get_qs_env(qs_env, para_env=para_env, dft_control=dft_control)
    3512            0 :       ionode = para_env%is_source()
    3513              : 
    3514              :       ! get info from the input
    3515            0 :       CALL section_vals_val_get(as_input, "SCF_EMBEDDING", l_val=do_scf_embedding)
    3516            0 :       active_space_env%do_scf_embedding = do_scf_embedding
    3517            0 :       CALL section_vals_val_get(as_input, "MAX_ITER", i_val=max_iter)
    3518            0 :       IF (max_iter < 0) CPABORT("Specify a non-negative number of max iterations.")
    3519            0 :       CALL section_vals_val_get(as_input, "EPS_ITER", r_val=eps_iter)
    3520            0 :       IF (eps_iter < 0.0_dp) CPABORT("Specify a non-negative convergence threshold.")
    3521              : 
    3522              :       ! create the socket and wait for the client to connect
    3523            0 :       CALL initialize_socket(socket_fd, client_fd, as_input, ionode)
    3524            0 :       CALL para_env%sync()
    3525              : 
    3526              :       ! send two-electron integrals to the client
    3527            0 :       CALL send_eri_to_client(client_fd, active_space_env, para_env)
    3528              : 
    3529              :       ! get pointer to density in ao basis
    3530            0 :       CALL get_qs_env(qs_env, rho=rho, energy=energy, ks_env=ks_env)
    3531            0 :       CALL qs_rho_get(rho, rho_ao=rho_ao)
    3532              : 
    3533            0 :       IF (iw > 0) THEN
    3534              :          WRITE (UNIT=iw, FMT="(/,T2,A,/)") &
    3535            0 :             "RANGE-SEPARATED DFT EMBEDDING SELF-CONSISTENT OPTIMIZATION"
    3536              : 
    3537            0 :          WRITE (iw, '(T3,A,T68,I12)') "Max. iterations", max_iter
    3538            0 :          WRITE (iw, '(T3,A,T68,E12.4)') "Conv. threshold", eps_iter
    3539            0 :          WRITE (iw, '(T3,A,T68,A)') "Density mixer", TRIM(active_space_mixing_label(active_space_env))
    3540            0 :          WRITE (iw, '(T3,A,T66,F14.2)') "Mixing alpha", active_space_env%alpha
    3541              : 
    3542              :          WRITE (UNIT=iw, FMT="(/,T3,A,T11,A,T21,A,T34,A,T55,A,T75,A,/,T3,A)") &
    3543            0 :             "Iter", "Update", "Time", "Corr. energy", "Total energy", "Change", REPEAT("-", 78)
    3544              :       END IF
    3545              :       ! TODO: consider using an iteration level
    3546              : 
    3547            0 :       iter = 0
    3548            0 :       converged = .FALSE.
    3549              :       ! store the scf energy
    3550            0 :       energy_scf = active_space_env%energy_ref
    3551            0 :       energy_new = energy_scf
    3552            0 :       mos_active => active_space_env%mos_active
    3553              :       ! CALL set_qs_env(qs_env, active_space=active_space_env)
    3554              : 
    3555              :       ! start the self-consistent embedding loop
    3556            0 :       DO WHILE (iter < max_iter)
    3557            0 :          iter = iter + 1
    3558              : 
    3559              :          ! send V_emb and E_ina to the active space solver and update
    3560              :          ! the active space environment with the new active energy and density
    3561            0 :          CALL send_fock_to_client(client_fd, active_space_env, para_env)
    3562              : 
    3563              :          ! update energies
    3564            0 :          energy_old = energy_new
    3565            0 :          energy_new = active_space_env%energy_total
    3566            0 :          energy_corr = energy_new - energy_scf
    3567            0 :          delta_E = energy_new - energy_old
    3568              : 
    3569              :          ! get timer
    3570            0 :          t2 = t1
    3571            0 :          t1 = m_walltime()
    3572              :          ! print out progress
    3573            0 :          IF ((iw > 0)) THEN
    3574              :             WRITE (UNIT=iw, &
    3575              :                    FMT="(T3,I4,T11,A,T19,F6.1,T28,F18.10,T49,F18.10,T70,ES11.2)") &
    3576            0 :                iter, TRIM(active_space_mixing_label(active_space_env)), &
    3577            0 :                t1 - t2, energy_corr, energy_new, delta_E
    3578            0 :             CALL m_flush(iw)
    3579              :          END IF
    3580              : 
    3581              :          ! update total density in AO basis with the AS contribution
    3582            0 :          CALL update_density_ao(active_space_env, rho_ao) ! rho_ao is updated
    3583              : 
    3584              :          ! calculate F_ks in AO basis (which contains Vxc) with the new density
    3585            0 :          CALL qs_rho_update_rho(rho, qs_env=qs_env) ! updates rho_r and rho_g using rho_ao
    3586            0 :          CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.) ! set flags about the change
    3587              :          ! Re-evaluate the traces between the density matrix and the core Hamiltonians
    3588            0 :          CALL evaluate_core_matrix_traces(qs_env)
    3589              :          ! the ks matrix will be rebuilt so this is fine now
    3590              :          ! CALL set_ks_env(qs_env%ks_env, potential_changed=.FALSE.)
    3591              :          CALL qs_ks_build_kohn_sham_matrix(qs_env, calculate_forces=.FALSE., &
    3592              :                                            just_energy=.FALSE., &
    3593            0 :                                            ext_xc_section=active_space_env%xc_section)
    3594              : 
    3595              :          ! update the reference energy
    3596            0 :          active_space_env%energy_ref = energy%total
    3597              : 
    3598              :          ! transform KS/Fock, Vxc and Hcore from AO to MO basis
    3599            0 :          CALL calculate_operators(mos_active, qs_env, active_space_env)
    3600              : 
    3601              :          ! calculate the new inactive energy and embedding potential
    3602            0 :          CALL subspace_fock_matrix(active_space_env, dft_control%roks)
    3603              : 
    3604              :          ! check if it is a one-shot correction
    3605            0 :          IF (.NOT. active_space_env%do_scf_embedding) THEN
    3606            0 :             IF (iw > 0) THEN
    3607              :                WRITE (UNIT=iw, FMT="(/,T3,A,I5,A)") &
    3608            0 :                   "*** one-shot embedding correction finished ***"
    3609              :             END IF
    3610              :             converged = .TRUE.
    3611              :             EXIT
    3612              :             ! check for convergence
    3613            0 :          ELSE IF (ABS(delta_E) <= eps_iter) THEN
    3614            0 :             IF (iw > 0) THEN
    3615              :                WRITE (UNIT=iw, FMT="(/,T3,A,I5,A)") &
    3616            0 :                   "*** rs-DFT embedding run converged in ", iter, " iteration(s) ***"
    3617              :             END IF
    3618              :             converged = .TRUE.
    3619              :             EXIT
    3620              :          END IF
    3621              :       END DO
    3622              : 
    3623              :       IF (.NOT. converged) THEN
    3624            0 :          IF (iw > 0) THEN
    3625              :             WRITE (UNIT=iw, FMT="(/,T3,A,I5,A)") &
    3626            0 :                "*** rs-DFT embedding did not converged after ", iter, " iteration(s) ***"
    3627              :          END IF
    3628              :       END IF
    3629              : 
    3630              :       ! update qs total energy to the final rs-DFT energy
    3631            0 :       energy%total = active_space_env%energy_total
    3632              : 
    3633              :       ! print final energy contributions
    3634            0 :       IF (iw > 0) THEN
    3635              :          WRITE (UNIT=iw, FMT="(/,T3,A)") &
    3636            0 :             "Final energy contributions:"
    3637              :          WRITE (UNIT=iw, FMT="(T6,A,T56,F20.10)") &
    3638            0 :             "Inactive energy:", active_space_env%energy_inactive
    3639              :          WRITE (UNIT=iw, FMT="(T6,A,T56,F20.10)") &
    3640            0 :             "Active energy:", active_space_env%energy_active
    3641              :          WRITE (UNIT=iw, FMT="(T6,A,T56,F20.10)") &
    3642            0 :             "Correlation energy:", energy_corr
    3643              :          WRITE (UNIT=iw, FMT="(T6,A,T56,F20.10)") &
    3644            0 :             "Total rs-DFT energy:", active_space_env%energy_total
    3645              :       END IF
    3646              : 
    3647              :       ! print the AS rdm and the natural orbital occupation numbers
    3648            0 :       CALL print_pmat_noon(active_space_env, iw)
    3649              : 
    3650            0 :       CALL finalize_socket(socket_fd, client_fd, as_input, ionode)
    3651            0 :       CALL para_env%sync()
    3652              : #endif
    3653              : 
    3654            0 :       CALL timestop(handle)
    3655              : 
    3656            0 :    END SUBROUTINE rsdft_embedding
    3657              : 
    3658              : #ifndef __NO_SOCKETS
    3659              : ! **************************************************************************************************
    3660              : !> \brief Creates the socket, spawns the client and connects to it
    3661              : !> \param socket_fd the socket file descriptor
    3662              : !> \param client_fd the client file descriptor
    3663              : !> \param as_input active space inpute section
    3664              : !> \param ionode logical flag indicating if the process is the master
    3665              : ! **************************************************************************************************
    3666            0 :    SUBROUTINE initialize_socket(socket_fd, client_fd, as_input, ionode)
    3667              :       INTEGER, INTENT(OUT)                               :: socket_fd, client_fd
    3668              :       TYPE(section_vals_type), INTENT(IN), POINTER       :: as_input
    3669              :       LOGICAL, INTENT(IN)                                :: ionode
    3670              : 
    3671              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'initialize_socket'
    3672              :       INTEGER, PARAMETER                                 :: backlog = 10
    3673              : 
    3674              :       CHARACTER(len=default_path_length)                 :: hostname
    3675              :       INTEGER                                            :: handle, iw, port, protocol
    3676              :       LOGICAL                                            :: inet
    3677              :       TYPE(cp_logger_type), POINTER                      :: logger
    3678              : 
    3679            0 :       CALL timeset(routineN, handle)
    3680              : 
    3681            0 :       logger => cp_get_default_logger()
    3682            0 :       iw = cp_logger_get_default_io_unit(logger)
    3683              : 
    3684              :       ! protocol == 0 for UNIX, protocol > 0 for INET
    3685            0 :       CALL section_vals_val_get(as_input, "SOCKET%INET", l_val=inet)
    3686            0 :       IF (inet) THEN
    3687            0 :          protocol = 1
    3688              :       ELSE
    3689            0 :          protocol = 0
    3690              :       END IF
    3691            0 :       CALL section_vals_val_get(as_input, "SOCKET%HOST", c_val=hostname)
    3692            0 :       CALL section_vals_val_get(as_input, "SOCKET%PORT", i_val=port)
    3693              : 
    3694            0 :       IF (ionode) THEN
    3695            0 :          CALL open_bind_socket(socket_fd, protocol, port, TRIM(hostname)//C_NULL_CHAR)
    3696            0 :          WRITE (iw, '(/,T2,A,A)') "@SERVER: Created socket with address ", TRIM(hostname)
    3697            0 :          CALL listen_socket(socket_fd, backlog)
    3698              : 
    3699              :          ! wait until a connetion request arrives
    3700            0 :          WRITE (iw, '(T2,A)') "@SERVER: Waiting for requests..."
    3701            0 :          CALL accept_socket(socket_fd, client_fd)
    3702            0 :          WRITE (iw, '(T2,A,I2)') "@SERVER: Accepted socket with fd ", client_fd
    3703              :       END IF
    3704              : 
    3705            0 :       CALL timestop(handle)
    3706              : 
    3707            0 :    END SUBROUTINE initialize_socket
    3708              : 
    3709              : ! **************************************************************************************************
    3710              : !> \brief Closes the connection to the socket and deletes the file
    3711              : !> \param socket_fd the socket file descriptor
    3712              : !> \param client_fd the client file descriptor
    3713              : !> \param as_input active space inpute section
    3714              : !> \param ionode logical flag indicating if the process is the master
    3715              : ! **************************************************************************************************
    3716            0 :    SUBROUTINE finalize_socket(socket_fd, client_fd, as_input, ionode)
    3717              :       INTEGER, INTENT(IN)                                :: socket_fd, client_fd
    3718              :       TYPE(section_vals_type), INTENT(IN), POINTER       :: as_input
    3719              :       LOGICAL, INTENT(IN)                                :: ionode
    3720              : 
    3721              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'finalize_socket'
    3722              :       INTEGER, PARAMETER                                 :: header_len = 12
    3723              : 
    3724              :       CHARACTER(len=default_path_length)                 :: hostname
    3725              :       INTEGER                                            :: handle
    3726              : 
    3727            0 :       CALL timeset(routineN, handle)
    3728              : 
    3729            0 :       CALL section_vals_val_get(as_input, "SOCKET%HOST", c_val=hostname)
    3730              : 
    3731            0 :       IF (ionode) THEN
    3732              :          ! signal the client to quit
    3733            0 :          CALL writebuffer(client_fd, "QUIT        ", header_len)
    3734              :          ! close the connection
    3735            0 :          CALL close_socket(client_fd)
    3736            0 :          CALL close_socket(socket_fd)
    3737              : 
    3738              :          ! delete the socket file
    3739            0 :          IF (file_exists(TRIM(hostname))) THEN
    3740            0 :             CALL remove_socket_file(TRIM(hostname)//C_NULL_CHAR)
    3741              :          END IF
    3742              :       END IF
    3743              : 
    3744            0 :       CALL timestop(handle)
    3745              : 
    3746            0 :    END SUBROUTINE finalize_socket
    3747              : 
    3748              : ! **************************************************************************************************
    3749              : !> \brief Sends the two-electron integrals to the client vie the socket
    3750              : !> \param client_fd the client file descriptor
    3751              : !> \param active_space_env active space environment
    3752              : !> \param para_env parallel environment
    3753              : ! **************************************************************************************************
    3754            0 :    SUBROUTINE send_eri_to_client(client_fd, active_space_env, para_env)
    3755              :       INTEGER, INTENT(IN)                                :: client_fd
    3756              :       TYPE(active_space_type), INTENT(IN), POINTER       :: active_space_env
    3757              :       TYPE(mp_para_env_type), INTENT(IN), POINTER        :: para_env
    3758              : 
    3759              :       CHARACTER(len=*), PARAMETER :: routineN = 'send_eri_to_client'
    3760              :       INTEGER, PARAMETER                                 :: header_len = 12
    3761              : 
    3762              :       CHARACTER(len=default_string_length)               :: header
    3763              :       INTEGER                                            :: handle, iw
    3764              :       LOGICAL                                            :: ionode, restricted_orbitals
    3765            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eri_aa, eri_ab, eri_bb, s_ab
    3766              :       TYPE(cp_logger_type), POINTER                      :: logger
    3767              : 
    3768            0 :       CALL timeset(routineN, handle)
    3769              : 
    3770            0 :       logger => cp_get_default_logger()
    3771            0 :       iw = cp_logger_get_default_io_unit(logger)
    3772            0 :       ionode = para_env%is_source()
    3773            0 :       restricted_orbitals = active_space_env%restricted_orbitals
    3774              : 
    3775            0 :       ALLOCATE (eri_aa(active_space_env%nmo_active**4))
    3776            0 :       CALL eri_to_array(active_space_env%eri, eri_aa, active_space_env%active_orbitals, 1, 1)
    3777            0 :       IF (active_space_env%nspins == 2) THEN
    3778            0 :          ALLOCATE (eri_ab(active_space_env%nmo_active**4))
    3779            0 :          ALLOCATE (eri_bb(active_space_env%nmo_active**4))
    3780            0 :          IF (restricted_orbitals) THEN
    3781            0 :             eri_ab(:) = eri_aa
    3782            0 :             eri_bb(:) = eri_aa
    3783              :          ELSE
    3784            0 :             CALL eri_to_array(active_space_env%eri, eri_ab, active_space_env%active_orbitals, 1, 2)
    3785            0 :             CALL eri_to_array(active_space_env%eri, eri_bb, active_space_env%active_orbitals, 2, 2)
    3786              :          END IF
    3787              :          ! get the overlap_ab matrix into Fortran array
    3788            0 :          ALLOCATE (s_ab(active_space_env%nmo_active**2))
    3789              :          ASSOCIATE (act_indices_a => active_space_env%active_orbitals(:, 1), &
    3790              :                     act_indices_b => active_space_env%active_orbitals(:, 2))
    3791            0 :             CALL subspace_matrix_to_array(active_space_env%sab_sub(1), s_ab, act_indices_a, act_indices_b)
    3792              :          END ASSOCIATE
    3793              :       END IF
    3794              : 
    3795              :       ! ask the status of the client
    3796            0 :       IF (ionode) CALL writebuffer(client_fd, "STATUS      ", header_len)
    3797              :       DO
    3798            0 :          header = ""
    3799            0 :          CALL para_env%sync()
    3800            0 :          IF (ionode) THEN
    3801              :             ! IF (iw > 0) WRITE(iw, *) "@SERVER: Waiting for messages..."
    3802            0 :             CALL readbuffer(client_fd, header, header_len)
    3803              :          END IF
    3804            0 :          CALL para_env%bcast(header, para_env%source)
    3805              : 
    3806              :          ! IF (iw > 0) WRITE(iw, *) "@SERVER: Message from client: ", TRIM(header)
    3807              : 
    3808            0 :          IF (TRIM(header) == "READY") THEN
    3809              :             ! if the client is ready, send the data
    3810            0 :             CALL para_env%sync()
    3811            0 :             IF (ionode) THEN
    3812            0 :                CALL writebuffer(client_fd, "TWOBODY     ", header_len)
    3813            0 :                CALL writebuffer(client_fd, active_space_env%nspins)
    3814            0 :                CALL writebuffer(client_fd, active_space_env%nmo_active)
    3815            0 :                CALL writebuffer(client_fd, active_space_env%nelec_active)
    3816            0 :                CALL writebuffer(client_fd, active_space_env%multiplicity)
    3817              :                ! send the alpha component
    3818            0 :                CALL writebuffer(client_fd, eri_aa, SIZE(eri_aa))
    3819              :                ! send the beta part for unrestricted calculations
    3820            0 :                IF (active_space_env%nspins == 2) THEN
    3821            0 :                   CALL writebuffer(client_fd, eri_ab, SIZE(eri_ab))
    3822            0 :                   CALL writebuffer(client_fd, eri_bb, SIZE(eri_bb))
    3823            0 :                   CALL writebuffer(client_fd, s_ab, SIZE(s_ab))
    3824              :                END IF
    3825              :             END IF
    3826            0 :          ELSE IF (TRIM(header) == "RECEIVED") THEN
    3827              :             EXIT
    3828              :          END IF
    3829              :       END DO
    3830              : 
    3831            0 :       DEALLOCATE (eri_aa)
    3832            0 :       IF (active_space_env%nspins == 2) THEN
    3833            0 :          DEALLOCATE (eri_ab)
    3834            0 :          DEALLOCATE (eri_bb)
    3835            0 :          DEALLOCATE (s_ab)
    3836              :       END IF
    3837              : 
    3838            0 :       CALL para_env%sync()
    3839              : 
    3840            0 :       CALL timestop(handle)
    3841              : 
    3842            0 :    END SUBROUTINE send_eri_to_client
    3843              : 
    3844              : ! **************************************************************************************************
    3845              : !> \brief Sends the one-electron embedding potential and the inactive energy to the client
    3846              : !> \param client_fd the client file descriptor
    3847              : !> \param active_space_env active space environment
    3848              : !> \param para_env parallel environment
    3849              : ! **************************************************************************************************
    3850            0 :    SUBROUTINE send_fock_to_client(client_fd, active_space_env, para_env)
    3851              :       INTEGER, INTENT(IN)                                :: client_fd
    3852              :       TYPE(active_space_type), INTENT(INOUT), POINTER    :: active_space_env
    3853              :       TYPE(mp_para_env_type), INTENT(IN), POINTER        :: para_env
    3854              : 
    3855              :       CHARACTER(len=*), PARAMETER :: routineN = 'send_fock_to_client'
    3856              :       INTEGER, PARAMETER                                 :: header_len = 12
    3857              : 
    3858              :       CHARACTER(len=default_string_length)               :: header
    3859              :       INTEGER                                            :: handle, iw
    3860              :       LOGICAL                                            :: debug, ionode
    3861            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: fock_a, fock_b, p_act_mo_a, p_act_mo_b
    3862              :       TYPE(cp_logger_type), POINTER                      :: logger
    3863              : 
    3864            0 :       CALL timeset(routineN, handle)
    3865              : 
    3866              :       ! Set to .TRUE. to activate debug output
    3867            0 :       debug = .FALSE.
    3868              : 
    3869            0 :       logger => cp_get_default_logger()
    3870            0 :       iw = cp_logger_get_default_io_unit(logger)
    3871            0 :       ionode = para_env%is_source()
    3872              : 
    3873            0 :       ALLOCATE (p_act_mo_a(active_space_env%nmo_active**2))
    3874            0 :       ALLOCATE (fock_a(active_space_env%nmo_active**2))
    3875            0 :       IF (active_space_env%nspins == 2) THEN
    3876            0 :          ALLOCATE (p_act_mo_b(active_space_env%nmo_active**2))
    3877            0 :          ALLOCATE (fock_b(active_space_env%nmo_active**2))
    3878              :       END IF
    3879              : 
    3880              :       ! get the fock matrix into Fortran arrays
    3881              :       ASSOCIATE (act_indices => active_space_env%active_orbitals(:, 1))
    3882            0 :          CALL subspace_matrix_to_array(active_space_env%fock_sub(1), fock_a, act_indices, act_indices)
    3883              :       END ASSOCIATE
    3884              : 
    3885            0 :       IF (active_space_env%nspins == 2) THEN
    3886              :          ASSOCIATE (act_indices => active_space_env%active_orbitals(:, 2))
    3887            0 :             CALL subspace_matrix_to_array(active_space_env%fock_sub(2), fock_b, act_indices, act_indices)
    3888              :          END ASSOCIATE
    3889              :       END IF
    3890              : 
    3891              :       ! ask the status of the client
    3892            0 :       IF (ionode) CALL writebuffer(client_fd, "STATUS      ", header_len)
    3893              :       DO
    3894            0 :          header = ""
    3895              : 
    3896            0 :          CALL para_env%sync()
    3897            0 :          IF (ionode) THEN
    3898              :             IF (debug .AND. iw > 0) WRITE (iw, *) "@SERVER: Waiting for messages..."
    3899            0 :             CALL readbuffer(client_fd, header, header_len)
    3900              :          END IF
    3901            0 :          CALL para_env%bcast(header, para_env%source)
    3902              : 
    3903              :          IF (debug .AND. iw > 0) WRITE (iw, *) "@SERVER: Message from client: ", TRIM(header)
    3904              : 
    3905            0 :          IF (TRIM(header) == "READY") THEN
    3906              :             ! if the client is ready, send the data
    3907            0 :             CALL para_env%sync()
    3908            0 :             IF (ionode) THEN
    3909            0 :                CALL writebuffer(client_fd, "ONEBODY     ", header_len)
    3910            0 :                CALL writebuffer(client_fd, active_space_env%energy_inactive)
    3911              :                ! send the alpha component
    3912            0 :                CALL writebuffer(client_fd, fock_a, SIZE(fock_a))
    3913              :                ! send the beta part for unrestricted calculations
    3914            0 :                IF (active_space_env%nspins == 2) THEN
    3915            0 :                   CALL writebuffer(client_fd, fock_b, SIZE(fock_b))
    3916              :                END IF
    3917              :             END IF
    3918              : 
    3919            0 :          ELSE IF (TRIM(header) == "HAVEDATA") THEN
    3920              :             ! qiskit has data to transfer, let them know we want it and wait for it
    3921            0 :             CALL para_env%sync()
    3922            0 :             IF (ionode) THEN
    3923              :                IF (debug .AND. iw > 0) WRITE (iw, *) "@SERVER: Qiskit has data to transfer"
    3924            0 :                CALL writebuffer(client_fd, "GETDENSITY  ", header_len)
    3925              : 
    3926              :                ! read the active energy and density
    3927            0 :                CALL readbuffer(client_fd, active_space_env%energy_active)
    3928            0 :                CALL readbuffer(client_fd, p_act_mo_a, SIZE(p_act_mo_a))
    3929            0 :                IF (active_space_env%nspins == 2) THEN
    3930            0 :                   CALL readbuffer(client_fd, p_act_mo_b, SIZE(p_act_mo_b))
    3931              :                END IF
    3932              :             END IF
    3933              : 
    3934              :             ! broadcast the data to all processors
    3935            0 :             CALL para_env%bcast(active_space_env%energy_active, para_env%source)
    3936            0 :             CALL para_env%bcast(p_act_mo_a, para_env%source)
    3937            0 :             IF (active_space_env%nspins == 2) THEN
    3938            0 :                CALL para_env%bcast(p_act_mo_b, para_env%source)
    3939              :             END IF
    3940              : 
    3941              :             ! update total and reference energies in active space enviornment
    3942            0 :             active_space_env%energy_total = active_space_env%energy_inactive + active_space_env%energy_active
    3943              : 
    3944              :             ! update the active density matrix in the active space environment
    3945            0 :             IF (active_space_env%nspins == 2) THEN
    3946            0 :                CALL update_active_density(p_act_mo_a, active_space_env, p_act_mo_b)
    3947              :             ELSE
    3948            0 :                CALL update_active_density(p_act_mo_a, active_space_env)
    3949              :             END IF
    3950              : 
    3951              :             ! the non-iterative part is done, we can continue
    3952              :             EXIT
    3953              :          END IF
    3954              : 
    3955              :       END DO
    3956              : 
    3957            0 :       DEALLOCATE (p_act_mo_a)
    3958            0 :       DEALLOCATE (fock_a)
    3959            0 :       IF (active_space_env%nspins == 2) THEN
    3960            0 :          DEALLOCATE (p_act_mo_b)
    3961            0 :          DEALLOCATE (fock_b)
    3962              :       END IF
    3963              : 
    3964            0 :       CALL para_env%sync()
    3965              : 
    3966            0 :       CALL timestop(handle)
    3967              : 
    3968            0 :    END SUBROUTINE send_fock_to_client
    3969              : #endif
    3970              : 
    3971            0 : END MODULE qs_active_space_methods
        

Generated by: LCOV version 2.0-1