LCOV - code coverage report
Current view: top level - src - xas_tdp_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:42dac4a) Lines: 85.0 % 1568 1333
Test Date: 2025-07-25 12:55:17 Functions: 92.0 % 25 23

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Methods for X-Ray absorption spectroscopy (XAS) using TDDFPT
      10              : !> \author AB (11.2017)
      11              : ! **************************************************************************************************
      12              : 
      13              : MODULE xas_tdp_methods
      14              :    USE admm_types,                      ONLY: admm_type
      15              :    USE admm_utils,                      ONLY: admm_correct_for_eigenvalues,&
      16              :                                               admm_uncorrect_for_eigenvalues
      17              :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      18              :                                               get_atomic_kind
      19              :    USE basis_set_types,                 ONLY: &
      20              :         allocate_sto_basis_set, create_gto_from_sto_basis, deallocate_gto_basis_set, &
      21              :         deallocate_sto_basis_set, get_gto_basis_set, gto_basis_set_type, init_orb_basis_set, &
      22              :         set_sto_basis_set, srules, sto_basis_set_type
      23              :    USE bibliography,                    ONLY: Bussy2021a,&
      24              :                                               cite_reference
      25              :    USE cell_types,                      ONLY: cell_type,&
      26              :                                               pbc
      27              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      28              :    USE cp_control_types,                ONLY: dft_control_type
      29              :    USE cp_dbcsr_api,                    ONLY: &
      30              :         dbcsr_complete_redistribute, dbcsr_copy, dbcsr_create, dbcsr_filter, dbcsr_finalize, &
      31              :         dbcsr_get_info, dbcsr_get_occupation, dbcsr_multiply, dbcsr_p_type, dbcsr_release, &
      32              :         dbcsr_set, dbcsr_type, dbcsr_type_antisymmetric, dbcsr_type_no_symmetry, &
      33              :         dbcsr_type_symmetric
      34              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_add_on_diag
      35              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      36              :                                               copy_fm_to_dbcsr,&
      37              :                                               cp_dbcsr_sm_fm_multiply
      38              :    USE cp_files,                        ONLY: close_file,&
      39              :                                               open_file
      40              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_column_scale
      41              :    USE cp_fm_diag,                      ONLY: cp_fm_geeig,&
      42              :                                               cp_fm_power,&
      43              :                                               cp_fm_syevd
      44              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      45              :                                               cp_fm_struct_release,&
      46              :                                               cp_fm_struct_type
      47              :    USE cp_fm_types,                     ONLY: &
      48              :         cp_fm_copy_general, cp_fm_create, cp_fm_get_diag, cp_fm_get_info, cp_fm_get_submatrix, &
      49              :         cp_fm_read_unformatted, cp_fm_release, cp_fm_set_all, cp_fm_to_fm, cp_fm_to_fm_submat, &
      50              :         cp_fm_type, cp_fm_write_unformatted
      51              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      52              :                                               cp_logger_get_default_io_unit,&
      53              :                                               cp_logger_type,&
      54              :                                               cp_to_string
      55              :    USE cp_output_handling,              ONLY: cp_p_file,&
      56              :                                               cp_print_key_finished_output,&
      57              :                                               cp_print_key_generate_filename,&
      58              :                                               cp_print_key_should_output,&
      59              :                                               cp_print_key_unit_nr,&
      60              :                                               debug_print_level
      61              :    USE input_constants,                 ONLY: &
      62              :         do_admm_purify_cauchy_subspace, do_admm_purify_mo_diag, do_admm_purify_none, do_loc_none, &
      63              :         do_potential_coulomb, do_potential_id, do_potential_short, do_potential_truncated, &
      64              :         op_loc_berry, state_loc_list, tddfpt_singlet, tddfpt_spin_cons, tddfpt_spin_flip, &
      65              :         tddfpt_triplet, xas_1s_type, xas_2p_type, xas_2s_type, xas_dip_len, xas_dip_vel, &
      66              :         xas_not_excited, xas_tdp_by_index, xas_tdp_by_kind
      67              :    USE input_cp2k_loc,                  ONLY: create_localize_section
      68              :    USE input_section_types,             ONLY: section_release,&
      69              :                                               section_type,&
      70              :                                               section_vals_create,&
      71              :                                               section_vals_get_subs_vals,&
      72              :                                               section_vals_type,&
      73              :                                               section_vals_val_get,&
      74              :                                               section_vals_val_set
      75              :    USE kinds,                           ONLY: default_path_length,&
      76              :                                               default_string_length,&
      77              :                                               dp
      78              :    USE libint_wrapper,                  ONLY: cp_libint_static_init
      79              :    USE machine,                         ONLY: m_flush
      80              :    USE mathlib,                         ONLY: get_diag
      81              :    USE memory_utilities,                ONLY: reallocate
      82              :    USE message_passing,                 ONLY: mp_comm_type,&
      83              :                                               mp_para_env_type
      84              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      85              :    USE parallel_rng_types,              ONLY: UNIFORM,&
      86              :                                               rng_stream_type
      87              :    USE particle_methods,                ONLY: get_particle_set
      88              :    USE particle_types,                  ONLY: particle_type
      89              :    USE periodic_table,                  ONLY: ptable
      90              :    USE physcon,                         ONLY: a_fine,&
      91              :                                               angstrom,&
      92              :                                               evolt
      93              :    USE qs_environment_types,            ONLY: get_qs_env,&
      94              :                                               qs_environment_type
      95              :    USE qs_interactions,                 ONLY: init_interaction_radii_orb_basis
      96              :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      97              :                                               qs_kind_type
      98              :    USE qs_loc_main,                     ONLY: qs_loc_driver
      99              :    USE qs_loc_methods,                  ONLY: centers_spreads_berry,&
     100              :                                               qs_print_cubes
     101              :    USE qs_loc_types,                    ONLY: get_qs_loc_env,&
     102              :                                               localized_wfn_control_create,&
     103              :                                               localized_wfn_control_type,&
     104              :                                               qs_loc_env_create,&
     105              :                                               qs_loc_env_release,&
     106              :                                               qs_loc_env_type
     107              :    USE qs_loc_utils,                    ONLY: qs_loc_control_init,&
     108              :                                               qs_loc_env_init,&
     109              :                                               set_loc_centers
     110              :    USE qs_mo_io,                        ONLY: write_mo_set_low
     111              :    USE qs_mo_methods,                   ONLY: calculate_subspace_eigenvalues
     112              :    USE qs_mo_types,                     ONLY: allocate_mo_set,&
     113              :                                               deallocate_mo_set,&
     114              :                                               duplicate_mo_set,&
     115              :                                               get_mo_set,&
     116              :                                               init_mo_set,&
     117              :                                               mo_set_type
     118              :    USE qs_operators_ao,                 ONLY: p_xyz_ao,&
     119              :                                               rRc_xyz_ao
     120              :    USE qs_pdos,                         ONLY: calculate_projected_dos
     121              :    USE qs_rho_types,                    ONLY: qs_rho_get,&
     122              :                                               qs_rho_type
     123              :    USE qs_scf_types,                    ONLY: ot_method_nr
     124              :    USE rixs_types,                      ONLY: rixs_env_type
     125              :    USE util,                            ONLY: get_limit,&
     126              :                                               locate,&
     127              :                                               sort_unique
     128              :    USE xas_methods,                     ONLY: calc_stogto_overlap
     129              :    USE xas_tdp_atom,                    ONLY: init_xas_atom_env,&
     130              :                                               integrate_fxc_atoms,&
     131              :                                               integrate_soc_atoms
     132              :    USE xas_tdp_correction,              ONLY: GW2X_shift,&
     133              :                                               get_soc_splitting
     134              :    USE xas_tdp_integrals,               ONLY: compute_ri_3c_coulomb,&
     135              :                                               compute_ri_3c_exchange,&
     136              :                                               compute_ri_coulomb2_int,&
     137              :                                               compute_ri_exchange2_int
     138              :    USE xas_tdp_types,                   ONLY: &
     139              :         donor_state_create, donor_state_type, free_ds_memory, free_exat_memory, &
     140              :         read_xas_tdp_control, set_donor_state, set_xas_tdp_env, xas_atom_env_create, &
     141              :         xas_atom_env_release, xas_atom_env_type, xas_tdp_control_create, xas_tdp_control_release, &
     142              :         xas_tdp_control_type, xas_tdp_env_create, xas_tdp_env_release, xas_tdp_env_type
     143              :    USE xas_tdp_utils,                   ONLY: include_os_soc,&
     144              :                                               include_rcs_soc,&
     145              :                                               setup_xas_tdp_prob,&
     146              :                                               solve_xas_tdp_prob
     147              :    USE xc_write_output,                 ONLY: xc_write
     148              : #include "./base/base_uses.f90"
     149              : 
     150              :    IMPLICIT NONE
     151              :    PRIVATE
     152              : 
     153              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'xas_tdp_methods'
     154              : 
     155              :    PUBLIC :: xas_tdp, xas_tdp_init
     156              : 
     157              : CONTAINS
     158              : 
     159              : ! **************************************************************************************************
     160              : !> \brief Driver for XAS TDDFT calculations.
     161              : !> \param qs_env the inherited qs_environment
     162              : !> \param rixs_env ...
     163              : !> \author AB
     164              : !> \note Empty for now...
     165              : ! **************************************************************************************************
     166          120 :    SUBROUTINE xas_tdp(qs_env, rixs_env)
     167              : 
     168              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     169              :       TYPE(rixs_env_type), OPTIONAL, POINTER             :: rixs_env
     170              : 
     171              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'xas_tdp'
     172              : 
     173              :       CHARACTER(default_string_length)                   :: rst_filename
     174              :       INTEGER                                            :: handle, n_rep, output_unit
     175              :       LOGICAL                                            :: do_restart, do_rixs
     176              :       TYPE(section_vals_type), POINTER                   :: xas_tdp_section
     177              : 
     178           60 :       CALL timeset(routineN, handle)
     179              : 
     180              : !  Logger initialization and XAS TDP banner printing
     181           60 :       NULLIFY (xas_tdp_section)
     182              : 
     183              :       ! check if subroutine is called as part of rixs calculation
     184           60 :       CALL get_qs_env(qs_env, do_rixs=do_rixs)
     185           60 :       IF (do_rixs) THEN
     186           10 :          xas_tdp_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%RIXS%XAS_TDP")
     187              :       ELSE
     188           50 :          xas_tdp_section => section_vals_get_subs_vals(qs_env%input, "DFT%XAS_TDP")
     189              :       END IF
     190           60 :       output_unit = cp_logger_get_default_io_unit()
     191              : 
     192           60 :       IF (output_unit > 0) THEN
     193              :          WRITE (UNIT=output_unit, FMT="(/,T3,A,/,T3,A,/,T3,A,/,T3,A,/)") &
     194           30 :             "!===========================================================================!", &
     195           30 :             "!                              XAS TDP                                      !", &
     196           30 :             "!    Starting TDDFPT driven X-rays absorption spectroscopy calculations     !", &
     197           60 :             "!===========================================================================!"
     198              :       END IF
     199              : 
     200           60 :       CALL cite_reference(Bussy2021a)
     201              : 
     202              : !  Check whether this is a restart calculation, i.e. is a restart file is provided
     203           60 :       CALL section_vals_val_get(xas_tdp_section, "RESTART_FROM_FILE", n_rep_val=n_rep)
     204              : 
     205           60 :       IF (n_rep < 1) THEN
     206              :          do_restart = .FALSE.
     207              :       ELSE
     208            2 :          CALL section_vals_val_get(xas_tdp_section, "RESTART_FROM_FILE", c_val=rst_filename)
     209              :          do_restart = .TRUE.
     210              :       END IF
     211              : 
     212              : !  Restart the calculation if needed
     213              :       IF (do_restart) THEN
     214              : 
     215            2 :          IF (output_unit > 0) THEN
     216              :             WRITE (UNIT=output_unit, FMT="(/,T3,A)") &
     217            1 :                "# This is a RESTART calculation for PDOS and/or CUBE printing"
     218              :          END IF
     219              : 
     220            2 :          CALL restart_calculation(rst_filename, xas_tdp_section, qs_env)
     221              : 
     222              : !  or run the core XAS_TDP routine if not
     223              :       ELSE
     224           58 :          IF (PRESENT(rixs_env)) THEN
     225           10 :             CALL xas_tdp_core(xas_tdp_section, qs_env, rixs_env)
     226              :          ELSE
     227           48 :             CALL xas_tdp_core(xas_tdp_section, qs_env)
     228              :          END IF
     229              :       END IF
     230              : 
     231           60 :       IF (output_unit > 0) THEN
     232              :          WRITE (UNIT=output_unit, FMT="(/,T3,A,/,T3,A,/,T3,A,/)") &
     233           30 :             "!===========================================================================!", &
     234           30 :             "!     End of TDDFPT driven X-rays absorption spectroscopy calculations      !", &
     235           60 :             "!===========================================================================!"
     236              :       END IF
     237              : 
     238           60 :       CALL timestop(handle)
     239              : 
     240           60 :    END SUBROUTINE xas_tdp
     241              : 
     242              : ! **************************************************************************************************
     243              : !> \brief The core workflow of the XAS_TDP method
     244              : !> \param xas_tdp_section the input values for XAS_TDP
     245              : !> \param qs_env ...
     246              : !> \param rixs_env ...
     247              : ! **************************************************************************************************
     248           58 :    SUBROUTINE xas_tdp_core(xas_tdp_section, qs_env, rixs_env)
     249              : 
     250              :       TYPE(section_vals_type), POINTER                   :: xas_tdp_section
     251              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     252              :       TYPE(rixs_env_type), OPTIONAL, POINTER             :: rixs_env
     253              : 
     254              :       CHARACTER(LEN=default_string_length)               :: kind_name
     255              :       INTEGER :: batch_size, bo(2), current_state_index, iat, iatom, ibatch, ikind, ispin, istate, &
     256              :          nbatch, nex_atom, output_unit, tmp_index
     257           58 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: batch_atoms, ex_atoms_of_kind
     258           58 :       INTEGER, DIMENSION(:), POINTER                     :: atoms_of_kind
     259              :       LOGICAL                                            :: do_os, do_rixs, end_of_batch, unique
     260              :       TYPE(admm_type), POINTER                           :: admm_env
     261           58 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     262           58 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks
     263              :       TYPE(dft_control_type), POINTER                    :: dft_control
     264              :       TYPE(donor_state_type), POINTER                    :: current_state
     265              :       TYPE(gto_basis_set_type), POINTER                  :: tmp_basis
     266           58 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     267              :       TYPE(xas_atom_env_type), POINTER                   :: xas_atom_env
     268              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
     269              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
     270              : 
     271           58 :       NULLIFY (xas_tdp_env, xas_tdp_control, atomic_kind_set, atoms_of_kind, current_state)
     272           58 :       NULLIFY (xas_atom_env, dft_control, matrix_ks, admm_env, qs_kind_set, tmp_basis)
     273              : 
     274              : !  Initialization
     275          116 :       output_unit = cp_logger_get_default_io_unit()
     276              : 
     277           58 :       IF (output_unit > 0) THEN
     278              :          WRITE (UNIT=output_unit, FMT="(/,T3,A)") &
     279           29 :             "# Create and initialize the XAS_TDP environment"
     280              :       END IF
     281           58 :       CALL get_qs_env(qs_env, dft_control=dft_control, do_rixs=do_rixs)
     282           58 :       IF (PRESENT(rixs_env)) THEN
     283           10 :          CALL xas_tdp_init(xas_tdp_env, xas_tdp_control, qs_env, rixs_env)
     284              :       ELSE
     285           48 :          CALL xas_tdp_init(xas_tdp_env, xas_tdp_control, qs_env)
     286              :       END IF
     287           58 :       CALL print_info(output_unit, xas_tdp_control, qs_env)
     288              : 
     289           58 :       IF (output_unit > 0) THEN
     290           29 :          IF (xas_tdp_control%check_only) THEN
     291            0 :             CPWARN("This is a CHECK_ONLY run for donor MOs verification")
     292              :          END IF
     293              :       END IF
     294              : 
     295              : !  Localization of the core orbitals if requested (used for better identification of donor states)
     296           58 :       IF (xas_tdp_control%do_loc) THEN
     297           34 :          IF (output_unit > 0) THEN
     298              :             WRITE (UNIT=output_unit, FMT="(/,T3,A,/)") &
     299           17 :                "# Localizing core orbitals for better identification"
     300              :          END IF
     301              : !        closed shell or ROKS => myspin=1
     302           34 :          IF (xas_tdp_control%do_uks) THEN
     303            6 :             DO ispin = 1, dft_control%nspins
     304              :                CALL qs_loc_driver(qs_env, xas_tdp_env%qs_loc_env, &
     305            6 :                                   xas_tdp_control%print_loc_subsection, myspin=ispin)
     306              :             END DO
     307              :          ELSE
     308              :             CALL qs_loc_driver(qs_env, xas_tdp_env%qs_loc_env, &
     309           32 :                                xas_tdp_control%print_loc_subsection, myspin=1)
     310              :          END IF
     311              :       END IF
     312              : 
     313              : !  Find the MO centers
     314           58 :       CALL find_mo_centers(xas_tdp_env, xas_tdp_control, qs_env)
     315              : 
     316              : !  Assign lowest energy orbitals to excited atoms
     317           58 :       CALL assign_mos_to_ex_atoms(xas_tdp_env, xas_tdp_control, qs_env)
     318              : 
     319              : !  Once assigned, diagonalize the MOs wrt the KS matrix in the subspace associated to each atom
     320           58 :       IF (xas_tdp_control%do_loc) THEN
     321           34 :          IF (output_unit > 0) THEN
     322              :             WRITE (UNIT=output_unit, FMT="(/,T3,A,/,T5,A)") &
     323           17 :                "# Diagonalize localized MOs wrt the KS matrix in the subspace of each excited", &
     324           34 :                "atom for better donor state identification."
     325              :          END IF
     326           34 :          CALL diagonalize_assigned_mo_subset(xas_tdp_env, xas_tdp_control, qs_env)
     327              :          ! update MO centers
     328           34 :          CALL find_mo_centers(xas_tdp_env, xas_tdp_control, qs_env)
     329              :       END IF
     330              : 
     331           58 :       IF (output_unit > 0) THEN
     332              :          WRITE (UNIT=output_unit, FMT="(/,T3,A,I4,A,/)") &
     333           29 :             "# Assign the relevant subset of the ", xas_tdp_control%n_search, &
     334           58 :             "  lowest energy MOs to excited atoms"
     335              :       END IF
     336           58 :       CALL write_mos_to_ex_atoms_association(xas_tdp_env, xas_tdp_control, qs_env)
     337              : 
     338              : !  If CHECK_ONLY run, check the donor MOs
     339           58 :       IF (xas_tdp_control%check_only) CALL print_checks(xas_tdp_env, xas_tdp_control, qs_env)
     340              : 
     341              : !  If not simply exact exchange, setup a xas_atom_env and compute the xc integrals on the atomic grids
     342              : !  Also needed if SOC is included or XPS GW2X(). Done before looping on atoms as it's all done at once
     343              :       IF ((xas_tdp_control%do_xc .OR. xas_tdp_control%do_soc .OR. xas_tdp_control%do_gw2x) &
     344           58 :           .AND. .NOT. xas_tdp_control%check_only) THEN
     345              : 
     346           58 :          IF (output_unit > 0 .AND. xas_tdp_control%do_xc) THEN
     347              :             WRITE (UNIT=output_unit, FMT="(/,T3,A,I4,A)") &
     348           24 :                "# Integrating the xc kernel on the atomic grids ..."
     349           24 :             CALL m_flush(output_unit)
     350              :          END IF
     351              : 
     352           58 :          CALL xas_atom_env_create(xas_atom_env)
     353           58 :          CALL init_xas_atom_env(xas_atom_env, xas_tdp_env, xas_tdp_control, qs_env)
     354           58 :          do_os = xas_tdp_control%do_uks .OR. xas_tdp_control%do_roks
     355              : 
     356           58 :          IF (xas_tdp_control%do_xc .AND. (.NOT. xas_tdp_control%xps_only)) THEN
     357           48 :             CALL integrate_fxc_atoms(xas_tdp_env%ri_fxc, xas_atom_env, xas_tdp_control, qs_env)
     358              :          END IF
     359              : 
     360           58 :          IF (xas_tdp_control%do_soc .OR. xas_tdp_control%do_gw2x) THEN
     361           22 :             CALL integrate_soc_atoms(xas_tdp_env%orb_soc, xas_atom_env=xas_atom_env, qs_env=qs_env)
     362              :          END IF
     363              : 
     364           58 :          CALL xas_atom_env_release(xas_atom_env)
     365              :       END IF
     366              : 
     367              : !  Compute the 3-center Coulomb integrals for the whole system
     368           58 :       IF ((.NOT. (xas_tdp_control%check_only .OR. xas_tdp_control%xps_only)) .AND. &
     369              :           (xas_tdp_control%do_xc .OR. xas_tdp_control%do_coulomb)) THEN
     370           54 :          IF (output_unit > 0) THEN
     371              :             WRITE (UNIT=output_unit, FMT="(/,T3,A,I4,A)") &
     372           27 :                "# Computing the RI 3-center Coulomb integrals ..."
     373           27 :             CALL m_flush(output_unit)
     374              :          END IF
     375           54 :          CALL compute_ri_3c_coulomb(xas_tdp_env, qs_env)
     376              : 
     377              :       END IF
     378              : 
     379              : !  Loop over donor states for calculation
     380           58 :       CALL get_qs_env(qs_env=qs_env, atomic_kind_set=atomic_kind_set)
     381           58 :       current_state_index = 1
     382              : 
     383              : !     Loop over atomic kinds
     384          148 :       DO ikind = 1, SIZE(atomic_kind_set)
     385              : 
     386           90 :          IF (xas_tdp_control%check_only) EXIT
     387          124 :          IF (.NOT. ANY(xas_tdp_env%ex_kind_indices == ikind)) CYCLE
     388              : 
     389              :          CALL get_atomic_kind(atomic_kind=atomic_kind_set(ikind), name=kind_name, &
     390           64 :                               atom_list=atoms_of_kind)
     391              : 
     392              :          ! compute the RI coulomb2 inverse for this kind, and RI exchange2 if needed
     393           64 :          CALL compute_ri_coulomb2_int(ikind, xas_tdp_env, xas_tdp_control, qs_env)
     394           64 :          IF (xas_tdp_control%do_hfx) THEN
     395           50 :             CALL compute_ri_exchange2_int(ikind, xas_tdp_env, xas_tdp_control, qs_env)
     396              :          END IF
     397              : 
     398              :          !Randomly distribute excited atoms of current kinds into batches for optimal load balance
     399              :          !of RI 3c exchange integrals. Take batch sizes of 2 to avoid taxing memory too much, while
     400              :          !greatly improving load balance
     401           64 :          batch_size = 2
     402           64 :          CALL get_ri_3c_batches(ex_atoms_of_kind, nbatch, batch_size, atoms_of_kind, xas_tdp_env)
     403           64 :          nex_atom = SIZE(ex_atoms_of_kind)
     404              : 
     405              :          !Loop over batches
     406          128 :          DO ibatch = 1, nbatch
     407              : 
     408           64 :             bo = get_limit(nex_atom, nbatch, ibatch - 1)
     409           64 :             batch_size = bo(2) - bo(1) + 1
     410          192 :             ALLOCATE (batch_atoms(batch_size))
     411           64 :             iatom = 0
     412          134 :             DO iat = bo(1), bo(2)
     413           70 :                iatom = iatom + 1
     414          134 :                batch_atoms(iatom) = ex_atoms_of_kind(iat)
     415              :             END DO
     416           64 :             CALL sort_unique(batch_atoms, unique)
     417              : 
     418              :             !compute RI 3c exchange integrals on batch, if so required
     419           64 :             IF (xas_tdp_control%do_hfx) THEN
     420           50 :                IF (output_unit > 0) THEN
     421              :                   WRITE (UNIT=output_unit, FMT="(/,T3,A,I4,A,I4,A,I1,A,A)") &
     422           25 :                      "# Computing the RI 3-center Exchange integrals for batch ", ibatch, "(/", nbatch, ") of ", &
     423           50 :                      batch_size, " atoms of kind: ", TRIM(kind_name)
     424           25 :                   CALL m_flush(output_unit)
     425              :                END IF
     426           50 :                CALL compute_ri_3c_exchange(batch_atoms, xas_tdp_env, xas_tdp_control, qs_env)
     427              :             END IF
     428              : 
     429              : !           Loop over atoms of batch
     430          134 :             DO iat = 1, batch_size
     431           70 :                iatom = batch_atoms(iat)
     432              : 
     433           70 :                tmp_index = locate(xas_tdp_env%ex_atom_indices, iatom)
     434              : 
     435              :                !if dipole in length rep, compute the dipole in the AO basis for this atom
     436              :                !if quadrupole is required, compute it there too (in length rep)
     437           70 :                IF (xas_tdp_control%dipole_form == xas_dip_len .OR. xas_tdp_control%do_quad) THEN
     438           24 :                   CALL compute_lenrep_multipole(iatom, xas_tdp_env, xas_tdp_control, qs_env)
     439              :                END IF
     440              : 
     441              : !              Loop over states of excited atom of kind
     442          150 :                DO istate = 1, SIZE(xas_tdp_env%state_types, 1)
     443              : 
     444           80 :                   IF (xas_tdp_env%state_types(istate, tmp_index) == xas_not_excited) CYCLE
     445              : 
     446           80 :                   current_state => xas_tdp_env%donor_states(current_state_index)
     447              :                   CALL set_donor_state(current_state, at_index=iatom, &
     448              :                                        at_symbol=kind_name, kind_index=ikind, &
     449           80 :                                        state_type=xas_tdp_env%state_types(istate, tmp_index))
     450              : 
     451              : !                 Initial write for the donor state of interest
     452           80 :                   IF (output_unit > 0) THEN
     453              :                      WRITE (UNIT=output_unit, FMT="(/,T3,A,A2,A,I4,A,A,/)") &
     454           40 :                         "# Start of calculations for donor state of type ", &
     455           40 :                         xas_tdp_env%state_type_char(current_state%state_type), " for atom", &
     456           80 :                         current_state%at_index, " of kind ", TRIM(current_state%at_symbol)
     457           40 :                      CALL m_flush(output_unit)
     458              :                   END IF
     459              : 
     460              : !                 Assign best fitting MO(s) to current core donnor state
     461           80 :                   CALL assign_mos_to_donor_state(current_state, xas_tdp_env, xas_tdp_control, qs_env)
     462              : 
     463              : !                 Perform MO restricted Mulliken pop analysis for verification
     464           80 :                   CALL perform_mulliken_on_donor_state(current_state, qs_env)
     465              : 
     466              : !                 GW2X correction
     467           80 :                   IF (xas_tdp_control%do_gw2x) THEN
     468           30 :                      CALL GW2X_shift(current_state, xas_tdp_env, xas_tdp_control, qs_env)
     469              :                   END IF
     470              : 
     471              : !                 Do main XAS calculations here
     472           80 :                   IF (.NOT. xas_tdp_control%xps_only) THEN
     473           68 :                      CALL setup_xas_tdp_prob(current_state, qs_env, xas_tdp_env, xas_tdp_control)
     474              : 
     475           68 :                      IF (xas_tdp_control%do_spin_cons) THEN
     476              :                         CALL solve_xas_tdp_prob(current_state, xas_tdp_control, xas_tdp_env, qs_env, &
     477            8 :                                                 ex_type=tddfpt_spin_cons)
     478            8 :                         CALL compute_dipole_fosc(current_state, xas_tdp_control, xas_tdp_env)
     479            8 :                         IF (xas_tdp_control%do_quad) CALL compute_quadrupole_fosc(current_state, &
     480            0 :                                                                                   xas_tdp_control, xas_tdp_env)
     481              :                         CALL xas_tdp_post(tddfpt_spin_cons, current_state, xas_tdp_env, &
     482            8 :                                           xas_tdp_section, qs_env)
     483            8 :                         CALL write_donor_state_restart(tddfpt_spin_cons, current_state, xas_tdp_section, qs_env)
     484              :                      END IF
     485              : 
     486           68 :                      IF (xas_tdp_control%do_spin_flip) THEN
     487              :                         CALL solve_xas_tdp_prob(current_state, xas_tdp_control, xas_tdp_env, qs_env, &
     488            2 :                                                 ex_type=tddfpt_spin_flip)
     489              :                         !no dipole in spin-flip (spin-forbidden)
     490              :                         CALL xas_tdp_post(tddfpt_spin_flip, current_state, xas_tdp_env, &
     491            2 :                                           xas_tdp_section, qs_env)
     492            2 :                         CALL write_donor_state_restart(tddfpt_spin_flip, current_state, xas_tdp_section, qs_env)
     493              :                      END IF
     494              : 
     495           68 :                      IF (xas_tdp_control%do_singlet) THEN
     496              :                         CALL solve_xas_tdp_prob(current_state, xas_tdp_control, xas_tdp_env, qs_env, &
     497           60 :                                                 ex_type=tddfpt_singlet)
     498           60 :                         CALL compute_dipole_fosc(current_state, xas_tdp_control, xas_tdp_env)
     499           60 :                         IF (xas_tdp_control%do_quad) CALL compute_quadrupole_fosc(current_state, &
     500            0 :                                                                                   xas_tdp_control, xas_tdp_env)
     501              :                         CALL xas_tdp_post(tddfpt_singlet, current_state, xas_tdp_env, &
     502           60 :                                           xas_tdp_section, qs_env)
     503           60 :                         CALL write_donor_state_restart(tddfpt_singlet, current_state, xas_tdp_section, qs_env)
     504              :                      END IF
     505              : 
     506           68 :                      IF (xas_tdp_control%do_triplet) THEN
     507              :                         CALL solve_xas_tdp_prob(current_state, xas_tdp_control, xas_tdp_env, qs_env, &
     508            2 :                                                 ex_type=tddfpt_triplet)
     509              :                         !no dipole for triplets by construction
     510              :                         CALL xas_tdp_post(tddfpt_triplet, current_state, xas_tdp_env, &
     511            2 :                                           xas_tdp_section, qs_env)
     512            2 :                         CALL write_donor_state_restart(tddfpt_triplet, current_state, xas_tdp_section, qs_env)
     513              :                      END IF
     514              : 
     515              : !                    Include the SOC if required, only for 2p donor stataes
     516           68 :                      IF (xas_tdp_control%do_soc .AND. current_state%state_type == xas_2p_type) THEN
     517            4 :                         IF (xas_tdp_control%do_singlet .AND. xas_tdp_control%do_triplet) THEN
     518            2 :                            CALL include_rcs_soc(current_state, xas_tdp_env, xas_tdp_control, qs_env)
     519              :                         END IF
     520            4 :                         IF (xas_tdp_control%do_spin_cons .AND. xas_tdp_control%do_spin_flip) THEN
     521            2 :                            CALL include_os_soc(current_state, xas_tdp_env, xas_tdp_control, qs_env)
     522              :                         END IF
     523              :                      END IF
     524              : 
     525              : !                    Print the requested properties
     526           68 :                      CALL print_xas_tdp_to_file(current_state, xas_tdp_env, xas_tdp_control, xas_tdp_section)
     527              :                   END IF !xps_only
     528           80 :                   IF (xas_tdp_control%do_gw2x) CALL print_xps(current_state, xas_tdp_env, xas_tdp_control, qs_env)
     529              : 
     530              : !                 Free some unneeded attributes of current_state
     531           80 :                   IF (.NOT. do_rixs) CALL free_ds_memory(current_state) ! donor-state will be cleaned in rixs
     532           80 :                   current_state_index = current_state_index + 1
     533          150 :                   NULLIFY (current_state)
     534              : 
     535              :                END DO ! state type
     536              : 
     537           70 :                end_of_batch = .FALSE.
     538           70 :                IF (iat == batch_size) end_of_batch = .TRUE.
     539          134 :                CALL free_exat_memory(xas_tdp_env, iatom, end_of_batch)
     540              :             END DO ! atom of batch
     541          192 :             DEALLOCATE (batch_atoms)
     542              :          END DO !ibatch
     543          212 :          DEALLOCATE (ex_atoms_of_kind)
     544              :       END DO ! kind
     545              : 
     546              : !  Return to ususal KS matrix
     547           58 :       IF (dft_control%do_admm) THEN
     548            6 :          CALL get_qs_env(qs_env, matrix_ks=matrix_ks, admm_env=admm_env)
     549           12 :          DO ispin = 1, dft_control%nspins
     550           12 :             CALL admm_uncorrect_for_eigenvalues(ispin, admm_env, matrix_ks(ispin)%matrix)
     551              :          END DO
     552              :       END IF
     553              : 
     554              : !  Return to initial basis set radii
     555           58 :       IF (xas_tdp_control%eps_pgf > 0.0_dp) THEN
     556            0 :          CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
     557            0 :          DO ikind = 1, SIZE(atomic_kind_set)
     558            0 :             CALL get_qs_kind(qs_kind_set(ikind), basis_set=tmp_basis, basis_type="ORB")
     559            0 :             CALL init_interaction_radii_orb_basis(tmp_basis, eps_pgf_orb=dft_control%qs_control%eps_pgf_orb)
     560              :          END DO
     561              :       END IF
     562              : 
     563              : !  Clean-up
     564           58 :       IF (.NOT. do_rixs) CALL xas_tdp_env_release(xas_tdp_env) ! is released at the end of rixs
     565           58 :       CALL xas_tdp_control_release(xas_tdp_control)
     566              : 
     567          116 :    END SUBROUTINE xas_tdp_core
     568              : 
     569              : ! **************************************************************************************************
     570              : !> \brief Overall control and  environment types initialization
     571              : !> \param xas_tdp_env the environment type to initialize
     572              : !> \param xas_tdp_control the control type to initialize
     573              : !> \param qs_env the inherited qs environement type
     574              : !> \param rixs_env ...
     575              : ! **************************************************************************************************
     576           58 :    SUBROUTINE xas_tdp_init(xas_tdp_env, xas_tdp_control, qs_env, rixs_env)
     577              : 
     578              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
     579              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
     580              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     581              :       TYPE(rixs_env_type), OPTIONAL, POINTER             :: rixs_env
     582              : 
     583              :       CHARACTER(LEN=default_string_length)               :: kind_name
     584              :       INTEGER                                            :: at_ind, i, ispin, j, k, kind_ind, &
     585              :                                                             n_donor_states, n_kinds, nao, &
     586              :                                                             nat_of_kind, natom, nex_atoms, &
     587              :                                                             nex_kinds, nmatch, nspins
     588              :       INTEGER, DIMENSION(2)                              :: homo, n_mo, n_moloc
     589           58 :       INTEGER, DIMENSION(:), POINTER                     :: ind_of_kind
     590              :       LOGICAL                                            :: do_os, do_rixs, do_uks, unique
     591              :       REAL(dp)                                           :: fact
     592           58 :       REAL(dp), DIMENSION(:), POINTER                    :: mo_evals
     593              :       TYPE(admm_type), POINTER                           :: admm_env
     594           58 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: at_kind_set
     595              :       TYPE(cell_type), POINTER                           :: cell
     596              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     597           58 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s, rho_ao
     598              :       TYPE(dbcsr_type)                                   :: matrix_tmp
     599              :       TYPE(dft_control_type), POINTER                    :: dft_control
     600              :       TYPE(gto_basis_set_type), POINTER                  :: tmp_basis
     601           58 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     602           58 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     603           58 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     604              :       TYPE(qs_loc_env_type), POINTER                     :: qs_loc_env
     605              :       TYPE(qs_rho_type), POINTER                         :: rho
     606              :       TYPE(section_type), POINTER                        :: dummy_section
     607              :       TYPE(section_vals_type), POINTER                   :: loc_section, xas_tdp_section
     608              : 
     609           58 :       NULLIFY (xas_tdp_section, at_kind_set, ind_of_kind, dft_control, qs_kind_set, tmp_basis)
     610           58 :       NULLIFY (qs_loc_env, loc_section, mos, particle_set, rho, rho_ao, mo_evals, cell)
     611           58 :       NULLIFY (mo_coeff, matrix_ks, admm_env, dummy_section)
     612              : 
     613              : !  XAS TDP control type initialization
     614           58 :       CALL get_qs_env(qs_env, dft_control=dft_control, do_rixs=do_rixs)
     615              : 
     616           58 :       IF (do_rixs) THEN
     617           10 :          xas_tdp_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%RIXS%XAS_TDP")
     618              :       ELSE
     619           48 :          xas_tdp_section => section_vals_get_subs_vals(qs_env%input, "DFT%XAS_TDP")
     620              :       END IF
     621              : 
     622           58 :       CALL xas_tdp_control_create(xas_tdp_control)
     623           58 :       CALL read_xas_tdp_control(xas_tdp_control, xas_tdp_section)
     624              : 
     625              : !  Check the qs_env for a LSD/ROKS calculation
     626           58 :       IF (dft_control%uks) xas_tdp_control%do_uks = .TRUE.
     627           58 :       IF (dft_control%roks) xas_tdp_control%do_roks = .TRUE.
     628           58 :       do_uks = xas_tdp_control%do_uks
     629           58 :       do_os = do_uks .OR. xas_tdp_control%do_roks
     630              : 
     631              : !  XAS TDP environment type initialization
     632           58 :       IF (PRESENT(rixs_env)) THEN
     633           10 :          xas_tdp_env => rixs_env%core_state
     634              :       ELSE
     635           48 :          CALL xas_tdp_env_create(xas_tdp_env)
     636              :       END IF
     637              : 
     638              : !  Retrieving the excited atoms indices and correspondig state types
     639           58 :       IF (xas_tdp_control%define_excited == xas_tdp_by_index) THEN
     640              : 
     641              : !        simply copy indices from xas_tdp_control
     642           34 :          nex_atoms = SIZE(xas_tdp_control%list_ex_atoms)
     643           34 :          CALL set_xas_tdp_env(xas_tdp_env, nex_atoms=nex_atoms)
     644          102 :          ALLOCATE (xas_tdp_env%ex_atom_indices(nex_atoms))
     645          136 :          ALLOCATE (xas_tdp_env%state_types(SIZE(xas_tdp_control%state_types, 1), nex_atoms))
     646          114 :          xas_tdp_env%ex_atom_indices = xas_tdp_control%list_ex_atoms
     647          194 :          xas_tdp_env%state_types = xas_tdp_control%state_types
     648              : 
     649              : !        Test that these indices are within the range of available atoms
     650           34 :          CALL get_qs_env(qs_env=qs_env, natom=natom)
     651           74 :          IF (ANY(xas_tdp_env%ex_atom_indices > natom)) THEN
     652            0 :             CPABORT("Invalid index for the ATOM_LIST keyword.")
     653              :          END IF
     654              : 
     655              : !        Check atom kinds and fill corresponding array
     656           68 :          ALLOCATE (xas_tdp_env%ex_kind_indices(nex_atoms))
     657           74 :          xas_tdp_env%ex_kind_indices = 0
     658           34 :          k = 0
     659           34 :          CALL get_qs_env(qs_env, particle_set=particle_set)
     660           74 :          DO i = 1, nex_atoms
     661           40 :             at_ind = xas_tdp_env%ex_atom_indices(i)
     662           40 :             CALL get_atomic_kind(particle_set(at_ind)%atomic_kind, kind_number=j)
     663          122 :             IF (ALL(ABS(xas_tdp_env%ex_kind_indices - j) .NE. 0)) THEN
     664           38 :                k = k + 1
     665           38 :                xas_tdp_env%ex_kind_indices(k) = j
     666              :             END IF
     667              :          END DO
     668           34 :          nex_kinds = k
     669           34 :          CALL set_xas_tdp_env(xas_tdp_env, nex_kinds=nex_kinds)
     670           34 :          CALL reallocate(xas_tdp_env%ex_kind_indices, 1, nex_kinds)
     671              : 
     672           24 :       ELSE IF (xas_tdp_control%define_excited == xas_tdp_by_kind) THEN
     673              : 
     674              : !        need to find out which atom of which kind is excited
     675           24 :          CALL get_qs_env(qs_env=qs_env, atomic_kind_set=at_kind_set)
     676           24 :          n_kinds = SIZE(at_kind_set)
     677           24 :          nex_atoms = 0
     678              : 
     679           24 :          nex_kinds = SIZE(xas_tdp_control%list_ex_kinds)
     680           72 :          ALLOCATE (xas_tdp_env%ex_kind_indices(nex_kinds))
     681           24 :          k = 0
     682              : 
     683           72 :          DO i = 1, n_kinds
     684              :             CALL get_atomic_kind(atomic_kind=at_kind_set(i), name=kind_name, &
     685           48 :                                  natom=nat_of_kind, kind_number=kind_ind)
     686           98 :             IF (ANY(xas_tdp_control%list_ex_kinds == kind_name)) THEN
     687           26 :                nex_atoms = nex_atoms + nat_of_kind
     688           26 :                k = k + 1
     689           26 :                xas_tdp_env%ex_kind_indices(k) = kind_ind
     690              :             END IF
     691              :          END DO
     692              : 
     693           72 :          ALLOCATE (xas_tdp_env%ex_atom_indices(nex_atoms))
     694           96 :          ALLOCATE (xas_tdp_env%state_types(SIZE(xas_tdp_control%state_types, 1), nex_atoms))
     695           24 :          nex_atoms = 0
     696           24 :          nmatch = 0
     697              : 
     698           72 :          DO i = 1, n_kinds
     699              :             CALL get_atomic_kind(atomic_kind=at_kind_set(i), name=kind_name, &
     700           48 :                                  natom=nat_of_kind, atom_list=ind_of_kind)
     701          126 :             DO j = 1, nex_kinds
     702          102 :                IF (xas_tdp_control%list_ex_kinds(j) == kind_name) THEN
     703           86 :                   xas_tdp_env%ex_atom_indices(nex_atoms + 1:nex_atoms + nat_of_kind) = ind_of_kind
     704           62 :                   DO k = 1, SIZE(xas_tdp_control%state_types, 1)
     705              :                      xas_tdp_env%state_types(k, nex_atoms + 1:nex_atoms + nat_of_kind) = &
     706          102 :                         xas_tdp_control%state_types(k, j)
     707              :                   END DO
     708           26 :                   nex_atoms = nex_atoms + nat_of_kind
     709           26 :                   nmatch = nmatch + 1
     710              :                END IF
     711              :             END DO
     712              :          END DO
     713              : 
     714           24 :          CALL set_xas_tdp_env(xas_tdp_env, nex_atoms=nex_atoms, nex_kinds=nex_kinds)
     715              : 
     716              : !        Verifying that the input was valid
     717           24 :          IF (nmatch .NE. SIZE(xas_tdp_control%list_ex_kinds)) THEN
     718            0 :             CPABORT("Invalid kind(s) for the KIND_LIST keyword.")
     719              :          END IF
     720              : 
     721              :       END IF
     722              : 
     723              : !  Sort the excited atoms indices (for convinience and use of locate function)
     724           58 :       CALL sort_unique(xas_tdp_env%ex_atom_indices, unique)
     725           58 :       IF (.NOT. unique) THEN
     726            0 :          CPABORT("Excited atoms not uniquely defined.")
     727              :       END IF
     728              : 
     729              : !  Check for periodicity
     730           58 :       CALL get_qs_env(qs_env, cell=cell)
     731          184 :       IF (ALL(cell%perd == 0)) THEN
     732           42 :          xas_tdp_control%is_periodic = .FALSE.
     733           64 :       ELSE IF (ALL(cell%perd == 1)) THEN
     734           16 :          xas_tdp_control%is_periodic = .TRUE.
     735              :       ELSE
     736            0 :          CPABORT("XAS TDP only implemented for full PBCs or non-PBCs")
     737              :       END IF
     738              : 
     739              : !  Allocating memory for the array of donor states
     740          208 :       n_donor_states = COUNT(xas_tdp_env%state_types /= xas_not_excited)
     741          254 :       ALLOCATE (xas_tdp_env%donor_states(n_donor_states))
     742          138 :       DO i = 1, n_donor_states
     743          138 :          CALL donor_state_create(xas_tdp_env%donor_states(i))
     744              :       END DO
     745              : 
     746              : !  In case of ADMM, for the whole duration of the XAS_TDP, we need the total KS matrix
     747           58 :       IF (dft_control%do_admm) THEN
     748            6 :          CALL get_qs_env(qs_env, admm_env=admm_env, matrix_ks=matrix_ks)
     749              : 
     750           12 :          DO ispin = 1, dft_control%nspins
     751           12 :             CALL admm_correct_for_eigenvalues(ispin, admm_env, matrix_ks(ispin)%matrix)
     752              :          END DO
     753              :       END IF
     754              : 
     755              : !  In case of externally imposed EPS_PGF_XAS, need to update ORB and RI_XAS interaction radii
     756           58 :       IF (xas_tdp_control%eps_pgf > 0.0_dp) THEN
     757            0 :          CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
     758              : 
     759            0 :          DO i = 1, SIZE(qs_kind_set)
     760            0 :             CALL get_qs_kind(qs_kind_set(i), basis_set=tmp_basis, basis_type="ORB")
     761            0 :             CALL init_interaction_radii_orb_basis(tmp_basis, eps_pgf_orb=xas_tdp_control%eps_pgf)
     762            0 :             CALL get_qs_kind(qs_kind_set(i), basis_set=tmp_basis, basis_type="RI_XAS")
     763            0 :             CALL init_interaction_radii_orb_basis(tmp_basis, eps_pgf_orb=xas_tdp_control%eps_pgf)
     764              :          END DO
     765              :       END IF
     766              : 
     767              : !  In case of ground state OT optimization, compute the MO eigenvalues and get canonical MOs
     768           58 :       IF (qs_env%scf_env%method == ot_method_nr) THEN
     769              : 
     770            6 :          CALL get_qs_env(qs_env, mos=mos, matrix_ks=matrix_ks)
     771            6 :          nspins = 1; IF (do_uks) nspins = 2
     772              : 
     773           12 :          DO ispin = 1, nspins
     774            6 :             CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, eigenvalues=mo_evals)
     775           12 :             CALL calculate_subspace_eigenvalues(mo_coeff, matrix_ks(ispin)%matrix, evals_arg=mo_evals)
     776              :          END DO
     777              :       END IF
     778              : 
     779              : !  Initializing the qs_loc_env from the LOCALIZE subsection of XAS_TDP (largely inpired by MI's XAS)
     780              : !  We create the LOCALIZE subsection here, since it is completely overwritten anyways
     781           58 :       CALL create_localize_section(dummy_section)
     782           58 :       CALL section_vals_create(xas_tdp_control%loc_subsection, dummy_section)
     783              :       CALL section_vals_val_set(xas_tdp_control%loc_subsection, "_SECTION_PARAMETERS_", &
     784           58 :                                 l_val=xas_tdp_control%do_loc)
     785           58 :       CALL section_release(dummy_section)
     786              :       xas_tdp_control%print_loc_subsection => section_vals_get_subs_vals( &
     787           58 :                                               xas_tdp_control%loc_subsection, "PRINT")
     788              : 
     789          406 :       ALLOCATE (xas_tdp_env%qs_loc_env)
     790           58 :       CALL qs_loc_env_create(xas_tdp_env%qs_loc_env)
     791           58 :       qs_loc_env => xas_tdp_env%qs_loc_env
     792           58 :       loc_section => xas_tdp_control%loc_subsection
     793              : !     getting the number of MOs
     794           58 :       CALL get_qs_env(qs_env, mos=mos)
     795           58 :       CALL get_mo_set(mos(1), nmo=n_mo(1), homo=homo(1), nao=nao)
     796           58 :       n_mo(2) = n_mo(1)
     797           58 :       homo(2) = homo(1)
     798           58 :       nspins = 1
     799           58 :       IF (do_os) CALL get_mo_set(mos(2), nmo=n_mo(2), homo=homo(2))
     800           58 :       IF (do_uks) nspins = 2 !in roks, same MOs for both spins
     801              : 
     802              :       ! by default, all (doubly occupied) homo are localized
     803          174 :       IF (xas_tdp_control%n_search < 0 .OR. xas_tdp_control%n_search > MINVAL(homo)) &
     804            0 :          xas_tdp_control%n_search = MINVAL(homo)
     805              :       CALL qs_loc_control_init(qs_loc_env, loc_section, do_homo=.TRUE., do_xas=.TRUE., &
     806           58 :                                nloc_xas=xas_tdp_control%n_search, spin_xas=1)
     807              : 
     808              :       ! do_xas argument above only prepares spin-alpha localization
     809           58 :       IF (do_uks) THEN
     810            6 :          qs_loc_env%localized_wfn_control%nloc_states(2) = xas_tdp_control%n_search
     811            6 :          qs_loc_env%localized_wfn_control%lu_bound_states(1, 2) = 1
     812            6 :          qs_loc_env%localized_wfn_control%lu_bound_states(2, 2) = xas_tdp_control%n_search
     813              :       END IF
     814              : 
     815              : !     final qs_loc_env initialization. Impose Berry operator
     816           58 :       qs_loc_env%localized_wfn_control%operator_type = op_loc_berry
     817           58 :       qs_loc_env%localized_wfn_control%max_iter = 25000
     818           58 :       IF (.NOT. xas_tdp_control%do_loc) THEN
     819           24 :          qs_loc_env%localized_wfn_control%localization_method = do_loc_none
     820              :       ELSE
     821          102 :          n_moloc = qs_loc_env%localized_wfn_control%nloc_states
     822           34 :          CALL set_loc_centers(qs_loc_env%localized_wfn_control, n_moloc, nspins)
     823           34 :          IF (do_uks) THEN
     824              :             CALL qs_loc_env_init(qs_loc_env, qs_loc_env%localized_wfn_control, &
     825            2 :                                  qs_env, do_localize=.TRUE.)
     826              :          ELSE
     827              :             CALL qs_loc_env_init(qs_loc_env, qs_loc_env%localized_wfn_control, &
     828           32 :                                  qs_env, do_localize=.TRUE., myspin=1)
     829              :          END IF
     830              :       END IF
     831              : 
     832              : !  Allocating memory for the array of excited atoms MOs. Worst case senario, all searched MOs are
     833              : !  associated to the same atom
     834          290 :       ALLOCATE (xas_tdp_env%mos_of_ex_atoms(xas_tdp_control%n_search, nex_atoms, nspins))
     835              : 
     836              : !  Compute the projector on the unoccupied, unperturbed ground state: Q = 1 - SP, sor each spin
     837           58 :       IF (do_os) nspins = 2
     838           58 :       CALL get_qs_env(qs_env, rho=rho, matrix_s=matrix_s)
     839           58 :       CALL qs_rho_get(rho, rho_ao=rho_ao)
     840              : 
     841          238 :       ALLOCATE (xas_tdp_env%q_projector(nspins))
     842           58 :       ALLOCATE (xas_tdp_env%q_projector(1)%matrix)
     843              :       CALL dbcsr_create(xas_tdp_env%q_projector(1)%matrix, name="Q PROJECTOR ALPHA", &
     844           58 :                         template=matrix_s(1)%matrix, matrix_type=dbcsr_type_no_symmetry)
     845           58 :       IF (do_os) THEN
     846            6 :          ALLOCATE (xas_tdp_env%q_projector(2)%matrix)
     847              :          CALL dbcsr_create(xas_tdp_env%q_projector(2)%matrix, name="Q PROJECTOR BETA", &
     848            6 :                            template=matrix_s(1)%matrix, matrix_type=dbcsr_type_no_symmetry)
     849              :       END IF
     850              : 
     851              : !     In the case of spin-restricted calculations, rho_ao includes double occupency => 0.5 prefactor
     852           58 :       fact = -0.5_dp; IF (do_os) fact = -1.0_dp
     853              :       CALL dbcsr_multiply('N', 'N', fact, matrix_s(1)%matrix, rho_ao(1)%matrix, 0.0_dp, &
     854           58 :                           xas_tdp_env%q_projector(1)%matrix, filter_eps=xas_tdp_control%eps_filter)
     855           58 :       CALL dbcsr_add_on_diag(xas_tdp_env%q_projector(1)%matrix, 1.0_dp)
     856           58 :       CALL dbcsr_finalize(xas_tdp_env%q_projector(1)%matrix)
     857              : 
     858           58 :       IF (do_os) THEN
     859              :          CALL dbcsr_multiply('N', 'N', fact, matrix_s(1)%matrix, rho_ao(2)%matrix, 0.0_dp, &
     860            6 :                              xas_tdp_env%q_projector(2)%matrix, filter_eps=xas_tdp_control%eps_filter)
     861            6 :          CALL dbcsr_add_on_diag(xas_tdp_env%q_projector(2)%matrix, 1.0_dp)
     862            6 :          CALL dbcsr_finalize(xas_tdp_env%q_projector(2)%matrix)
     863              :       END IF
     864              : 
     865              : !  Create the structure for the dipole in the AO basis
     866          232 :       ALLOCATE (xas_tdp_env%dipmat(3))
     867          232 :       DO i = 1, 3
     868          174 :          ALLOCATE (xas_tdp_env%dipmat(i)%matrix)
     869          174 :          CALL dbcsr_copy(matrix_tmp, matrix_s(1)%matrix, name="XAS TDP dipole matrix")
     870          174 :          IF (xas_tdp_control%dipole_form == xas_dip_vel) THEN
     871              :             CALL dbcsr_create(xas_tdp_env%dipmat(i)%matrix, template=matrix_s(1)%matrix, &
     872          120 :                               matrix_type=dbcsr_type_antisymmetric)
     873          120 :             CALL dbcsr_complete_redistribute(matrix_tmp, xas_tdp_env%dipmat(i)%matrix)
     874              :          ELSE
     875              :             CALL dbcsr_create(xas_tdp_env%dipmat(i)%matrix, template=matrix_s(1)%matrix, &
     876           54 :                               matrix_type=dbcsr_type_symmetric)
     877           54 :             CALL dbcsr_copy(xas_tdp_env%dipmat(i)%matrix, matrix_tmp)
     878              :          END IF
     879          174 :          CALL dbcsr_set(xas_tdp_env%dipmat(i)%matrix, 0.0_dp)
     880          232 :          CALL dbcsr_release(matrix_tmp)
     881              :       END DO
     882              : 
     883              : !  Create the structure for the electric quadrupole in the AO basis, if required
     884           58 :       IF (xas_tdp_control%do_quad) THEN
     885            0 :          ALLOCATE (xas_tdp_env%quadmat(6))
     886            0 :          DO i = 1, 6
     887            0 :             ALLOCATE (xas_tdp_env%quadmat(i)%matrix)
     888            0 :             CALL dbcsr_copy(xas_tdp_env%quadmat(i)%matrix, matrix_s(1)%matrix, name="XAS TDP quadrupole matrix")
     889            0 :             CALL dbcsr_set(xas_tdp_env%quadmat(i)%matrix, 0.0_dp)
     890              :          END DO
     891              :       END IF
     892              : 
     893              : !     Precompute it in the velocity representation, if so chosen
     894           58 :       IF (xas_tdp_control%dipole_form == xas_dip_vel) THEN
     895              :          !enforce minimum image to avoid any PBCs related issues. Ok because very localized densities
     896           40 :          CALL p_xyz_ao(xas_tdp_env%dipmat, qs_env, minimum_image=.TRUE.)
     897              :       END IF
     898              : 
     899              : !  Allocate SOC in AO basis matrices
     900           58 :       IF (xas_tdp_control%do_soc .OR. xas_tdp_control%do_gw2x) THEN
     901           88 :          ALLOCATE (xas_tdp_env%orb_soc(3))
     902           88 :          DO i = 1, 3
     903          124 :             ALLOCATE (xas_tdp_env%orb_soc(i)%matrix)
     904              :          END DO
     905              :       END IF
     906              : 
     907              : !  Check that everything is allowed
     908           58 :       CALL safety_check(xas_tdp_control, qs_env)
     909              : 
     910              : !  Initialize libint for the 3-center integrals
     911           58 :       CALL cp_libint_static_init()
     912              : 
     913              : !  Compute LUMOs as guess for OT solver and/or for GW2X correction
     914           58 :       IF (xas_tdp_control%do_ot .OR. xas_tdp_control%do_gw2x) THEN
     915           20 :          CALL make_lumo_guess(xas_tdp_env, xas_tdp_control, qs_env)
     916              :       END IF
     917              : 
     918          174 :    END SUBROUTINE xas_tdp_init
     919              : 
     920              : ! **************************************************************************************************
     921              : !> \brief splits the excited atoms of a kind into batches for RI 3c integrals load balance
     922              : !> \param ex_atoms_of_kind the excited atoms for the current kind, randomly shuffled
     923              : !> \param nbatch number of batches to loop over
     924              : !> \param batch_size standard size of a batch
     925              : !> \param atoms_of_kind number of atoms for the current kind (excited or not)
     926              : !> \param xas_tdp_env ...
     927              : ! **************************************************************************************************
     928           64 :    SUBROUTINE get_ri_3c_batches(ex_atoms_of_kind, nbatch, batch_size, atoms_of_kind, xas_tdp_env)
     929              : 
     930              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(INOUT)  :: ex_atoms_of_kind
     931              :       INTEGER, INTENT(OUT)                               :: nbatch
     932              :       INTEGER, INTENT(IN)                                :: batch_size
     933              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: atoms_of_kind
     934              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
     935              : 
     936              :       INTEGER                                            :: iat, iatom, nex_atom
     937           64 :       TYPE(rng_stream_type), ALLOCATABLE                 :: rng_stream
     938              : 
     939              :       !Get the atoms from atoms_of_kind that are excited
     940           64 :       nex_atom = 0
     941          292 :       DO iat = 1, SIZE(atoms_of_kind)
     942          228 :          iatom = atoms_of_kind(iat)
     943          458 :          IF (.NOT. ANY(xas_tdp_env%ex_atom_indices == iatom)) CYCLE
     944          292 :          nex_atom = nex_atom + 1
     945              :       END DO
     946              : 
     947          192 :       ALLOCATE (ex_atoms_of_kind(nex_atom))
     948           64 :       nex_atom = 0
     949          292 :       DO iat = 1, SIZE(atoms_of_kind)
     950          228 :          iatom = atoms_of_kind(iat)
     951          458 :          IF (.NOT. ANY(xas_tdp_env%ex_atom_indices == iatom)) CYCLE
     952           70 :          nex_atom = nex_atom + 1
     953          292 :          ex_atoms_of_kind(nex_atom) = iatom
     954              :       END DO
     955              : 
     956              :       !We shuffle those atoms to spread them
     957           64 :       rng_stream = rng_stream_type(name="uniform_rng", distribution_type=UNIFORM)
     958           64 :       CALL rng_stream%shuffle(ex_atoms_of_kind(1:nex_atom))
     959              : 
     960           64 :       nbatch = nex_atom/batch_size
     961           64 :       IF (nbatch*batch_size .NE. nex_atom) nbatch = nbatch + 1
     962              : 
     963           64 :    END SUBROUTINE get_ri_3c_batches
     964              : 
     965              : ! **************************************************************************************************
     966              : !> \brief Checks for forbidden keywords combinations
     967              : !> \param xas_tdp_control ...
     968              : !> \param qs_env ...
     969              : ! **************************************************************************************************
     970           58 :    SUBROUTINE safety_check(xas_tdp_control, qs_env)
     971              : 
     972              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
     973              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     974              : 
     975              :       TYPE(dft_control_type), POINTER                    :: dft_control
     976              : 
     977              :       !PB only available without exact exchange
     978              :       IF (xas_tdp_control%is_periodic .AND. xas_tdp_control%do_hfx &
     979           58 :           .AND. xas_tdp_control%x_potential%potential_type == do_potential_coulomb) THEN
     980            0 :          CPABORT("XAS TDP with Coulomb operator for exact exchange only supports non-periodic BCs")
     981              :       END IF
     982              : 
     983              :       !open-shell/closed-shell tests
     984           58 :       IF (xas_tdp_control%do_roks .OR. xas_tdp_control%do_uks) THEN
     985              : 
     986            6 :          IF (.NOT. (xas_tdp_control%do_spin_cons .OR. xas_tdp_control%do_spin_flip)) THEN
     987            0 :             CPABORT("Need spin-conserving and/or spin-flip excitations for open-shell systems")
     988              :          END IF
     989              : 
     990            6 :          IF (xas_tdp_control%do_singlet .OR. xas_tdp_control%do_triplet) THEN
     991            0 :             CPABORT("Singlet/triplet excitations only for restricted closed-shell systems")
     992              :          END IF
     993              : 
     994            6 :          IF (xas_tdp_control%do_soc .AND. .NOT. &
     995              :              (xas_tdp_control%do_spin_flip .AND. xas_tdp_control%do_spin_cons)) THEN
     996              : 
     997            0 :             CPABORT("Both spin-conserving and spin-flip excitations are required for SOC")
     998              :          END IF
     999              :       ELSE
    1000              : 
    1001           52 :          IF (.NOT. (xas_tdp_control%do_singlet .OR. xas_tdp_control%do_triplet)) THEN
    1002            0 :             CPABORT("Need singlet and/or triplet excitations for closed-shell systems")
    1003              :          END IF
    1004              : 
    1005           52 :          IF (xas_tdp_control%do_spin_cons .OR. xas_tdp_control%do_spin_flip) THEN
    1006            0 :             CPABORT("Spin-conserving/spin-flip excitations only for open-shell systems")
    1007              :          END IF
    1008              : 
    1009           52 :          IF (xas_tdp_control%do_soc .AND. .NOT. &
    1010              :              (xas_tdp_control%do_singlet .AND. xas_tdp_control%do_triplet)) THEN
    1011              : 
    1012            0 :             CPABORT("Both singlet and triplet excitations are needed for SOC")
    1013              :          END IF
    1014              :       END IF
    1015              : 
    1016              :       !Warn against using E_RANGE with SOC
    1017           58 :       IF (xas_tdp_control%do_soc .AND. xas_tdp_control%e_range > 0.0_dp) THEN
    1018            0 :          CPWARN("Using E_RANGE and SOC together may lead to crashes, use N_EXCITED for safety.")
    1019              :       END IF
    1020              : 
    1021              :       !TDA, full-TDDFT and diagonalization
    1022           58 :       IF (.NOT. xas_tdp_control%tamm_dancoff) THEN
    1023              : 
    1024            6 :          IF (xas_tdp_control%do_spin_flip) THEN
    1025            0 :             CPABORT("Spin-flip kernel only implemented for Tamm-Dancoff approximation")
    1026              :          END IF
    1027              : 
    1028            6 :          IF (xas_tdp_control%do_ot) THEN
    1029            0 :             CPABORT("OT diagonalization only available within the Tamm-Dancoff approximation")
    1030              :          END IF
    1031              :       END IF
    1032              : 
    1033              :       !GW2X, need hfx kernel and LOCALIZE
    1034           58 :       IF (xas_tdp_control%do_gw2x) THEN
    1035           18 :          IF (.NOT. xas_tdp_control%do_hfx) THEN
    1036            0 :             CPABORT("GW2x requires the definition of the EXACT_EXCHANGE kernel")
    1037              :          END IF
    1038           18 :          IF (.NOT. xas_tdp_control%do_loc) THEN
    1039            0 :             CPABORT("GW2X requires the LOCALIZE keyword in DONOR_STATES")
    1040              :          END IF
    1041              :       END IF
    1042              : 
    1043              :       !Only allow ADMM schemes that correct for eigenvalues
    1044           58 :       CALL get_qs_env(qs_env, dft_control=dft_control)
    1045           58 :       IF (dft_control%do_admm) THEN
    1046              :          IF ((.NOT. qs_env%admm_env%purification_method == do_admm_purify_none) .AND. &
    1047            6 :              (.NOT. qs_env%admm_env%purification_method == do_admm_purify_cauchy_subspace) .AND. &
    1048              :              (.NOT. qs_env%admm_env%purification_method == do_admm_purify_mo_diag)) THEN
    1049              : 
    1050            0 :             CPABORT("XAS_TDP only compatible with ADMM purification NONE, CAUCHY_SUBSPACE and MO_DIAG")
    1051              : 
    1052              :          END IF
    1053              :       END IF
    1054              : 
    1055           58 :    END SUBROUTINE safety_check
    1056              : 
    1057              : ! **************************************************************************************************
    1058              : !> \brief Prints some basic info about the chosen parameters
    1059              : !> \param ou the output unis
    1060              : !> \param xas_tdp_control ...
    1061              : !> \param qs_env ...
    1062              : ! **************************************************************************************************
    1063           58 :    SUBROUTINE print_info(ou, xas_tdp_control, qs_env)
    1064              : 
    1065              :       INTEGER, INTENT(IN)                                :: ou
    1066              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    1067              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1068              : 
    1069              :       INTEGER                                            :: i
    1070              :       REAL(dp)                                           :: occ
    1071           58 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
    1072              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1073              :       TYPE(section_vals_type), POINTER                   :: input, kernel_section
    1074              : 
    1075           58 :       NULLIFY (input, kernel_section, dft_control, matrix_s)
    1076              : 
    1077           58 :       CALL get_qs_env(qs_env, input=input, dft_control=dft_control, matrix_s=matrix_s)
    1078              : 
    1079              :       !Overlap matrix sparsity
    1080           58 :       occ = dbcsr_get_occupation(matrix_s(1)%matrix)
    1081              : 
    1082           58 :       IF (ou .LE. 0) RETURN
    1083              : 
    1084              :       !Reference calculation
    1085           29 :       IF (xas_tdp_control%do_uks) THEN
    1086              :          WRITE (UNIT=ou, FMT="(/,T3,A)") &
    1087            3 :             "XAS_TDP| Reference calculation: Unrestricted Kohn-Sham"
    1088           26 :       ELSE IF (xas_tdp_control%do_roks) THEN
    1089              :          WRITE (UNIT=ou, FMT="(/,T3,A)") &
    1090            0 :             "XAS_TDP| Reference calculation: Restricted Open-Shell Kohn-Sham"
    1091              :       ELSE
    1092              :          WRITE (UNIT=ou, FMT="(/,T3,A)") &
    1093           26 :             "XAS_TDP| Reference calculation: Restricted Closed-Shell Kohn-Sham"
    1094              :       END IF
    1095              : 
    1096              :       !TDA
    1097           29 :       IF (xas_tdp_control%tamm_dancoff) THEN
    1098              :          WRITE (UNIT=ou, FMT="(T3,A)") &
    1099           26 :             "XAS_TDP| Tamm-Dancoff Approximation (TDA): On"
    1100              :       ELSE
    1101              :          WRITE (UNIT=ou, FMT="(T3,A)") &
    1102            3 :             "XAS_TDP| Tamm-Dancoff Approximation (TDA): Off"
    1103              :       END IF
    1104              : 
    1105              :       !Dipole form
    1106           29 :       IF (xas_tdp_control%dipole_form == xas_dip_vel) THEN
    1107              :          WRITE (UNIT=ou, FMT="(T3,A)") &
    1108           20 :             "XAS_TDP| Transition Dipole Representation: VELOCITY"
    1109              :       ELSE
    1110              :          WRITE (UNIT=ou, FMT="(T3,A)") &
    1111            9 :             "XAS_TDP| Transition Dipole Representation: LENGTH"
    1112              :       END IF
    1113              : 
    1114              :       !Quadrupole
    1115           29 :       IF (xas_tdp_control%do_quad) THEN
    1116              :          WRITE (UNIT=ou, FMT="(T3,A)") &
    1117            0 :             "XAS_TDP| Transition Quadrupole: On"
    1118              :       END IF
    1119              : 
    1120              :       !EPS_PGF
    1121           29 :       IF (xas_tdp_control%eps_pgf > 0.0_dp) THEN
    1122              :          WRITE (UNIT=ou, FMT="(T3,A,ES7.1)") &
    1123            0 :             "XAS_TDP| EPS_PGF_XAS: ", xas_tdp_control%eps_pgf
    1124              :       ELSE
    1125              :          WRITE (UNIT=ou, FMT="(T3,A,ES7.1,A)") &
    1126           29 :             "XAS_TDP| EPS_PGF_XAS: ", dft_control%qs_control%eps_pgf_orb, " (= EPS_PGF_ORB)"
    1127              :       END IF
    1128              : 
    1129              :       !EPS_FILTER
    1130              :       WRITE (UNIT=ou, FMT="(T3,A,ES7.1)") &
    1131           29 :          "XAS_TDP| EPS_FILTER: ", xas_tdp_control%eps_filter
    1132              : 
    1133              :       !Grid info
    1134           29 :       IF (xas_tdp_control%do_xc) THEN
    1135              :          WRITE (UNIT=ou, FMT="(T3,A)") &
    1136           24 :             "XAS_TDP| Radial Grid(s) Info: Kind,  na,  nr"
    1137           51 :          DO i = 1, SIZE(xas_tdp_control%grid_info, 1)
    1138              :             WRITE (UNIT=ou, FMT="(T3,A,A6,A,A,A,A)") &
    1139           27 :                "                            ", TRIM(xas_tdp_control%grid_info(i, 1)), ", ", &
    1140           78 :                TRIM(xas_tdp_control%grid_info(i, 2)), ", ", TRIM(xas_tdp_control%grid_info(i, 3))
    1141              :          END DO
    1142              :       END IF
    1143              : 
    1144              :       !No kernel
    1145           29 :       IF (.NOT. xas_tdp_control%do_coulomb) THEN
    1146              :          WRITE (UNIT=ou, FMT="(/,T3,A)") &
    1147            0 :             "XAS_TDP| No kernel (standard DFT)"
    1148              :       END IF
    1149              : 
    1150              :       !XC kernel
    1151           29 :       IF (xas_tdp_control%do_xc) THEN
    1152              : 
    1153              :          WRITE (UNIT=ou, FMT="(/,T3,A,F5.2,A)") &
    1154           24 :             "XAS_TDP| RI Region's Radius: ", xas_tdp_control%ri_radius*angstrom, " Ang"
    1155              : 
    1156              :          WRITE (UNIT=ou, FMT="(T3,A,/)") &
    1157           24 :             "XAS_TDP| XC Kernel Functional(s) used for the kernel:"
    1158              : 
    1159           24 :          kernel_section => section_vals_get_subs_vals(input, "DFT%XAS_TDP%KERNEL")
    1160           24 :          CALL xc_write(ou, kernel_section, lsd=.TRUE.)
    1161              :       END IF
    1162              : 
    1163              :       !HFX kernel
    1164           29 :       IF (xas_tdp_control%do_hfx) THEN
    1165              :          WRITE (UNIT=ou, FMT="(/,T3,A,/,/,T3,A,F5.3)") &
    1166           22 :             "XAS_TDP| Exact Exchange Kernel: Yes ", &
    1167           44 :             "EXACT_EXCHANGE| Scale: ", xas_tdp_control%sx
    1168           22 :          IF (xas_tdp_control%x_potential%potential_type == do_potential_coulomb) THEN
    1169              :             WRITE (UNIT=ou, FMT="(T3,A)") &
    1170           15 :                "EXACT_EXCHANGE| Potential : Coulomb"
    1171            7 :          ELSE IF (xas_tdp_control%x_potential%potential_type == do_potential_truncated) THEN
    1172              :             WRITE (UNIT=ou, FMT="(T3,A,/,T3,A,F5.2,A,/,T3,A,A)") &
    1173            3 :                "EXACT_EXCHANGE| Potential: Truncated Coulomb", &
    1174            3 :                "EXACT_EXCHANGE| Range: ", xas_tdp_control%x_potential%cutoff_radius*angstrom, ", (Ang)", &
    1175            6 :                "EXACT_EXCHANGE| T_C_G_DATA: ", TRIM(xas_tdp_control%x_potential%filename)
    1176            4 :          ELSE IF (xas_tdp_control%x_potential%potential_type == do_potential_short) THEN
    1177              :             WRITE (UNIT=ou, FMT="(T3,A,/,T3,A,F5.2,A,/,T3,A,F5.2,A,/,T3,A,ES7.1)") &
    1178            4 :                "EXACT_EXCHANGE| Potential: Short Range", &
    1179            4 :                "EXACT_EXCHANGE| Omega: ", xas_tdp_control%x_potential%omega, ", (1/a0)", &
    1180            4 :                "EXACT_EXCHANGE| Effective Range: ", xas_tdp_control%x_potential%cutoff_radius*angstrom, ", (Ang)", &
    1181            8 :                "EXACT_EXCHANGE| EPS_RANGE: ", xas_tdp_control%eps_range
    1182              :          END IF
    1183           22 :          IF (xas_tdp_control%eps_screen > 1.0E-16) THEN
    1184              :             WRITE (UNIT=ou, FMT="(T3,A,ES7.1)") &
    1185           22 :                "EXACT_EXCHANGE| EPS_SCREENING: ", xas_tdp_control%eps_screen
    1186              :          END IF
    1187              : 
    1188              :          !RI metric
    1189           22 :          IF (xas_tdp_control%do_ri_metric) THEN
    1190              : 
    1191              :             WRITE (UNIT=ou, FMT="(/,T3,A)") &
    1192            3 :                "EXACT_EXCHANGE| Using a RI metric"
    1193            3 :             IF (xas_tdp_control%ri_m_potential%potential_type == do_potential_id) THEN
    1194              :                WRITE (UNIT=ou, FMT="(T3,A)") &
    1195            1 :                   "EXACT_EXCHANGE RI_METRIC| Potential : Overlap"
    1196            2 :             ELSE IF (xas_tdp_control%ri_m_potential%potential_type == do_potential_truncated) THEN
    1197              :                WRITE (UNIT=ou, FMT="(T3,A,/,T3,A,F5.2,A,/,T3,A,A)") &
    1198            1 :                   "EXACT_EXCHANGE RI_METRIC| Potential: Truncated Coulomb", &
    1199            1 :                   "EXACT_EXCHANGE RI_METRIC| Range: ", xas_tdp_control%ri_m_potential%cutoff_radius &
    1200            1 :                   *angstrom, ", (Ang)", &
    1201            2 :                   "EXACT_EXCHANGE RI_METRIC| T_C_G_DATA: ", TRIM(xas_tdp_control%ri_m_potential%filename)
    1202            1 :             ELSE IF (xas_tdp_control%ri_m_potential%potential_type == do_potential_short) THEN
    1203              :                WRITE (UNIT=ou, FMT="(T3,A,/,T3,A,F5.2,A,/,T3,A,F5.2,A,/,T3,A,ES7.1)") &
    1204            1 :                   "EXACT_EXCHANGE RI_METRIC| Potential: Short Range", &
    1205            1 :                   "EXACT_EXCHANGE RI_METRIC| Omega: ", xas_tdp_control%ri_m_potential%omega, ", (1/a0)", &
    1206            1 :                   "EXACT_EXCHANGE RI_METRIC| Effective Range: ", &
    1207            1 :                   xas_tdp_control%ri_m_potential%cutoff_radius*angstrom, ", (Ang)", &
    1208            2 :                   "EXACT_EXCHANGE RI_METRIC| EPS_RANGE: ", xas_tdp_control%eps_range
    1209              :             END IF
    1210              :          END IF
    1211              :       ELSE
    1212              :          WRITE (UNIT=ou, FMT="(/,T3,A,/)") &
    1213            7 :             "XAS_TDP| Exact Exchange Kernel: No "
    1214              :       END IF
    1215              : 
    1216              :       !overlap mtrix occupation
    1217              :       WRITE (UNIT=ou, FMT="(/,T3,A,F5.2)") &
    1218           29 :          "XAS_TDP| Overlap matrix occupation: ", occ
    1219              : 
    1220              :       !GW2X parameter
    1221           29 :       IF (xas_tdp_control%do_gw2x) THEN
    1222              :          WRITE (UNIT=ou, FMT="(T3,A,/)") &
    1223            9 :             "XAS_TDP| GW2X correction enabled"
    1224              : 
    1225            9 :          IF (xas_tdp_control%xps_only) THEN
    1226              :             WRITE (UNIT=ou, FMT="(T3,A)") &
    1227            2 :                "GW2X| Only computing ionizations potentials for XPS"
    1228              :          END IF
    1229              : 
    1230            9 :          IF (xas_tdp_control%pseudo_canonical) THEN
    1231              :             WRITE (UNIT=ou, FMT="(T3,A)") &
    1232            8 :                "GW2X| Using the pseudo-canonical scheme"
    1233              :          ELSE
    1234              :             WRITE (UNIT=ou, FMT="(T3,A)") &
    1235            1 :                "GW2X| Using the GW2X* scheme"
    1236              :          END IF
    1237              : 
    1238              :          WRITE (UNIT=ou, FMT="(T3,A,ES7.1)") &
    1239            9 :             "GW2X| EPS_GW2X: ", xas_tdp_control%gw2x_eps
    1240              : 
    1241              :          WRITE (UNIT=ou, FMT="(T3,A,I5)") &
    1242            9 :             "GW2X| contraction batch size: ", xas_tdp_control%batch_size
    1243              : 
    1244            9 :          IF ((INT(xas_tdp_control%c_os) .NE. 1) .OR. (INT(xas_tdp_control%c_ss) .NE. 1)) THEN
    1245              :             WRITE (UNIT=ou, FMT="(T3,A,F7.4,/,T3,A,F7.4)") &
    1246            1 :                "GW2X| Same-spin scaling factor: ", xas_tdp_control%c_ss, &
    1247            2 :                "GW2X| Opposite-spin scaling factor: ", xas_tdp_control%c_os
    1248              :          END IF
    1249              : 
    1250              :       END IF
    1251              : 
    1252           58 :    END SUBROUTINE print_info
    1253              : 
    1254              : ! **************************************************************************************************
    1255              : !> \brief Assosciate (possibly localized) lowest energy  MOs to each excited atoms. The procedure
    1256              : !>        looks for MOs "centered" on the excited atoms by comparing distances. It
    1257              : !>        then fills the mos_of_ex_atoms arrays of the xas_tdp_env. Only the xas_tdp_control%n_search
    1258              : !>        lowest energy MOs are considered. Largely inspired by MI's implementation of XAS
    1259              : !>        It is assumed that the Berry phase is used to compute centers.
    1260              : !> \param xas_tdp_env ...
    1261              : !> \param xas_tdp_control ...
    1262              : !> \param qs_env ...
    1263              : !> \note Whether localization took place or not, the procedure is the same as centers are stored in
    1264              : !>       xas_tdp_env%qs_loc_env%localized_wfn_control%centers_set
    1265              : !>       Assumes that find_mo_centers has been run previously
    1266              : ! **************************************************************************************************
    1267           58 :    SUBROUTINE assign_mos_to_ex_atoms(xas_tdp_env, xas_tdp_control, qs_env)
    1268              : 
    1269              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    1270              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    1271              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1272              : 
    1273              :       INTEGER                                            :: at_index, iat, iat_memo, imo, ispin, &
    1274              :                                                             n_atoms, n_search, nex_atoms, nspins
    1275              :       INTEGER, DIMENSION(3)                              :: perd_init
    1276           58 :       INTEGER, DIMENSION(:, :, :), POINTER               :: mos_of_ex_atoms
    1277              :       REAL(dp)                                           :: dist, dist_min
    1278              :       REAL(dp), DIMENSION(3)                             :: at_pos, r_ac, wfn_center
    1279              :       TYPE(cell_type), POINTER                           :: cell
    1280              :       TYPE(localized_wfn_control_type), POINTER          :: localized_wfn_control
    1281           58 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1282              : 
    1283           58 :       NULLIFY (localized_wfn_control, mos_of_ex_atoms, cell, particle_set)
    1284              : 
    1285              : !  Initialization. mos_of_ex_atoms filled with -1, meaning no assigned state
    1286           58 :       mos_of_ex_atoms => xas_tdp_env%mos_of_ex_atoms
    1287          580 :       mos_of_ex_atoms(:, :, :) = -1
    1288           58 :       n_search = xas_tdp_control%n_search
    1289           58 :       nex_atoms = xas_tdp_env%nex_atoms
    1290           58 :       localized_wfn_control => xas_tdp_env%qs_loc_env%localized_wfn_control
    1291           58 :       CALL get_qs_env(qs_env=qs_env, particle_set=particle_set, cell=cell)
    1292           58 :       n_atoms = SIZE(particle_set)
    1293           58 :       nspins = 1; IF (xas_tdp_control%do_uks) nspins = 2
    1294              : 
    1295              : !     Temporarly impose periodic BCs because of Berry's phase operator used for localization
    1296          232 :       perd_init = cell%perd
    1297          232 :       cell%perd = 1
    1298              : 
    1299              : !  Loop over n_search lowest energy MOs and all atoms, for each spin
    1300          122 :       DO ispin = 1, nspins
    1301          414 :          DO imo = 1, n_search
    1302              : !           retrieve MO wave function center coordinates.
    1303         1168 :             wfn_center(1:3) = localized_wfn_control%centers_set(ispin)%array(1:3, imo)
    1304          292 :             iat_memo = 0
    1305              : 
    1306              : !           a large enough value to avoid bad surprises
    1307          292 :             dist_min = 10000.0_dp
    1308         7678 :             DO iat = 1, n_atoms
    1309        29544 :                at_pos = particle_set(iat)%r
    1310         7386 :                r_ac = pbc(at_pos, wfn_center, cell)
    1311        29544 :                dist = NORM2(r_ac)
    1312              : 
    1313              : !              keep memory of which atom is the closest to the wave function center
    1314         7678 :                IF (dist < dist_min) THEN
    1315          668 :                   iat_memo = iat
    1316          668 :                   dist_min = dist
    1317              :                END IF
    1318              :             END DO
    1319              : 
    1320              : !           Verify that the closest atom is actually excited and assign the MO if so
    1321          588 :             IF (ANY(xas_tdp_env%ex_atom_indices == iat_memo)) THEN
    1322          134 :                at_index = locate(xas_tdp_env%ex_atom_indices, iat_memo)
    1323          134 :                mos_of_ex_atoms(imo, at_index, ispin) = 1
    1324              :             END IF
    1325              :          END DO !imo
    1326              :       END DO !ispin
    1327              : 
    1328              : !  Go back to initial BCs
    1329          232 :       cell%perd = perd_init
    1330              : 
    1331           58 :    END SUBROUTINE assign_mos_to_ex_atoms
    1332              : 
    1333              : ! **************************************************************************************************
    1334              : !> \brief Re-initialize the qs_loc_env to the current MOs.
    1335              : !> \param qs_loc_env the env to re-initialize
    1336              : !> \param n_loc_states the number of states to include
    1337              : !> \param do_uks in cas of spin unrestricted calculation, initialize for both spins
    1338              : !> \param qs_env ...
    1339              : !> \note  Useful when one needs to make use of qs_loc features and it is either with canonical MOs
    1340              : !>        or the localized MOs have been modified. do_localize is overwritten.
    1341              : !>        Same loc range for both spins
    1342              : ! **************************************************************************************************
    1343           92 :    SUBROUTINE reinit_qs_loc_env(qs_loc_env, n_loc_states, do_uks, qs_env)
    1344              : 
    1345              :       TYPE(qs_loc_env_type), POINTER                     :: qs_loc_env
    1346              :       INTEGER, INTENT(IN)                                :: n_loc_states
    1347              :       LOGICAL, INTENT(IN)                                :: do_uks
    1348              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1349              : 
    1350              :       INTEGER                                            :: i, nspins
    1351              :       TYPE(localized_wfn_control_type), POINTER          :: loc_wfn_control
    1352              : 
    1353              : !  First, release the old env
    1354           92 :       CALL qs_loc_env_release(qs_loc_env)
    1355              : 
    1356              : !  Re-create it
    1357           92 :       CALL qs_loc_env_create(qs_loc_env)
    1358           92 :       CALL localized_wfn_control_create(qs_loc_env%localized_wfn_control)
    1359           92 :       loc_wfn_control => qs_loc_env%localized_wfn_control
    1360              : 
    1361              : !  Initialize it
    1362           92 :       loc_wfn_control%localization_method = do_loc_none
    1363           92 :       loc_wfn_control%operator_type = op_loc_berry
    1364          276 :       loc_wfn_control%nloc_states(:) = n_loc_states
    1365           92 :       loc_wfn_control%eps_occ = 0.0_dp
    1366          276 :       loc_wfn_control%lu_bound_states(1, :) = 1
    1367          276 :       loc_wfn_control%lu_bound_states(2, :) = n_loc_states
    1368           92 :       loc_wfn_control%set_of_states = state_loc_list
    1369           92 :       loc_wfn_control%do_homo = .TRUE.
    1370          276 :       ALLOCATE (loc_wfn_control%loc_states(n_loc_states, 2))
    1371          584 :       DO i = 1, n_loc_states
    1372         1568 :          loc_wfn_control%loc_states(i, :) = i
    1373              :       END DO
    1374              : 
    1375           92 :       nspins = 1; IF (do_uks) nspins = 2
    1376           92 :       CALL set_loc_centers(loc_wfn_control, loc_wfn_control%nloc_states, nspins=nspins)
    1377              :       ! need to set do_localize=.TRUE. because otherwise no routine works
    1378           92 :       IF (do_uks) THEN
    1379            8 :          CALL qs_loc_env_init(qs_loc_env, loc_wfn_control, qs_env, do_localize=.TRUE.)
    1380              :       ELSE
    1381           84 :          CALL qs_loc_env_init(qs_loc_env, loc_wfn_control, qs_env, myspin=1, do_localize=.TRUE.)
    1382              :       END IF
    1383              : 
    1384           92 :    END SUBROUTINE reinit_qs_loc_env
    1385              : 
    1386              : ! *************************************************************************************************
    1387              : !> \brief Diagonalize the subset of previously localized MOs that are associated to each excited
    1388              : !>        atoms. Updates the MO coeffs accordingly.
    1389              : !> \param xas_tdp_env ...
    1390              : !> \param xas_tdp_control ...
    1391              : !> \param qs_env ...
    1392              : !> \note  Needed because after localization, the MOs loose their identity (1s, 2s , 2p, etc)
    1393              : ! **************************************************************************************************
    1394           34 :    SUBROUTINE diagonalize_assigned_mo_subset(xas_tdp_env, xas_tdp_control, qs_env)
    1395              : 
    1396              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    1397              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    1398              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1399              : 
    1400              :       INTEGER                                            :: i, iat, ilmo, ispin, nao, nlmo, nspins
    1401           34 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: evals
    1402              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    1403              :       TYPE(cp_fm_struct_type), POINTER                   :: ks_struct, lmo_struct
    1404              :       TYPE(cp_fm_type)                                   :: evecs, ks_fm, lmo_fm, work
    1405              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
    1406           34 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks
    1407           34 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
    1408              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1409              : 
    1410           34 :       NULLIFY (mos, mo_coeff, matrix_ks, para_env, blacs_env, lmo_struct, ks_struct)
    1411              : 
    1412              :       ! Get what we need from qs_env
    1413           34 :       CALL get_qs_env(qs_env, mos=mos, matrix_ks=matrix_ks, para_env=para_env, blacs_env=blacs_env)
    1414              : 
    1415           34 :       nspins = 1; IF (xas_tdp_control%do_uks) nspins = 2
    1416              : 
    1417              :       ! Loop over the excited atoms and spin
    1418           70 :       DO ispin = 1, nspins
    1419          116 :          DO iat = 1, xas_tdp_env%nex_atoms
    1420              : 
    1421              :             ! get the MOs
    1422           46 :             CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, nao=nao)
    1423              : 
    1424              :             ! count how many MOs are associated to this atom and create a fm/struct
    1425          346 :             nlmo = COUNT(xas_tdp_env%mos_of_ex_atoms(:, iat, ispin) == 1)
    1426              :             CALL cp_fm_struct_create(lmo_struct, nrow_global=nao, ncol_global=nlmo, &
    1427           46 :                                      para_env=para_env, context=blacs_env)
    1428           46 :             CALL cp_fm_create(lmo_fm, lmo_struct)
    1429           46 :             CALL cp_fm_create(work, lmo_struct)
    1430              : 
    1431              :             CALL cp_fm_struct_create(ks_struct, nrow_global=nlmo, ncol_global=nlmo, &
    1432           46 :                                      para_env=para_env, context=blacs_env)
    1433           46 :             CALL cp_fm_create(ks_fm, ks_struct)
    1434           46 :             CALL cp_fm_create(evecs, ks_struct)
    1435              : 
    1436              :             ! Loop over the localized MOs associated to this atom
    1437           46 :             i = 0
    1438          346 :             DO ilmo = 1, xas_tdp_control%n_search
    1439          300 :                IF (xas_tdp_env%mos_of_ex_atoms(ilmo, iat, ispin) == -1) CYCLE
    1440              : 
    1441           62 :                i = i + 1
    1442              :                ! put the coeff in our atom-restricted lmo_fm
    1443              :                CALL cp_fm_to_fm_submat(mo_coeff, lmo_fm, nrow=nao, ncol=1, s_firstrow=1, &
    1444          346 :                                        s_firstcol=ilmo, t_firstrow=1, t_firstcol=i)
    1445              : 
    1446              :             END DO !ilmo
    1447              : 
    1448              :             ! Computing the KS matrix in the subset of MOs
    1449           46 :             CALL cp_dbcsr_sm_fm_multiply(matrix_ks(ispin)%matrix, lmo_fm, work, ncol=nlmo)
    1450           46 :             CALL parallel_gemm('T', 'N', nlmo, nlmo, nao, 1.0_dp, lmo_fm, work, 0.0_dp, ks_fm)
    1451              : 
    1452              :             ! Diagonalizing the KS matrix in the subset of MOs
    1453          138 :             ALLOCATE (evals(nlmo))
    1454           46 :             CALL cp_fm_syevd(ks_fm, evecs, evals)
    1455           46 :             DEALLOCATE (evals)
    1456              : 
    1457              :             ! Express the MOs in the basis that diagonalizes KS
    1458           46 :             CALL parallel_gemm('N', 'N', nao, nlmo, nlmo, 1.0_dp, lmo_fm, evecs, 0.0_dp, work)
    1459              : 
    1460              :             ! Replacing the new MOs back in the MO coeffs
    1461           46 :             i = 0
    1462          346 :             DO ilmo = 1, xas_tdp_control%n_search
    1463          300 :                IF (xas_tdp_env%mos_of_ex_atoms(ilmo, iat, ispin) == -1) CYCLE
    1464              : 
    1465           62 :                i = i + 1
    1466              :                CALL cp_fm_to_fm_submat(work, mo_coeff, nrow=nao, ncol=1, s_firstrow=1, &
    1467          346 :                                        s_firstcol=i, t_firstrow=1, t_firstcol=ilmo)
    1468              : 
    1469              :             END DO
    1470              : 
    1471              :             ! Excited atom clean-up
    1472           46 :             CALL cp_fm_release(lmo_fm)
    1473           46 :             CALL cp_fm_release(work)
    1474           46 :             CALL cp_fm_struct_release(lmo_struct)
    1475           46 :             CALL cp_fm_release(ks_fm)
    1476           46 :             CALL cp_fm_release(evecs)
    1477          220 :             CALL cp_fm_struct_release(ks_struct)
    1478              :          END DO !iat
    1479              :       END DO !ispin
    1480              : 
    1481           68 :    END SUBROUTINE diagonalize_assigned_mo_subset
    1482              : 
    1483              : ! **************************************************************************************************
    1484              : !> \brief Assign core MO(s) to a given donor_state, taking the type (1S, 2S, etc) into account.
    1485              : !>        The projection on a representative Slater-type orbital basis is used as a indicator.
    1486              : !>        It is assumed that MOs are already assigned to excited atoms based on their center
    1487              : !> \param donor_state the donor_state to which a MO must be assigned
    1488              : !> \param xas_tdp_env ...
    1489              : !> \param xas_tdp_control ...
    1490              : !> \param qs_env ...
    1491              : ! **************************************************************************************************
    1492           80 :    SUBROUTINE assign_mos_to_donor_state(donor_state, xas_tdp_env, xas_tdp_control, qs_env)
    1493              : 
    1494              :       TYPE(donor_state_type), POINTER                    :: donor_state
    1495              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    1496              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    1497              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1498              : 
    1499              :       INTEGER                                            :: at_index, i, iat, imo, ispin, l, my_mo, &
    1500              :                                                             n_search, n_states, nao, ndo_so, nj, &
    1501              :                                                             nsgf_kind, nsgf_sto, nspins, &
    1502              :                                                             output_unit, zval
    1503           80 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: my_mos
    1504              :       INTEGER, DIMENSION(2)                              :: next_best_overlap_ind
    1505              :       INTEGER, DIMENSION(4, 7)                           :: ne
    1506           80 :       INTEGER, DIMENSION(:), POINTER                     :: first_sgf, lq, nq
    1507           80 :       INTEGER, DIMENSION(:, :, :), POINTER               :: mos_of_ex_atoms
    1508              :       LOGICAL                                            :: unique
    1509              :       REAL(dp)                                           :: zeff
    1510           80 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: diag, overlap, sto_overlap
    1511           80 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: max_overlap
    1512              :       REAL(dp), DIMENSION(2)                             :: next_best_overlap
    1513           80 :       REAL(dp), DIMENSION(:), POINTER                    :: mo_evals, zeta
    1514           80 :       REAL(dp), DIMENSION(:, :), POINTER                 :: overlap_matrix, tmp_coeff
    1515              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    1516              :       TYPE(cp_fm_struct_type), POINTER                   :: eval_mat_struct, gs_struct, matrix_struct
    1517              :       TYPE(cp_fm_type)                                   :: eval_mat, work_mat
    1518              :       TYPE(cp_fm_type), POINTER                          :: gs_coeffs, mo_coeff
    1519           80 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks
    1520              :       TYPE(gto_basis_set_type), POINTER                  :: kind_basis_set, sto_to_gto_basis_set
    1521           80 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
    1522              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1523           80 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1524           80 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1525              :       TYPE(sto_basis_set_type), POINTER                  :: sto_basis_set
    1526              : 
    1527           80 :       NULLIFY (sto_basis_set, sto_to_gto_basis_set, qs_kind_set, kind_basis_set, lq, nq, zeta)
    1528           80 :       NULLIFY (overlap_matrix, mos, mo_coeff, mos_of_ex_atoms, tmp_coeff, first_sgf, particle_set)
    1529           80 :       NULLIFY (mo_evals, matrix_ks, para_env, blacs_env)
    1530           80 :       NULLIFY (eval_mat_struct, gs_struct, gs_coeffs)
    1531              : 
    1532          160 :       output_unit = cp_logger_get_default_io_unit()
    1533              : 
    1534              :       CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set, mos=mos, particle_set=particle_set, &
    1535           80 :                       matrix_ks=matrix_ks, para_env=para_env, blacs_env=blacs_env)
    1536              : 
    1537           80 :       nspins = 1; IF (xas_tdp_control%do_uks) nspins = 2
    1538              : 
    1539              : !  Construction of a STO that fits the type of orbital we look for
    1540           80 :       ALLOCATE (zeta(1))
    1541           80 :       ALLOCATE (lq(1))
    1542           80 :       ALLOCATE (nq(1))
    1543              : !     Retrieving quantum numbers
    1544           80 :       IF (donor_state%state_type == xas_1s_type) THEN
    1545           66 :          nq(1) = 1
    1546           66 :          lq(1) = 0
    1547           66 :          n_states = 1
    1548           14 :       ELSE IF (donor_state%state_type == xas_2s_type) THEN
    1549            6 :          nq(1) = 2
    1550            6 :          lq(1) = 0
    1551            6 :          n_states = 1
    1552            8 :       ELSE IF (donor_state%state_type == xas_2p_type) THEN
    1553            8 :          nq(1) = 2
    1554            8 :          lq(1) = 1
    1555            8 :          n_states = 3
    1556              :       ELSE
    1557            0 :          CPABORT("Procedure for required type not implemented")
    1558              :       END IF
    1559          320 :       ALLOCATE (my_mos(n_states, nspins))
    1560          240 :       ALLOCATE (max_overlap(n_states, nspins))
    1561              : 
    1562              : !     Getting the atomic number
    1563           80 :       CALL get_qs_kind(qs_kind_set(donor_state%kind_index), zeff=zeff)
    1564           80 :       zval = INT(zeff)
    1565              : 
    1566              : !     Electronic configuration (copied from MI's XAS)
    1567           80 :       ne = 0
    1568          400 :       DO l = 1, 4
    1569          320 :          nj = 2*(l - 1) + 1
    1570         2160 :          DO i = l, 7
    1571         1760 :             ne(l, i) = ptable(zval)%e_conv(l - 1) - 2*nj*(i - l)
    1572         1760 :             ne(l, i) = MAX(ne(l, i), 0)
    1573         2080 :             ne(l, i) = MIN(ne(l, i), 2*nj)
    1574              :          END DO
    1575              :       END DO
    1576              : 
    1577              : !     computing zeta with the Slater sum rules
    1578           80 :       zeta(1) = srules(zval, ne, nq(1), lq(1))
    1579              : 
    1580              : !     Allocating memory and initiate STO
    1581           80 :       CALL allocate_sto_basis_set(sto_basis_set)
    1582           80 :       CALL set_sto_basis_set(sto_basis_set, nshell=1, nq=nq, lq=lq, zet=zeta)
    1583              : 
    1584              : !     Some clean-up
    1585           80 :       DEALLOCATE (nq, lq, zeta)
    1586              : 
    1587              : !  Expanding the STO into (normalized) GTOs for later calculations, use standard 3 gaussians
    1588              :       CALL create_gto_from_sto_basis(sto_basis_set=sto_basis_set, &
    1589              :                                      gto_basis_set=sto_to_gto_basis_set, &
    1590           80 :                                      ngauss=3)
    1591           80 :       sto_to_gto_basis_set%norm_type = 2
    1592           80 :       CALL init_orb_basis_set(sto_to_gto_basis_set)
    1593              : 
    1594              : !  Retrieving the atomic kind related GTO in which MOs are expanded
    1595           80 :       CALL get_qs_kind(qs_kind_set(donor_state%kind_index), basis_set=kind_basis_set)
    1596              : 
    1597              : !  Allocating and computing the overlap between the two basis (they share the same center)
    1598           80 :       CALL get_gto_basis_set(gto_basis_set=kind_basis_set, nsgf=nsgf_kind)
    1599           80 :       CALL get_gto_basis_set(gto_basis_set=sto_to_gto_basis_set, nsgf=nsgf_sto)
    1600          320 :       ALLOCATE (overlap_matrix(nsgf_sto, nsgf_kind))
    1601              : 
    1602              : !     Making use of MI's subroutine
    1603           80 :       CALL calc_stogto_overlap(sto_to_gto_basis_set, kind_basis_set, overlap_matrix)
    1604              : 
    1605              : !     Some clean-up
    1606           80 :       CALL deallocate_sto_basis_set(sto_basis_set)
    1607           80 :       CALL deallocate_gto_basis_set(sto_to_gto_basis_set)
    1608              : 
    1609              : !  Looping over the potential donor states to compute overlap with STO basis
    1610           80 :       mos_of_ex_atoms => xas_tdp_env%mos_of_ex_atoms
    1611           80 :       n_search = xas_tdp_control%n_search
    1612           80 :       at_index = donor_state%at_index
    1613           80 :       iat = locate(xas_tdp_env%ex_atom_indices, at_index)
    1614          240 :       ALLOCATE (first_sgf(SIZE(particle_set))) !probably do not need that
    1615           80 :       CALL get_particle_set(particle_set=particle_set, qs_kind_set=qs_kind_set, first_sgf=first_sgf)
    1616          240 :       ALLOCATE (tmp_coeff(nsgf_kind, 1))
    1617          160 :       ALLOCATE (sto_overlap(nsgf_kind))
    1618          240 :       ALLOCATE (overlap(n_search))
    1619              : 
    1620           80 :       next_best_overlap = 0.0_dp
    1621          276 :       max_overlap = 0.0_dp
    1622              : 
    1623          168 :       DO ispin = 1, nspins
    1624              : 
    1625           88 :          CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, nao=nao)
    1626          518 :          overlap = 0.0_dp
    1627              : 
    1628           88 :          my_mo = 0
    1629          518 :          DO imo = 1, n_search
    1630          518 :             IF (mos_of_ex_atoms(imo, iat, ispin) > 0) THEN
    1631              : 
    1632         4320 :                sto_overlap = 0.0_dp
    1633         4504 :                tmp_coeff = 0.0_dp
    1634              : 
    1635              : !              Getting the relevant coefficients for the candidate state
    1636              :                CALL cp_fm_get_submatrix(fm=mo_coeff, target_m=tmp_coeff, start_row=first_sgf(at_index), &
    1637          184 :                                         start_col=imo, n_rows=nsgf_kind, n_cols=1, transpose=.FALSE.)
    1638              : 
    1639              : !              Computing the product overlap_matrix*coeffs
    1640              :                CALL dgemm('N', 'N', nsgf_sto, 1, nsgf_kind, 1.0_dp, overlap_matrix, nsgf_sto, &
    1641          184 :                           tmp_coeff, nsgf_kind, 0.0_dp, sto_overlap, nsgf_sto)
    1642              : 
    1643              : !              Each element of column vector sto_overlap is the overlap of a basis element of the
    1644              : !              generated STO basis with the kind specific orbital basis. Take the sum of the absolute
    1645              : !              values so that rotation (of the px, py, pz for example) does not hinder our search
    1646         4320 :                overlap(imo) = SUM(ABS(sto_overlap))
    1647              : 
    1648              :             END IF
    1649              :          END DO
    1650              : 
    1651              : !     Finding the best overlap(s)
    1652          196 :          DO i = 1, n_states
    1653          638 :             my_mo = MAXLOC(overlap, 1)
    1654          108 :             my_mos(i, ispin) = my_mo
    1655          746 :             max_overlap(i, ispin) = MAXVAL(overlap, 1)
    1656          196 :             overlap(my_mo) = 0.0_dp
    1657              :          END DO
    1658              : !        Getting the next best overlap (for validation purposes)
    1659          606 :          next_best_overlap(ispin) = MAXVAL(overlap, 1)
    1660          518 :          next_best_overlap_ind(ispin) = MAXLOC(overlap, 1)
    1661              : 
    1662              : !        Sort MO indices
    1663          256 :          CALL sort_unique(my_mos(:, ispin), unique)
    1664              : 
    1665              :       END DO !ispin
    1666              : 
    1667              : !     Some clean-up
    1668           80 :       DEALLOCATE (overlap_matrix, tmp_coeff)
    1669              : 
    1670              : !  Dealing with the result
    1671          552 :       IF (ALL(my_mos > 0) .AND. ALL(my_mos <= n_search)) THEN
    1672              : !        Assigning the MO indices to the donor_state
    1673          160 :          ALLOCATE (donor_state%mo_indices(n_states, nspins))
    1674          276 :          donor_state%mo_indices = my_mos
    1675           80 :          donor_state%ndo_mo = n_states
    1676              : 
    1677              : !        Storing the MOs in the donor_state, as vectors column: first columns alpha spin, then beta
    1678              :          CALL cp_fm_struct_create(gs_struct, nrow_global=nao, ncol_global=n_states*nspins, &
    1679           80 :                                   para_env=para_env, context=blacs_env)
    1680           80 :          ALLOCATE (donor_state%gs_coeffs)
    1681           80 :          CALL cp_fm_create(donor_state%gs_coeffs, gs_struct)
    1682              : 
    1683           80 :          IF (.NOT. ASSOCIATED(xas_tdp_env%mo_coeff)) THEN
    1684          180 :             ALLOCATE (xas_tdp_env%mo_coeff(nspins))
    1685              :          END IF
    1686              : 
    1687          168 :          DO ispin = 1, nspins
    1688           88 :             CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff)
    1689              :             ! check if mo_coeff is copied before for another donor_state
    1690           88 :             IF (.NOT. ASSOCIATED(xas_tdp_env%mo_coeff(ispin)%local_data)) THEN
    1691              :                ! copy mo_coeff
    1692              :                CALL cp_fm_get_info(matrix=mo_coeff, &
    1693           64 :                                    matrix_struct=matrix_struct)
    1694           64 :                CALL cp_fm_create(xas_tdp_env%mo_coeff(ispin), matrix_struct)
    1695           64 :                CALL cp_fm_to_fm(mo_coeff, xas_tdp_env%mo_coeff(ispin))
    1696              :             END IF
    1697              : 
    1698          276 :             DO i = 1, n_states
    1699              :                CALL cp_fm_to_fm_submat(msource=mo_coeff, mtarget=donor_state%gs_coeffs, nrow=nao, &
    1700              :                                        ncol=1, s_firstrow=1, s_firstcol=my_mos(i, ispin), &
    1701          196 :                                        t_firstrow=1, t_firstcol=(ispin - 1)*n_states + i)
    1702              :             END DO
    1703              :          END DO
    1704           80 :          gs_coeffs => donor_state%gs_coeffs
    1705              : 
    1706              :          !Keep the subset of the coeffs centered on the excited atom as global array (used a lot)
    1707          320 :          ALLOCATE (donor_state%contract_coeffs(nsgf_kind, n_states*nspins))
    1708              :          CALL cp_fm_get_submatrix(gs_coeffs, donor_state%contract_coeffs, start_row=first_sgf(at_index), &
    1709           80 :                                   start_col=1, n_rows=nsgf_kind, n_cols=n_states*nspins)
    1710              : 
    1711              : !     Assigning corresponding energy eigenvalues and writing some info in standard input file
    1712              : 
    1713              :          !standard eigenvalues as gotten from the KS diagonalization in the ground state
    1714           80 :          IF (.NOT. xas_tdp_control%do_loc .AND. .NOT. xas_tdp_control%do_roks) THEN
    1715           30 :             IF (output_unit > 0) THEN
    1716              :                WRITE (UNIT=output_unit, FMT="(T5,A,/,T5,A,/,T5,A)") &
    1717           15 :                   "The following canonical MO(s) have been associated with the donor state(s)", &
    1718           15 :                   "based on the overlap with the components of a minimal STO basis: ", &
    1719           30 :                   "                                         Spin   MO index     overlap(sum)"
    1720              :             END IF
    1721              : 
    1722           60 :             ALLOCATE (donor_state%energy_evals(n_states, nspins))
    1723          110 :             donor_state%energy_evals = 0.0_dp
    1724              : 
    1725              : !           Canonical MO, no change in eigenvalues, only diagonal elements
    1726           64 :             DO ispin = 1, nspins
    1727           34 :                CALL get_mo_set(mos(ispin), eigenvalues=mo_evals)
    1728          110 :                DO i = 1, n_states
    1729           46 :                   donor_state%energy_evals(i, ispin) = mo_evals(my_mos(i, ispin))
    1730              : 
    1731           80 :                   IF (output_unit > 0) THEN
    1732              :                      WRITE (UNIT=output_unit, FMT="(T46,I4,I11,F17.5)") &
    1733           23 :                         ispin, my_mos(i, ispin), max_overlap(i, ispin)
    1734              :                   END IF
    1735              :                END DO
    1736              :             END DO
    1737              : 
    1738              :             !either localization of MOs or ROKS, in both cases the MO eigenvalues from the KS
    1739              :             !digonalization mat have changed
    1740              :          ELSE
    1741           50 :             IF (output_unit > 0) THEN
    1742              :                WRITE (UNIT=output_unit, FMT="(T5,A,/,T5,A,/,T5,A)") &
    1743           25 :                   "The following localized MO(s) have been associated with the donor state(s)", &
    1744           25 :                   "based on the overlap with the components of a minimal STO basis: ", &
    1745           50 :                   "                                         Spin   MO index     overlap(sum)"
    1746              :             END IF
    1747              : 
    1748              : !           Loop over the donor states  and print
    1749          104 :             DO ispin = 1, nspins
    1750          166 :                DO i = 1, n_states
    1751              : 
    1752              : !                 Print info
    1753          116 :                   IF (output_unit > 0) THEN
    1754              :                      WRITE (UNIT=output_unit, FMT="(T46,I4,I11,F17.5)") &
    1755           31 :                         ispin, my_mos(i, ispin), max_overlap(i, ispin)
    1756              :                   END IF
    1757              :                END DO
    1758              :             END DO
    1759              : 
    1760              : !           MO have been rotated or non-physical ROKS MO eigrenvalues:
    1761              : !           => need epsilon_ij = <psi_i|F|psi_j> = sum_{pq} c_{qi}c_{pj} F_{pq}
    1762              : !           Note: only have digonal elements by construction
    1763           50 :             ndo_so = nspins*n_states
    1764           50 :             CALL cp_fm_create(work_mat, gs_struct)
    1765              :             CALL cp_fm_struct_create(eval_mat_struct, nrow_global=ndo_so, ncol_global=ndo_so, &
    1766           50 :                                      para_env=para_env, context=blacs_env)
    1767           50 :             CALL cp_fm_create(eval_mat, eval_mat_struct)
    1768          150 :             ALLOCATE (diag(ndo_so))
    1769              : 
    1770           50 :             IF (.NOT. xas_tdp_control%do_roks) THEN
    1771              : 
    1772          100 :                ALLOCATE (donor_state%energy_evals(n_states, nspins))
    1773          166 :                donor_state%energy_evals = 0.0_dp
    1774              : 
    1775              : !              Compute gs_coeff^T * matrix_ks * gs_coeff to get the epsilon_ij matrix
    1776          104 :                DO ispin = 1, nspins
    1777           54 :                   CALL cp_dbcsr_sm_fm_multiply(matrix_ks(ispin)%matrix, gs_coeffs, work_mat, ncol=ndo_so)
    1778           54 :                   CALL parallel_gemm('T', 'N', ndo_so, ndo_so, nao, 1.0_dp, gs_coeffs, work_mat, 0.0_dp, eval_mat)
    1779              : 
    1780              : !                 Put the epsilon_ii into the donor_state. No off-diagonal element because of subset diag
    1781           54 :                   CALL cp_fm_get_diag(eval_mat, diag)
    1782          166 :                   donor_state%energy_evals(:, ispin) = diag((ispin - 1)*n_states + 1:ispin*n_states)
    1783              : 
    1784              :                END DO
    1785              : 
    1786              :             ELSE
    1787              :                ! If ROKS, slightly different procedure => 2 KS matrices but one type of MOs
    1788            0 :                ALLOCATE (donor_state%energy_evals(n_states, 2))
    1789            0 :                donor_state%energy_evals = 0.0_dp
    1790              : 
    1791              : !              Compute gs_coeff^T * matrix_ks * gs_coeff to get the epsilon_ij matrix
    1792            0 :                DO ispin = 1, 2
    1793            0 :                   CALL cp_dbcsr_sm_fm_multiply(matrix_ks(ispin)%matrix, gs_coeffs, work_mat, ncol=ndo_so)
    1794            0 :                   CALL parallel_gemm('T', 'N', ndo_so, ndo_so, nao, 1.0_dp, gs_coeffs, work_mat, 0.0_dp, eval_mat)
    1795              : 
    1796            0 :                   CALL cp_fm_get_diag(eval_mat, diag)
    1797            0 :                   donor_state%energy_evals(:, ispin) = diag(:)
    1798              : 
    1799              :                END DO
    1800              : 
    1801            0 :                DEALLOCATE (diag)
    1802              :             END IF
    1803              : 
    1804              : !           Clean-up
    1805           50 :             CALL cp_fm_release(work_mat)
    1806           50 :             CALL cp_fm_release(eval_mat)
    1807          150 :             CALL cp_fm_struct_release(eval_mat_struct)
    1808              : 
    1809              :          END IF ! do_localize and/or ROKS
    1810              : 
    1811              : !        Allocate and initialize GW2X corrected IPs as energy_evals
    1812          320 :          ALLOCATE (donor_state%gw2x_evals(SIZE(donor_state%energy_evals, 1), SIZE(donor_state%energy_evals, 2)))
    1813          276 :          donor_state%gw2x_evals(:, :) = donor_state%energy_evals(:, :)
    1814              : 
    1815              : !        Clean-up
    1816           80 :          CALL cp_fm_struct_release(gs_struct)
    1817           80 :          DEALLOCATE (first_sgf)
    1818              : 
    1819           80 :          IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T5,A)") " "
    1820              : 
    1821          168 :          DO ispin = 1, nspins
    1822          168 :             IF (output_unit > 0) THEN
    1823              :                WRITE (UNIT=output_unit, FMT="(T5,A,I1,A,F7.5,A,I4)") &
    1824           44 :                   "The next best overlap for spin ", ispin, " is ", next_best_overlap(ispin), &
    1825           88 :                   " for MO with index ", next_best_overlap_ind(ispin)
    1826              :             END IF
    1827              :          END DO
    1828           80 :          IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T5,A)") " "
    1829              : 
    1830              :       ELSE
    1831            0 :          CPABORT("A core donor state could not be assigned MO(s). Increasing NSEARCH might help.")
    1832              :       END IF
    1833              : 
    1834          320 :    END SUBROUTINE assign_mos_to_donor_state
    1835              : 
    1836              : ! **************************************************************************************************
    1837              : !> \brief Compute the centers and spreads of (core) MOs using the Berry phase operator
    1838              : !> \param xas_tdp_env ...
    1839              : !> \param xas_tdp_control ...
    1840              : !> \param qs_env ...
    1841              : !> \note xas_tdp_env%qs_loc_env is used and modified. OK since no localization done after this
    1842              : !>       subroutine is used.
    1843              : ! **************************************************************************************************
    1844           92 :    SUBROUTINE find_mo_centers(xas_tdp_env, xas_tdp_control, qs_env)
    1845              : 
    1846              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    1847              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    1848              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1849              : 
    1850              :       INTEGER                                            :: dim_op, i, ispin, j, n_centers, nao, &
    1851              :                                                             nspins
    1852              :       REAL(dp), DIMENSION(6)                             :: weights
    1853              :       TYPE(cell_type), POINTER                           :: cell
    1854              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    1855              :       TYPE(cp_fm_struct_type), POINTER                   :: tmp_fm_struct
    1856              :       TYPE(cp_fm_type)                                   :: opvec
    1857           92 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: zij_fm_set
    1858           92 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: moloc_coeff
    1859              :       TYPE(cp_fm_type), POINTER                          :: vectors
    1860           92 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: op_sm_set
    1861              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1862              :       TYPE(qs_loc_env_type), POINTER                     :: qs_loc_env
    1863              :       TYPE(section_vals_type), POINTER                   :: print_loc_section, prog_run_info
    1864              : 
    1865           92 :       NULLIFY (qs_loc_env, cell, print_loc_section, op_sm_set, moloc_coeff, vectors)
    1866           92 :       NULLIFY (tmp_fm_struct, para_env, blacs_env, prog_run_info)
    1867              : 
    1868              : !  Initialization
    1869           92 :       print_loc_section => xas_tdp_control%print_loc_subsection
    1870           92 :       n_centers = xas_tdp_control%n_search
    1871           92 :       CALL get_qs_env(qs_env=qs_env, para_env=para_env, blacs_env=blacs_env, cell=cell)
    1872              : 
    1873              : !  Set print option to debug to keep clean output file
    1874           92 :       prog_run_info => section_vals_get_subs_vals(print_loc_section, "PROGRAM_RUN_INFO")
    1875              :       CALL section_vals_val_set(prog_run_info, keyword_name="_SECTION_PARAMETERS_", &
    1876           92 :                                 i_val=debug_print_level)
    1877              : 
    1878              : !  Re-initialize the qs_loc_env to get the current MOs. Use force_loc because needed for centers
    1879           92 :       CALL reinit_qs_loc_env(xas_tdp_env%qs_loc_env, n_centers, xas_tdp_control%do_uks, qs_env)
    1880           92 :       qs_loc_env => xas_tdp_env%qs_loc_env
    1881              : 
    1882              : !  Get what we need from the qs_lovc_env
    1883              :       CALL get_qs_loc_env(qs_loc_env=qs_loc_env, weights=weights, op_sm_set=op_sm_set, &
    1884           92 :                           moloc_coeff=moloc_coeff)
    1885              : 
    1886              : !  Prepare for zij
    1887           92 :       vectors => moloc_coeff(1)
    1888           92 :       CALL cp_fm_get_info(vectors, nrow_global=nao)
    1889           92 :       CALL cp_fm_create(opvec, vectors%matrix_struct)
    1890              : 
    1891              :       CALL cp_fm_struct_create(tmp_fm_struct, para_env=para_env, context=blacs_env, &
    1892           92 :                                ncol_global=n_centers, nrow_global=n_centers)
    1893              : 
    1894           92 :       IF (cell%orthorhombic) THEN
    1895              :          dim_op = 3
    1896              :       ELSE
    1897            0 :          dim_op = 6
    1898              :       END IF
    1899         1012 :       ALLOCATE (zij_fm_set(2, dim_op))
    1900          368 :       DO i = 1, dim_op
    1901          920 :          DO j = 1, 2
    1902          828 :             CALL cp_fm_create(zij_fm_set(j, i), tmp_fm_struct)
    1903              :          END DO
    1904              :       END DO
    1905              : 
    1906              :       !  If spin-unrestricted, need to go spin by spin
    1907           92 :       nspins = 1; IF (xas_tdp_control%do_uks) nspins = 2
    1908              : 
    1909          192 :       DO ispin = 1, nspins
    1910              : !     zij computation, copied from qs_loc_methods:optimize_loc_berry
    1911          100 :          vectors => moloc_coeff(ispin)
    1912          400 :          DO i = 1, dim_op
    1913         1000 :             DO j = 1, 2
    1914          600 :                CALL cp_fm_set_all(zij_fm_set(j, i), 0.0_dp)
    1915          600 :                CALL cp_dbcsr_sm_fm_multiply(op_sm_set(j, i)%matrix, vectors, opvec, ncol=n_centers)
    1916              :                CALL parallel_gemm("T", "N", n_centers, n_centers, nao, 1.0_dp, vectors, opvec, 0.0_dp, &
    1917          900 :                                   zij_fm_set(j, i))
    1918              :             END DO
    1919              :          END DO
    1920              : 
    1921              : !     Compute centers (and spread)
    1922              :          CALL centers_spreads_berry(qs_loc_env=qs_loc_env, zij=zij_fm_set, nmoloc=n_centers, &
    1923              :                                     cell=cell, weights=weights, ispin=ispin, &
    1924          192 :                                     print_loc_section=print_loc_section, only_initial_out=.TRUE.)
    1925              :       END DO !ispins
    1926              : 
    1927              : !  Clean-up
    1928           92 :       CALL cp_fm_release(opvec)
    1929           92 :       CALL cp_fm_struct_release(tmp_fm_struct)
    1930           92 :       CALL cp_fm_release(zij_fm_set)
    1931              : 
    1932              : !  Make sure we leave with the correct do_loc value
    1933           92 :       qs_loc_env%do_localize = xas_tdp_control%do_loc
    1934              : 
    1935          276 :    END SUBROUTINE find_mo_centers
    1936              : 
    1937              : ! **************************************************************************************************
    1938              : !> \brief Prints the MO to donor_state assocaition with overlap and Mulliken population analysis
    1939              : !> \param xas_tdp_env ...
    1940              : !> \param xas_tdp_control ...
    1941              : !> \param qs_env ...
    1942              : !> \note  Called only in case of CHECK_ONLY run
    1943              : ! **************************************************************************************************
    1944            0 :    SUBROUTINE print_checks(xas_tdp_env, xas_tdp_control, qs_env)
    1945              : 
    1946              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    1947              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    1948              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1949              : 
    1950              :       CHARACTER(LEN=default_string_length)               :: kind_name
    1951              :       INTEGER                                            :: current_state_index, iat, iatom, ikind, &
    1952              :                                                             istate, output_unit, tmp_index
    1953            0 :       INTEGER, DIMENSION(:), POINTER                     :: atoms_of_kind
    1954            0 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    1955              :       TYPE(donor_state_type), POINTER                    :: current_state
    1956              : 
    1957            0 :       NULLIFY (atomic_kind_set, atoms_of_kind, current_state)
    1958              : 
    1959            0 :       output_unit = cp_logger_get_default_io_unit()
    1960              : 
    1961            0 :       IF (output_unit > 0) THEN
    1962              :          WRITE (output_unit, "(/,T3,A,/,T3,A,/,T3,A)") &
    1963            0 :             "# Check the donor states for their quality. They need to have a well defined type ", &
    1964            0 :             "  (1s, 2s, etc) which is indicated by the overlap. They also need to be localized, ", &
    1965            0 :             "  for which the Mulliken population analysis is one indicator (must be close to 1.0)"
    1966              :       END IF
    1967              : 
    1968              : !  Loop over the donor states (as in the main xas_tdp loop)
    1969            0 :       CALL get_qs_env(qs_env=qs_env, atomic_kind_set=atomic_kind_set)
    1970            0 :       current_state_index = 1
    1971              : 
    1972              :       !loop over atomic kinds
    1973            0 :       DO ikind = 1, SIZE(atomic_kind_set)
    1974              : 
    1975              :          CALL get_atomic_kind(atomic_kind=atomic_kind_set(ikind), name=kind_name, &
    1976            0 :                               atom_list=atoms_of_kind)
    1977              : 
    1978            0 :          IF (.NOT. ANY(xas_tdp_env%ex_kind_indices == ikind)) CYCLE
    1979              : 
    1980              :          !loop over atoms of kind
    1981            0 :          DO iat = 1, SIZE(atoms_of_kind)
    1982            0 :             iatom = atoms_of_kind(iat)
    1983              : 
    1984            0 :             IF (.NOT. ANY(xas_tdp_env%ex_atom_indices == iatom)) CYCLE
    1985            0 :             tmp_index = locate(xas_tdp_env%ex_atom_indices, iatom)
    1986              : 
    1987              :             !loop over states of excited atom
    1988            0 :             DO istate = 1, SIZE(xas_tdp_env%state_types, 1)
    1989              : 
    1990            0 :                IF (xas_tdp_env%state_types(istate, tmp_index) == xas_not_excited) CYCLE
    1991              : 
    1992            0 :                current_state => xas_tdp_env%donor_states(current_state_index)
    1993              :                CALL set_donor_state(current_state, at_index=iatom, &
    1994              :                                     at_symbol=kind_name, kind_index=ikind, &
    1995            0 :                                     state_type=xas_tdp_env%state_types(istate, tmp_index))
    1996              : 
    1997            0 :                IF (output_unit > 0) THEN
    1998              :                   WRITE (output_unit, "(/,T4,A,A2,A,I4,A,A,A)") &
    1999            0 :                      "-Donor state of type ", xas_tdp_env%state_type_char(current_state%state_type), &
    2000            0 :                      " for atom", current_state%at_index, " of kind ", TRIM(current_state%at_symbol), ":"
    2001              :                END IF
    2002              : 
    2003              :                !Assign the MOs and perform Mulliken
    2004            0 :                CALL assign_mos_to_donor_state(current_state, xas_tdp_env, xas_tdp_control, qs_env)
    2005            0 :                CALL perform_mulliken_on_donor_state(current_state, qs_env)
    2006              : 
    2007            0 :                current_state_index = current_state_index + 1
    2008            0 :                NULLIFY (current_state)
    2009              : 
    2010              :             END DO !istate
    2011              :          END DO !iat
    2012              :       END DO !ikind
    2013              : 
    2014            0 :       IF (output_unit > 0) THEN
    2015              :          WRITE (output_unit, "(/,T5,A)") &
    2016            0 :             "Use LOCALIZE and/or increase N_SEARCH for better results, if so required."
    2017              :       END IF
    2018              : 
    2019            0 :    END SUBROUTINE print_checks
    2020              : 
    2021              : ! **************************************************************************************************
    2022              : !> \brief Computes the required multipole moment in the length representation for a given atom
    2023              : !> \param iatom index of the given atom
    2024              : !> \param xas_tdp_env ...
    2025              : !> \param xas_tdp_control ...
    2026              : !> \param qs_env ...
    2027              : !> \note Assumes that wither dipole or quadrupole in length rep is required
    2028              : ! **************************************************************************************************
    2029           24 :    SUBROUTINE compute_lenrep_multipole(iatom, xas_tdp_env, xas_tdp_control, qs_env)
    2030              : 
    2031              :       INTEGER, INTENT(IN)                                :: iatom
    2032              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    2033              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    2034              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2035              : 
    2036              :       INTEGER                                            :: i, order
    2037              :       REAL(dp), DIMENSION(3)                             :: rc
    2038           24 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: work
    2039           24 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    2040              : 
    2041           24 :       NULLIFY (work, particle_set)
    2042              : 
    2043           24 :       CALL get_qs_env(qs_env, particle_set=particle_set)
    2044           96 :       rc = particle_set(iatom)%r
    2045              : 
    2046          240 :       ALLOCATE (work(9))
    2047           24 :       IF (xas_tdp_control%dipole_form == xas_dip_len) THEN
    2048           96 :          DO i = 1, 3
    2049           72 :             CALL dbcsr_set(xas_tdp_env%dipmat(i)%matrix, 0.0_dp)
    2050           96 :             work(i)%matrix => xas_tdp_env%dipmat(i)%matrix
    2051              :          END DO
    2052           24 :          order = 1
    2053              :       END IF
    2054           24 :       IF (xas_tdp_control%do_quad) THEN
    2055            0 :          DO i = 1, 6
    2056            0 :             CALL dbcsr_set(xas_tdp_env%quadmat(i)%matrix, 0.0_dp)
    2057            0 :             work(3 + i)%matrix => xas_tdp_env%quadmat(i)%matrix
    2058              :          END DO
    2059            0 :          order = 2
    2060            0 :          IF (xas_tdp_control%dipole_form == xas_dip_vel) order = -2
    2061              :       END IF
    2062              : 
    2063              :       !enforce minimum image to avoid PBCs related issues, ok because localized densities
    2064           24 :       CALL rRc_xyz_ao(work, qs_env, rc, order=order, minimum_image=.TRUE.)
    2065           24 :       DEALLOCATE (work)
    2066              : 
    2067           24 :    END SUBROUTINE compute_lenrep_multipole
    2068              : 
    2069              : ! **************************************************************************************************
    2070              : !> \brief Computes the oscillator strength based on the dipole moment (velocity or length rep) for
    2071              : !>        all available excitation energies and store the results in the donor_state. There is no
    2072              : !>        triplet dipole in the spin-restricted ground state.
    2073              : !> \param donor_state the donor state which is excited
    2074              : !> \param xas_tdp_control ...
    2075              : !> \param xas_tdp_env ...
    2076              : !> \note The oscillator strength is a scalar: osc_str = 2/(3*omega)*(dipole_v)^2 in the velocity rep
    2077              : !>       or : osc_str = 2/3*omega*(dipole_r)^2 in the length representation
    2078              : !>       The formulae for the dipoles come from the trace of the dipole operator with the transition
    2079              : !>       densities, i.e. what we get from solving the xas_tdp problem. Same procedure with or wo TDA
    2080              : ! **************************************************************************************************
    2081           68 :    SUBROUTINE compute_dipole_fosc(donor_state, xas_tdp_control, xas_tdp_env)
    2082              : 
    2083              :       TYPE(donor_state_type), POINTER                    :: donor_state
    2084              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    2085              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    2086              : 
    2087              :       CHARACTER(len=*), PARAMETER :: routineN = 'compute_dipole_fosc'
    2088              : 
    2089              :       INTEGER                                            :: handle, iosc, j, nao, ndo_mo, ndo_so, &
    2090              :                                                             ngs, nosc, nspins
    2091              :       LOGICAL                                            :: do_sc, do_sg
    2092              :       REAL(dp)                                           :: alpha_xyz, beta_xyz, osc_xyz, pref
    2093           68 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: alpha_contr, beta_contr, tot_contr
    2094           68 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: dip_block
    2095           68 :       REAL(dp), DIMENSION(:), POINTER                    :: lr_evals
    2096           68 :       REAL(dp), DIMENSION(:, :), POINTER                 :: alpha_osc, beta_osc, osc_str
    2097              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    2098              :       TYPE(cp_fm_struct_type), POINTER                   :: col_struct, mat_struct
    2099              :       TYPE(cp_fm_type)                                   :: col_work, mat_work
    2100              :       TYPE(cp_fm_type), POINTER                          :: lr_coeffs
    2101           68 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: dipmat
    2102              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2103              : 
    2104           68 :       NULLIFY (dipmat, col_struct, mat_struct, para_env, blacs_env, lr_coeffs)
    2105           68 :       NULLIFY (lr_evals, osc_str, alpha_osc, beta_osc)
    2106              : 
    2107           68 :       CALL timeset(routineN, handle)
    2108              : 
    2109              : !  Initialization
    2110           68 :       do_sc = xas_tdp_control%do_spin_cons
    2111           68 :       do_sg = xas_tdp_control%do_singlet
    2112           68 :       IF (do_sc) THEN
    2113            8 :          nspins = 2
    2114            8 :          lr_evals => donor_state%sc_evals
    2115            8 :          lr_coeffs => donor_state%sc_coeffs
    2116           60 :       ELSE IF (do_sg) THEN
    2117           60 :          nspins = 1
    2118           60 :          lr_evals => donor_state%sg_evals
    2119           60 :          lr_coeffs => donor_state%sg_coeffs
    2120              :       ELSE
    2121            0 :          CPABORT("Dipole oscilaltor strength only for singlets and spin-conserving excitations.")
    2122              :       END IF
    2123           68 :       ndo_mo = donor_state%ndo_mo
    2124           68 :       ndo_so = ndo_mo*nspins
    2125           68 :       ngs = ndo_so; IF (xas_tdp_control%do_roks) ngs = ndo_mo !in ROKS, same gs coeffs
    2126           68 :       nosc = SIZE(lr_evals)
    2127          340 :       ALLOCATE (donor_state%osc_str(nosc, 4), donor_state%alpha_osc(nosc, 4), donor_state%beta_osc(nosc, 4))
    2128           68 :       osc_str => donor_state%osc_str
    2129           68 :       alpha_osc => donor_state%alpha_osc
    2130           68 :       beta_osc => donor_state%beta_osc
    2131         4436 :       osc_str = 0.0_dp
    2132         4436 :       alpha_osc = 0.0_dp
    2133         4436 :       beta_osc = 0.0_dp
    2134           68 :       dipmat => xas_tdp_env%dipmat
    2135              : 
    2136              :       ! do some work matrix initialization
    2137              :       CALL cp_fm_get_info(donor_state%gs_coeffs, matrix_struct=col_struct, para_env=para_env, &
    2138           68 :                           context=blacs_env, nrow_global=nao)
    2139              :       CALL cp_fm_struct_create(mat_struct, para_env=para_env, context=blacs_env, &
    2140           68 :                                nrow_global=ndo_so*nosc, ncol_global=ngs)
    2141           68 :       CALL cp_fm_create(mat_work, mat_struct)
    2142           68 :       CALL cp_fm_create(col_work, col_struct)
    2143              : 
    2144          544 :       ALLOCATE (tot_contr(ndo_mo), dip_block(ndo_so, ngs), alpha_contr(ndo_mo), beta_contr(ndo_mo))
    2145           68 :       pref = 2.0_dp; IF (do_sc) pref = 1.0_dp !because of singlet definition u = 1/sqrt(2)(c_a+c_b)
    2146              : 
    2147              : !  Looping over cartesian coord
    2148          272 :       DO j = 1, 3
    2149              : 
    2150              :          !Compute dip*gs_coeffs
    2151          204 :          CALL cp_dbcsr_sm_fm_multiply(dipmat(j)%matrix, donor_state%gs_coeffs, col_work, ncol=ngs)
    2152              :          !compute lr_coeffs*dip*gs_coeffs
    2153          204 :          CALL parallel_gemm('T', 'N', ndo_so*nosc, ngs, nao, 1.0_dp, lr_coeffs, col_work, 0.0_dp, mat_work)
    2154              : 
    2155              :          !Loop over the excited states
    2156         3344 :          DO iosc = 1, nosc
    2157              : 
    2158         6432 :             tot_contr = 0.0_dp
    2159              :             CALL cp_fm_get_submatrix(fm=mat_work, target_m=dip_block, start_row=(iosc - 1)*ndo_so + 1, &
    2160         3072 :                                      start_col=1, n_rows=ndo_so, n_cols=ngs)
    2161         3072 :             IF (do_sg) THEN
    2162         2448 :                tot_contr(:) = get_diag(dip_block)
    2163          624 :             ELSE IF (do_sc .AND. xas_tdp_control%do_uks) THEN
    2164          624 :                alpha_contr(:) = get_diag(dip_block(1:ndo_mo, 1:ndo_mo))
    2165          624 :                beta_contr(:) = get_diag(dip_block(ndo_mo + 1:ndo_so, ndo_mo + 1:ndo_so))
    2166         1392 :                tot_contr(:) = alpha_contr(:) + beta_contr(:)
    2167              :             ELSE
    2168              :                !roks
    2169            0 :                alpha_contr(:) = get_diag(dip_block(1:ndo_mo, :))
    2170            0 :                beta_contr(:) = get_diag(dip_block(ndo_mo + 1:ndo_so, :))
    2171            0 :                tot_contr(:) = alpha_contr(:) + beta_contr(:)
    2172              :             END IF
    2173              : 
    2174         6432 :             osc_xyz = SUM(tot_contr)**2
    2175         6432 :             alpha_xyz = SUM(alpha_contr)**2
    2176         6432 :             beta_xyz = SUM(beta_contr)**2
    2177              : 
    2178         3072 :             alpha_osc(iosc, 4) = alpha_osc(iosc, 4) + alpha_xyz
    2179         3072 :             alpha_osc(iosc, j) = alpha_xyz
    2180              : 
    2181         3072 :             beta_osc(iosc, 4) = beta_osc(iosc, 4) + beta_xyz
    2182         3072 :             beta_osc(iosc, j) = beta_xyz
    2183              : 
    2184         3072 :             osc_str(iosc, 4) = osc_str(iosc, 4) + osc_xyz
    2185         3276 :             osc_str(iosc, j) = osc_xyz
    2186              : 
    2187              :          END DO !iosc
    2188              :       END DO !j
    2189              : 
    2190              :       !compute the prefactor
    2191          340 :       DO j = 1, 4
    2192          340 :          IF (xas_tdp_control%dipole_form == xas_dip_len) THEN
    2193         3248 :             osc_str(:, j) = pref*2.0_dp/3.0_dp*lr_evals(:)*osc_str(:, j)
    2194         3248 :             alpha_osc(:, j) = pref*2.0_dp/3.0_dp*lr_evals(:)*alpha_osc(:, j)
    2195         3248 :             beta_osc(:, j) = pref*2.0_dp/3.0_dp*lr_evals(:)*beta_osc(:, j)
    2196              :          ELSE
    2197         5488 :             osc_str(:, j) = pref*2.0_dp/3.0_dp/lr_evals(:)*osc_str(:, j)
    2198         5488 :             alpha_osc(:, j) = pref*2.0_dp/3.0_dp/lr_evals(:)*alpha_osc(:, j)
    2199         5488 :             beta_osc(:, j) = pref*2.0_dp/3.0_dp/lr_evals(:)*beta_osc(:, j)
    2200              :          END IF
    2201              :       END DO
    2202              : 
    2203              :       !clean-up
    2204           68 :       CALL cp_fm_release(mat_work)
    2205           68 :       CALL cp_fm_release(col_work)
    2206           68 :       CALL cp_fm_struct_release(mat_struct)
    2207              : 
    2208           68 :       CALL timestop(handle)
    2209              : 
    2210          272 :    END SUBROUTINE compute_dipole_fosc
    2211              : 
    2212              : ! **************************************************************************************************
    2213              : !> \brief Computes the oscillator strength due to the electric quadrupole moment and store it in
    2214              : !>        the donor_state (for singlet or spin-conserving)
    2215              : !> \param donor_state the donor state which is excited
    2216              : !> \param xas_tdp_control ...
    2217              : !> \param xas_tdp_env ...
    2218              : !> \note Formula: 1/20*a_fine^2*omega^3 * sum_ab (sum_i r_ia*r_ib - 1/3*ri^2*delta_ab)
    2219              : ! **************************************************************************************************
    2220            0 :    SUBROUTINE compute_quadrupole_fosc(donor_state, xas_tdp_control, xas_tdp_env)
    2221              : 
    2222              :       TYPE(donor_state_type), POINTER                    :: donor_state
    2223              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    2224              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    2225              : 
    2226              :       CHARACTER(len=*), PARAMETER :: routineN = 'compute_quadrupole_fosc'
    2227              : 
    2228              :       INTEGER                                            :: handle, iosc, j, nao, ndo_mo, ndo_so, &
    2229              :                                                             ngs, nosc, nspins
    2230              :       LOGICAL                                            :: do_sc, do_sg
    2231              :       REAL(dp)                                           :: pref
    2232            0 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: tot_contr, trace
    2233            0 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: quad_block
    2234            0 :       REAL(dp), DIMENSION(:), POINTER                    :: lr_evals, osc_str
    2235              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    2236              :       TYPE(cp_fm_struct_type), POINTER                   :: col_struct, mat_struct
    2237              :       TYPE(cp_fm_type)                                   :: col_work, mat_work
    2238              :       TYPE(cp_fm_type), POINTER                          :: lr_coeffs
    2239            0 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: quadmat
    2240              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2241              : 
    2242            0 :       NULLIFY (lr_evals, osc_str, lr_coeffs, col_struct, mat_struct, para_env)
    2243            0 :       NULLIFY (blacs_env)
    2244              : 
    2245            0 :       CALL timeset(routineN, handle)
    2246              : 
    2247              :       ! Initialization
    2248            0 :       do_sc = xas_tdp_control%do_spin_cons
    2249            0 :       do_sg = xas_tdp_control%do_singlet
    2250            0 :       IF (do_sc) THEN
    2251            0 :          nspins = 2
    2252            0 :          lr_evals => donor_state%sc_evals
    2253            0 :          lr_coeffs => donor_state%sc_coeffs
    2254            0 :       ELSE IF (do_sg) THEN
    2255            0 :          nspins = 1
    2256            0 :          lr_evals => donor_state%sg_evals
    2257            0 :          lr_coeffs => donor_state%sg_coeffs
    2258              :       ELSE
    2259            0 :          CPABORT("Quadrupole oscillator strengths only for singlet and spin-conserving excitations")
    2260              :       END IF
    2261            0 :       ndo_mo = donor_state%ndo_mo
    2262            0 :       ndo_so = ndo_mo*nspins
    2263            0 :       ngs = ndo_so; IF (xas_tdp_control%do_roks) ngs = ndo_mo !only alpha do_mo in ROKS
    2264            0 :       nosc = SIZE(lr_evals)
    2265            0 :       ALLOCATE (donor_state%quad_osc_str(nosc))
    2266            0 :       osc_str => donor_state%quad_osc_str
    2267            0 :       osc_str = 0.0_dp
    2268            0 :       quadmat => xas_tdp_env%quadmat
    2269              : 
    2270              :       !work matrices init
    2271              :       CALL cp_fm_get_info(donor_state%gs_coeffs, matrix_struct=col_struct, para_env=para_env, &
    2272            0 :                           context=blacs_env, nrow_global=nao)
    2273              :       CALL cp_fm_struct_create(mat_struct, para_env=para_env, context=blacs_env, &
    2274            0 :                                nrow_global=ndo_so*nosc, ncol_global=ngs)
    2275            0 :       CALL cp_fm_create(mat_work, mat_struct)
    2276            0 :       CALL cp_fm_create(col_work, col_struct)
    2277              : 
    2278            0 :       ALLOCATE (quad_block(ndo_so, ngs), tot_contr(ndo_mo))
    2279            0 :       pref = 2.0_dp; IF (do_sc) pref = 1.0_dp !because of singlet definition u = 1/sqrt(2)*...
    2280            0 :       ALLOCATE (trace(nosc))
    2281            0 :       trace = 0.0_dp
    2282              : 
    2283              :       !Loop over the cartesioan coord :x2, xy, xz, y2, yz, z2
    2284            0 :       DO j = 1, 6
    2285              : 
    2286              :          !Compute quad*gs_coeffs
    2287            0 :          CALL cp_dbcsr_sm_fm_multiply(quadmat(j)%matrix, donor_state%gs_coeffs, col_work, ncol=ngs)
    2288              :          !compute lr_coeffs*quadmat*gs_coeffs
    2289            0 :          CALL parallel_gemm('T', 'N', ndo_so*nosc, ngs, nao, 1.0_dp, lr_coeffs, col_work, 0.0_dp, mat_work)
    2290              : 
    2291              :          !Loop over the excited states
    2292            0 :          DO iosc = 1, nosc
    2293              : 
    2294            0 :             tot_contr = 0.0_dp
    2295              :             CALL cp_fm_get_submatrix(fm=mat_work, target_m=quad_block, start_row=(iosc - 1)*ndo_so + 1, &
    2296            0 :                                      start_col=1, n_rows=ndo_so, n_cols=ngs)
    2297              : 
    2298            0 :             IF (do_sg) THEN
    2299            0 :                tot_contr(:) = get_diag(quad_block)
    2300            0 :             ELSE IF (do_sc .AND. xas_tdp_control%do_uks) THEN
    2301            0 :                tot_contr(:) = get_diag(quad_block(1:ndo_mo, 1:ndo_mo)) !alpha
    2302            0 :                tot_contr(:) = tot_contr(:) + get_diag(quad_block(ndo_mo + 1:ndo_so, ndo_mo + 1:ndo_so)) !beta
    2303              :             ELSE
    2304              :                !roks
    2305            0 :                tot_contr(:) = get_diag(quad_block(1:ndo_mo, :)) !alpha
    2306            0 :                tot_contr(:) = tot_contr(:) + get_diag(quad_block(ndo_mo + 1:ndo_so, :)) !beta
    2307              :             END IF
    2308              : 
    2309              :             !if x2, y2, or z2 direction, need to update the trace (for later)
    2310            0 :             IF (j == 1 .OR. j == 4 .OR. j == 6) THEN
    2311            0 :                osc_str(iosc) = osc_str(iosc) + SUM(tot_contr)**2
    2312            0 :                trace(iosc) = trace(iosc) + SUM(tot_contr)
    2313              : 
    2314              :                !if xy, xz or yz, need to count twice the contribution (for yx, zx and zy)
    2315              :             ELSE
    2316            0 :                osc_str(iosc) = osc_str(iosc) + 2.0_dp*SUM(tot_contr)**2
    2317              :             END IF
    2318              : 
    2319              :          END DO !iosc
    2320              :       END DO !j
    2321              : 
    2322              :       !compute the prefactor, and remove 1/3*trace^2
    2323            0 :       osc_str(:) = pref*1._dp/20._dp*a_fine**2*lr_evals(:)**3*(osc_str(:) - 1._dp/3._dp*trace(:)**2)
    2324              : 
    2325              :       !clean-up
    2326            0 :       CALL cp_fm_release(mat_work)
    2327            0 :       CALL cp_fm_release(col_work)
    2328            0 :       CALL cp_fm_struct_release(mat_struct)
    2329              : 
    2330            0 :       CALL timestop(handle)
    2331              : 
    2332            0 :    END SUBROUTINE compute_quadrupole_fosc
    2333              : 
    2334              : ! **************************************************************************************************
    2335              : !> \brief Writes the core MOs to excited atoms associations in the main output file
    2336              : !> \param xas_tdp_env ...
    2337              : !> \param xas_tdp_control ...
    2338              : !> \param qs_env ...
    2339              : !> \note Look at alpha spin MOs, as we are dealing with core states and alpha/beta MOs are the same
    2340              : ! **************************************************************************************************
    2341           58 :    SUBROUTINE write_mos_to_ex_atoms_association(xas_tdp_env, xas_tdp_control, qs_env)
    2342              : 
    2343              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    2344              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    2345              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2346              : 
    2347              :       CHARACTER(LEN=default_string_length)               :: kind_name
    2348              :       INTEGER                                            :: at_index, imo, ispin, nmo, nspins, &
    2349              :                                                             output_unit, tmp_index
    2350              :       INTEGER, DIMENSION(3)                              :: perd_init
    2351           58 :       INTEGER, DIMENSION(:), POINTER                     :: ex_atom_indices
    2352           58 :       INTEGER, DIMENSION(:, :, :), POINTER               :: mos_of_ex_atoms
    2353              :       REAL(dp)                                           :: dist, mo_spread
    2354              :       REAL(dp), DIMENSION(3)                             :: at_pos, r_ac, wfn_center
    2355              :       TYPE(cell_type), POINTER                           :: cell
    2356           58 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    2357              : 
    2358           58 :       NULLIFY (cell, particle_set, mos_of_ex_atoms, ex_atom_indices)
    2359              : 
    2360          116 :       output_unit = cp_logger_get_default_io_unit()
    2361              : 
    2362           58 :       IF (output_unit > 0) THEN
    2363              :          WRITE (UNIT=output_unit, FMT="(/,T3,A,/,T3,A,/,T3,A)") &
    2364           29 :             "                  Associated    Associated        Distance to   MO spread (Ang^2)", &
    2365           29 :             "Spin  MO index    atom index     atom kind    MO center (Ang)   -w_i ln(|z_ij|^2)", &
    2366           58 :             "---------------------------------------------------------------------------------"
    2367              :       END IF
    2368              : 
    2369              : !  Initialization
    2370           58 :       nspins = 1; IF (xas_tdp_control%do_uks) nspins = 2
    2371           58 :       mos_of_ex_atoms => xas_tdp_env%mos_of_ex_atoms
    2372           58 :       ex_atom_indices => xas_tdp_env%ex_atom_indices
    2373           58 :       nmo = xas_tdp_control%n_search
    2374           58 :       CALL get_qs_env(qs_env=qs_env, particle_set=particle_set, cell=cell)
    2375              : 
    2376              : !     because the use of Berry's phase operator implies PBCs
    2377          232 :       perd_init = cell%perd
    2378          232 :       cell%perd = 1
    2379              : 
    2380              : !  Retrieving all the info for each MO and spin
    2381          334 :       DO imo = 1, nmo
    2382          626 :          DO ispin = 1, nspins
    2383              : 
    2384              : !           each Mo is associated to at most one atom (only 1 in array of -1)
    2385          800 :             IF (ANY(mos_of_ex_atoms(imo, :, ispin) == 1)) THEN
    2386          296 :                tmp_index = MAXLOC(mos_of_ex_atoms(imo, :, ispin), 1)
    2387          134 :                at_index = ex_atom_indices(tmp_index)
    2388          134 :                kind_name = particle_set(at_index)%atomic_kind%name
    2389              : 
    2390          536 :                at_pos = particle_set(at_index)%r
    2391          536 :                wfn_center = xas_tdp_env%qs_loc_env%localized_wfn_control%centers_set(ispin)%array(1:3, imo)
    2392          134 :                r_ac = pbc(at_pos, wfn_center, cell)
    2393          536 :                dist = NORM2(r_ac)
    2394              : !              convert distance from a.u. to Angstrom
    2395          134 :                dist = dist*angstrom
    2396              : 
    2397          134 :                mo_spread = xas_tdp_env%qs_loc_env%localized_wfn_control%centers_set(ispin)%array(4, imo)
    2398          134 :                mo_spread = mo_spread*angstrom*angstrom
    2399              : 
    2400          134 :                IF (output_unit > 0) THEN
    2401              :                   WRITE (UNIT=output_unit, FMT="(T3,I4,I10,I14,A14,ES19.3,ES20.3)") &
    2402           67 :                      ispin, imo, at_index, TRIM(kind_name), dist, mo_spread
    2403              :                END IF
    2404              : 
    2405              :             END IF
    2406              :          END DO !ispin
    2407              :       END DO !imo
    2408              : 
    2409           58 :       IF (output_unit > 0) THEN
    2410              :          WRITE (UNIT=output_unit, FMT="(T3,A,/)") &
    2411           29 :             "---------------------------------------------------------------------------------"
    2412              :       END IF
    2413              : 
    2414              : !  Go back to initial BCs
    2415          232 :       cell%perd = perd_init
    2416              : 
    2417           58 :    END SUBROUTINE write_mos_to_ex_atoms_association
    2418              : 
    2419              : ! **************************************************************************************************
    2420              : !> \brief Performs Mulliken population analysis for the MO(s) of a donor_state_type so that user
    2421              : !>        can verify it is indeed a core state
    2422              : !> \param donor_state ...
    2423              : !> \param qs_env ...
    2424              : !> \note This is a specific case of Mulliken analysis. In general one computes sum_i (SP)_ii, where
    2425              : !>       i labels the basis function centered on the atom of interest. For a specific MO with index
    2426              : !>       j, one need to compute sum_{ik} c_{ij} S_{ik} c_{kj}, k = 1,nao
    2427              : ! **************************************************************************************************
    2428           80 :    SUBROUTINE perform_mulliken_on_donor_state(donor_state, qs_env)
    2429              :       TYPE(donor_state_type), POINTER                    :: donor_state
    2430              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2431              : 
    2432              :       INTEGER                                            :: at_index, i, ispin, nao, natom, ndo_mo, &
    2433              :                                                             ndo_so, nsgf, nspins, output_unit
    2434           80 :       INTEGER, DIMENSION(:), POINTER                     :: first_sgf, last_sgf
    2435           80 :       INTEGER, DIMENSION(:, :), POINTER                  :: mo_indices
    2436           80 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: mul_pop, pop_mat
    2437           80 :       REAL(dp), DIMENSION(:, :), POINTER                 :: work_array
    2438              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    2439              :       TYPE(cp_fm_struct_type), POINTER                   :: col_vect_struct
    2440              :       TYPE(cp_fm_type)                                   :: work_vect
    2441              :       TYPE(cp_fm_type), POINTER                          :: gs_coeffs
    2442           80 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
    2443              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2444           80 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    2445           80 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    2446              : 
    2447           80 :       NULLIFY (mo_indices, qs_kind_set, particle_set, first_sgf, work_array)
    2448           80 :       NULLIFY (matrix_s, para_env, blacs_env, col_vect_struct, last_sgf)
    2449              : 
    2450              : !  Initialization
    2451           80 :       at_index = donor_state%at_index
    2452           80 :       mo_indices => donor_state%mo_indices
    2453           80 :       ndo_mo = donor_state%ndo_mo
    2454           80 :       gs_coeffs => donor_state%gs_coeffs
    2455          160 :       output_unit = cp_logger_get_default_io_unit()
    2456           80 :       nspins = 1; IF (SIZE(mo_indices, 2) == 2) nspins = 2
    2457           80 :       ndo_so = ndo_mo*nspins
    2458          320 :       ALLOCATE (mul_pop(ndo_mo, nspins))
    2459          276 :       mul_pop = 0.0_dp
    2460              : 
    2461              :       CALL get_qs_env(qs_env=qs_env, particle_set=particle_set, qs_kind_set=qs_kind_set, &
    2462           80 :                       para_env=para_env, blacs_env=blacs_env, matrix_s=matrix_s)
    2463           80 :       CALL cp_fm_get_info(gs_coeffs, nrow_global=nao, matrix_struct=col_vect_struct)
    2464              : 
    2465           80 :       natom = SIZE(particle_set, 1)
    2466          240 :       ALLOCATE (first_sgf(natom))
    2467          160 :       ALLOCATE (last_sgf(natom))
    2468              : 
    2469           80 :       CALL get_particle_set(particle_set, qs_kind_set, first_sgf=first_sgf, last_sgf=last_sgf)
    2470           80 :       nsgf = last_sgf(at_index) - first_sgf(at_index) + 1
    2471              : 
    2472           80 :       CALL cp_fm_create(work_vect, col_vect_struct)
    2473              : 
    2474              : !  Take the product of S*coeffs
    2475           80 :       CALL cp_dbcsr_sm_fm_multiply(matrix_s(1)%matrix, gs_coeffs, work_vect, ncol=ndo_so)
    2476              : 
    2477              : !  Only consider the product coeffs^T * S * coeffs on the atom of interest
    2478          320 :       ALLOCATE (work_array(nsgf, ndo_so))
    2479          320 :       ALLOCATE (pop_mat(ndo_so, ndo_so))
    2480              : 
    2481              :       CALL cp_fm_get_submatrix(fm=work_vect, target_m=work_array, start_row=first_sgf(at_index), &
    2482           80 :                                start_col=1, n_rows=nsgf, n_cols=ndo_so, transpose=.FALSE.)
    2483              : 
    2484              :       CALL dgemm('T', 'N', ndo_so, ndo_so, nsgf, 1.0_dp, donor_state%contract_coeffs, nsgf, &
    2485           80 :                  work_array, nsgf, 0.0_dp, pop_mat, ndo_so)
    2486              : 
    2487              : !  The Mullikan population for the MOs in on the diagonal.
    2488          168 :       DO ispin = 1, nspins
    2489          276 :          DO i = 1, ndo_mo
    2490          196 :             mul_pop(i, ispin) = pop_mat((ispin - 1)*ndo_mo + i, (ispin - 1)*ndo_mo + i)
    2491              :          END DO
    2492              :       END DO
    2493              : 
    2494              : !  Printing in main output file
    2495           80 :       IF (output_unit > 0) THEN
    2496              :          WRITE (UNIT=output_unit, FMT="(T5,A,/,T5,A)") &
    2497           40 :             "Mulliken population analysis retricted to the associated MO(s) yields: ", &
    2498           80 :             "                                              Spin  MO index     charge"
    2499           84 :          DO ispin = 1, nspins
    2500          138 :             DO i = 1, ndo_mo
    2501              :                WRITE (UNIT=output_unit, FMT="(T51,I4,I10,F11.3)") &
    2502           98 :                   ispin, mo_indices(i, ispin), mul_pop(i, ispin)
    2503              :             END DO
    2504              :          END DO
    2505              :       END IF
    2506              : 
    2507              : !  Clean-up
    2508           80 :       DEALLOCATE (first_sgf, last_sgf, work_array)
    2509           80 :       CALL cp_fm_release(work_vect)
    2510              : 
    2511          320 :    END SUBROUTINE perform_mulliken_on_donor_state
    2512              : 
    2513              : ! **************************************************************************************************
    2514              : !> \brief write the PDOS wrt the LR-orbitals for the current donor_state and/or the CUBES files
    2515              : !> \param ex_type the excitation type: singlet, triplet, spin-conserving, etc
    2516              : !> \param donor_state ...
    2517              : !> \param xas_tdp_env ...
    2518              : !> \param xas_tdp_section ...
    2519              : !> \param qs_env ...
    2520              : ! **************************************************************************************************
    2521           86 :    SUBROUTINE xas_tdp_post(ex_type, donor_state, xas_tdp_env, xas_tdp_section, qs_env)
    2522              : 
    2523              :       INTEGER, INTENT(IN)                                :: ex_type
    2524              :       TYPE(donor_state_type), POINTER                    :: donor_state
    2525              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    2526              :       TYPE(section_vals_type), POINTER                   :: xas_tdp_section
    2527              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2528              : 
    2529              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'xas_tdp_post'
    2530              : 
    2531              :       CHARACTER(len=default_string_length)               :: domo, domon, excite, pos, xas_mittle
    2532              :       INTEGER :: ex_state_idx, handle, ic, ido_mo, imo, irep, ispin, n_dependent, n_rep, nao, &
    2533              :          ncubes, ndo_mo, ndo_so, nlumo, nmo, nspins, output_unit
    2534           74 :       INTEGER, DIMENSION(:), POINTER                     :: bounds, list, state_list
    2535              :       LOGICAL                                            :: append_cube, do_cubes, do_pdos, &
    2536              :                                                             do_wfn_restart
    2537           74 :       REAL(dp), DIMENSION(:), POINTER                    :: lr_evals
    2538           74 :       REAL(dp), DIMENSION(:, :), POINTER                 :: centers
    2539           74 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    2540              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    2541              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct, mo_struct
    2542              :       TYPE(cp_fm_type)                                   :: mo_coeff, work_fm
    2543              :       TYPE(cp_fm_type), POINTER                          :: lr_coeffs
    2544              :       TYPE(cp_logger_type), POINTER                      :: logger
    2545           74 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
    2546           74 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
    2547              :       TYPE(mo_set_type), POINTER                         :: mo_set
    2548              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2549           74 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    2550           74 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    2551              :       TYPE(section_vals_type), POINTER                   :: print_key
    2552              : 
    2553           74 :       NULLIFY (atomic_kind_set, particle_set, qs_kind_set, mo_set, lr_evals, lr_coeffs)
    2554           74 :       NULLIFY (mo_struct, para_env, blacs_env, fm_struct, matrix_s, print_key, logger)
    2555           74 :       NULLIFY (bounds, state_list, list, mos)
    2556              : 
    2557              :       !Tests on what to do
    2558          148 :       logger => cp_get_default_logger()
    2559           74 :       do_pdos = .FALSE.; do_cubes = .FALSE.; do_wfn_restart = .FALSE.
    2560              : 
    2561           74 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, xas_tdp_section, &
    2562            2 :                                            "PRINT%PDOS"), cp_p_file)) do_pdos = .TRUE.
    2563              : 
    2564           74 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, xas_tdp_section, &
    2565            2 :                                            "PRINT%CUBES"), cp_p_file)) do_cubes = .TRUE.
    2566              : 
    2567           74 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, xas_tdp_section, &
    2568            2 :                                            "PRINT%RESTART_WFN"), cp_p_file)) do_wfn_restart = .TRUE.
    2569              : 
    2570           74 :       IF (.NOT. (do_pdos .OR. do_cubes .OR. do_wfn_restart)) RETURN
    2571              : 
    2572            4 :       CALL timeset(routineN, handle)
    2573              : 
    2574              :       !Initialization
    2575              :       CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, particle_set=particle_set, &
    2576              :                       qs_kind_set=qs_kind_set, para_env=para_env, blacs_env=blacs_env, &
    2577            4 :                       matrix_s=matrix_s, mos=mos)
    2578              : 
    2579            4 :       SELECT CASE (ex_type)
    2580              :       CASE (tddfpt_spin_cons)
    2581            0 :          lr_evals => donor_state%sc_evals
    2582            0 :          lr_coeffs => donor_state%sc_coeffs
    2583            0 :          nspins = 2
    2584            0 :          excite = "spincons"
    2585              :       CASE (tddfpt_spin_flip)
    2586            0 :          lr_evals => donor_state%sf_evals
    2587            0 :          lr_coeffs => donor_state%sf_coeffs
    2588            0 :          nspins = 2
    2589            0 :          excite = "spinflip"
    2590              :       CASE (tddfpt_singlet)
    2591            4 :          lr_evals => donor_state%sg_evals
    2592            4 :          lr_coeffs => donor_state%sg_coeffs
    2593            4 :          nspins = 1
    2594            4 :          excite = "singlet"
    2595              :       CASE (tddfpt_triplet)
    2596            0 :          lr_evals => donor_state%tp_evals
    2597            0 :          lr_coeffs => donor_state%tp_coeffs
    2598            0 :          nspins = 1
    2599            4 :          excite = "triplet"
    2600              :       END SELECT
    2601              : 
    2602            8 :       SELECT CASE (donor_state%state_type)
    2603              :       CASE (xas_1s_type)
    2604            4 :          domo = "1s"
    2605              :       CASE (xas_2s_type)
    2606            0 :          domo = "2s"
    2607              :       CASE (xas_2p_type)
    2608            4 :          domo = "2p"
    2609              :       END SELECT
    2610              : 
    2611            4 :       ndo_mo = donor_state%ndo_mo
    2612            4 :       ndo_so = ndo_mo*nspins
    2613            4 :       nmo = SIZE(lr_evals)
    2614            4 :       CALL dbcsr_get_info(matrix_s(1)%matrix, nfullrows_total=nao)
    2615              : 
    2616              :       CALL cp_fm_struct_create(mo_struct, context=blacs_env, para_env=para_env, &
    2617            4 :                                nrow_global=nao, ncol_global=nmo)
    2618            4 :       CALL cp_fm_create(mo_coeff, mo_struct)
    2619              : 
    2620              :       !Dump the TDDFT excited state AMEW wavefunction into a file for restart in RTP
    2621            4 :       IF (do_wfn_restart) THEN
    2622            2 :          BLOCK
    2623            6 :             TYPE(mo_set_type), DIMENSION(2) :: restart_mos
    2624            2 :             IF (.NOT. (nspins == 1 .AND. donor_state%state_type == xas_1s_type)) THEN
    2625            0 :                CPABORT("RESTART.wfn file only available for RKS K-edge XAS spectroscopy")
    2626              :             END IF
    2627              : 
    2628            2 :             CALL section_vals_val_get(xas_tdp_section, "PRINT%RESTART_WFN%EXCITED_STATE_INDEX", n_rep_val=n_rep)
    2629              : 
    2630            4 :             DO irep = 1, n_rep
    2631              :                CALL section_vals_val_get(xas_tdp_section, "PRINT%RESTART_WFN%EXCITED_STATE_INDEX", &
    2632            2 :                                          i_rep_val=irep, i_val=ex_state_idx)
    2633            2 :                CPASSERT(ex_state_idx <= SIZE(lr_evals))
    2634              : 
    2635            6 :                DO ispin = 1, 2
    2636            4 :                   CALL duplicate_mo_set(restart_mos(ispin), mos(1))
    2637              :                   ! Set the new occupation number in the case of spin-independent based calculaltion since the restart is spin-depedent
    2638            4 :                   IF (SIZE(mos) == 1) &
    2639           26 :                      restart_mos(ispin)%occupation_numbers = mos(1)%occupation_numbers/2
    2640              :                END DO
    2641              : 
    2642              :                CALL cp_fm_to_fm_submat(msource=lr_coeffs, mtarget=restart_mos(1)%mo_coeff, nrow=nao, &
    2643              :                                        ncol=1, s_firstrow=1, s_firstcol=ex_state_idx, t_firstrow=1, &
    2644            2 :                                        t_firstcol=donor_state%mo_indices(1, 1))
    2645              : 
    2646              :                xas_mittle = 'xasat'//TRIM(ADJUSTL(cp_to_string(donor_state%at_index)))//'_'//TRIM(domo)// &
    2647            2 :                             '_'//TRIM(excite)//'_idx'//TRIM(ADJUSTL(cp_to_string(ex_state_idx)))
    2648              :                output_unit = cp_print_key_unit_nr(logger, xas_tdp_section, "PRINT%RESTART_WFN", &
    2649              :                                                   extension=".wfn", file_status="REPLACE", &
    2650              :                                                   file_action="WRITE", file_form="UNFORMATTED", &
    2651            2 :                                                   middle_name=xas_mittle)
    2652              : 
    2653              :                CALL write_mo_set_low(restart_mos, particle_set=particle_set, &
    2654            2 :                                      qs_kind_set=qs_kind_set, ires=output_unit)
    2655              : 
    2656            2 :                CALL cp_print_key_finished_output(output_unit, logger, xas_tdp_section, "PRINT%RESTART_WFN")
    2657              : 
    2658           10 :                DO ispin = 1, 2
    2659            6 :                   CALL deallocate_mo_set(restart_mos(ispin))
    2660              :                END DO
    2661              :             END DO
    2662              :          END BLOCK
    2663              :       END IF
    2664              : 
    2665              :       !PDOS related stuff
    2666            4 :       IF (do_pdos) THEN
    2667              : 
    2668              :          !If S^0.5 not yet stored, compute it once and for all
    2669            2 :          IF (.NOT. ASSOCIATED(xas_tdp_env%matrix_shalf) .AND. do_pdos) THEN
    2670              :             CALL cp_fm_struct_create(fm_struct, context=blacs_env, para_env=para_env, &
    2671            2 :                                      nrow_global=nao, ncol_global=nao)
    2672            2 :             ALLOCATE (xas_tdp_env%matrix_shalf)
    2673            2 :             CALL cp_fm_create(xas_tdp_env%matrix_shalf, fm_struct)
    2674            2 :             CALL cp_fm_create(work_fm, fm_struct)
    2675              : 
    2676            2 :             CALL copy_dbcsr_to_fm(matrix_s(1)%matrix, xas_tdp_env%matrix_shalf)
    2677            2 :             CALL cp_fm_power(xas_tdp_env%matrix_shalf, work_fm, 0.5_dp, EPSILON(0.0_dp), n_dependent)
    2678              : 
    2679            2 :             CALL cp_fm_release(work_fm)
    2680            2 :             CALL cp_fm_struct_release(fm_struct)
    2681              :          END IF
    2682              : 
    2683              :          !Giving some PDOS info
    2684            2 :          output_unit = cp_logger_get_default_io_unit()
    2685            2 :          IF (output_unit > 0) THEN
    2686              :             WRITE (UNIT=output_unit, FMT="(/,T5,A,/,T5,A,/,T5,A)") &
    2687            1 :                "Computing the PDOS of linear-response orbitals for spectral features analysis", &
    2688            1 :                "Note: using standard PDOS routines => ignore mentions of KS states and MO ", &
    2689            2 :                "      occupation numbers. Eigenvalues in *.pdos files are excitations energies."
    2690              :          END IF
    2691              : 
    2692              :          !Check on NLUMO
    2693            2 :          CALL section_vals_val_get(xas_tdp_section, "PRINT%PDOS%NLUMO", i_val=nlumo)
    2694            2 :          IF (nlumo .NE. 0) THEN
    2695            0 :             CPWARN("NLUMO is irrelevant for XAS_TDP PDOS. It was overwritten to 0.")
    2696              :          END IF
    2697            2 :          CALL section_vals_val_set(xas_tdp_section, "PRINT%PDOS%NLUMO", i_val=0)
    2698              :       END IF
    2699              : 
    2700              :       !CUBES related stuff
    2701            4 :       IF (do_cubes) THEN
    2702              : 
    2703            2 :          print_key => section_vals_get_subs_vals(xas_tdp_section, "PRINT%CUBES")
    2704              : 
    2705            2 :          CALL section_vals_val_get(print_key, "CUBES_LU_BOUNDS", i_vals=bounds)
    2706            2 :          ncubes = bounds(2) - bounds(1) + 1
    2707            2 :          IF (ncubes > 0) THEN
    2708            0 :             ALLOCATE (state_list(ncubes))
    2709            0 :             DO ic = 1, ncubes
    2710            0 :                state_list(ic) = bounds(1) + ic - 1
    2711              :             END DO
    2712              :          END IF
    2713              : 
    2714            2 :          IF (.NOT. ASSOCIATED(state_list)) THEN
    2715            2 :             CALL section_vals_val_get(print_key, "CUBES_LIST", n_rep_val=n_rep)
    2716              : 
    2717            2 :             ncubes = 0
    2718            4 :             DO irep = 1, n_rep
    2719            2 :                NULLIFY (list)
    2720            2 :                CALL section_vals_val_get(print_key, "CUBES_LIST", i_rep_val=irep, i_vals=list)
    2721            4 :                IF (ASSOCIATED(list)) THEN
    2722            2 :                   CALL reallocate(state_list, 1, ncubes + SIZE(list))
    2723            4 :                   DO ic = 1, SIZE(list)
    2724            4 :                      state_list(ncubes + ic) = list(ic)
    2725              :                   END DO
    2726            2 :                   ncubes = ncubes + SIZE(list)
    2727              :                END IF
    2728              :             END DO
    2729              :          END IF
    2730              : 
    2731            2 :          IF (.NOT. ASSOCIATED(state_list)) THEN
    2732            0 :             ncubes = 1
    2733            0 :             ALLOCATE (state_list(1))
    2734            0 :             state_list(1) = 1
    2735              :          END IF
    2736              : 
    2737            2 :          CALL section_vals_val_get(print_key, "APPEND", l_val=append_cube)
    2738            2 :          pos = "REWIND"
    2739            2 :          IF (append_cube) pos = "APPEND"
    2740              : 
    2741            6 :          ALLOCATE (centers(6, ncubes))
    2742           18 :          centers = 0.0_dp
    2743              : 
    2744              :       END IF
    2745              : 
    2746              :       !Loop over MOs and spin, one PDOS/CUBE for each
    2747            8 :       DO ido_mo = 1, ndo_mo
    2748           12 :          DO ispin = 1, nspins
    2749              : 
    2750              :             !need to create a mo set for the LR-orbitals
    2751            4 :             ALLOCATE (mo_set)
    2752              :             CALL allocate_mo_set(mo_set, nao=nao, nmo=nmo, nelectron=nmo, n_el_f=REAL(nmo, dp), &
    2753            4 :                                  maxocc=1.0_dp, flexible_electron_count=0.0_dp)
    2754            4 :             CALL init_mo_set(mo_set, fm_ref=mo_coeff, name="PDOS XAS_TDP MOs")
    2755          156 :             mo_set%eigenvalues(:) = lr_evals(:)
    2756              : 
    2757              :             !get the actual coeff => most common case: closed-shell K-edge, can directly take lr_coeffs
    2758            4 :             IF (nspins == 1 .AND. ndo_mo == 1) THEN
    2759            4 :                CALL cp_fm_to_fm(lr_coeffs, mo_set%mo_coeff)
    2760              :             ELSE
    2761            0 :                DO imo = 1, nmo
    2762              :                   CALL cp_fm_to_fm_submat(msource=lr_coeffs, mtarget=mo_set%mo_coeff, &
    2763              :                                           nrow=nao, ncol=1, s_firstrow=1, &
    2764              :                                           s_firstcol=(imo - 1)*ndo_so + (ispin - 1)*ndo_mo + ido_mo, &
    2765            0 :                                           t_firstrow=1, t_firstcol=imo)
    2766              :                END DO
    2767              :             END IF
    2768              : 
    2769              :             !naming the output
    2770            4 :             domon = domo
    2771            4 :             IF (donor_state%state_type == xas_2p_type) domon = TRIM(domo)//TRIM(ADJUSTL(cp_to_string(ido_mo)))
    2772              :             xas_mittle = 'xasat'//TRIM(ADJUSTL(cp_to_string(donor_state%at_index)))//'_'// &
    2773            4 :                          TRIM(domon)//'_'//TRIM(excite)
    2774              : 
    2775            4 :             IF (do_pdos) THEN
    2776              :                CALL calculate_projected_dos(mo_set, atomic_kind_set, qs_kind_set, particle_set, &
    2777              :                                             qs_env, xas_tdp_section, ispin, xas_mittle, &
    2778            2 :                                             external_matrix_shalf=xas_tdp_env%matrix_shalf)
    2779              :             END IF
    2780              : 
    2781            4 :             IF (do_cubes) THEN
    2782              :                CALL qs_print_cubes(qs_env, mo_set%mo_coeff, ncubes, state_list, centers, &
    2783              :                                    print_key=print_key, root=xas_mittle, ispin=ispin, &
    2784            2 :                                    file_position=pos)
    2785              :             END IF
    2786              : 
    2787              :             !clean-up
    2788            4 :             CALL deallocate_mo_set(mo_set)
    2789            8 :             DEALLOCATE (mo_set)
    2790              : 
    2791              :          END DO
    2792              :       END DO
    2793              : 
    2794              :       !clean-up
    2795            4 :       CALL cp_fm_release(mo_coeff)
    2796            4 :       CALL cp_fm_struct_release(mo_struct)
    2797            4 :       IF (do_cubes) DEALLOCATE (centers, state_list)
    2798              : 
    2799            4 :       CALL timestop(handle)
    2800              : 
    2801           74 :    END SUBROUTINE xas_tdp_post
    2802              : 
    2803              : ! **************************************************************************************************
    2804              : !> \brief Computed the LUMOs for the OT eigensolver guesses
    2805              : !> \param xas_tdp_env ...
    2806              : !> \param xas_tdp_control ...
    2807              : !> \param qs_env ...
    2808              : !> \note Uses stendard diagonalization. Do not use the stendard make_lumo subroutine as it uses
    2809              : !>       the OT eigensolver and there is no guarantee that it will converge fast
    2810              : ! **************************************************************************************************
    2811           20 :    SUBROUTINE make_lumo_guess(xas_tdp_env, xas_tdp_control, qs_env)
    2812              : 
    2813              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    2814              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    2815              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2816              : 
    2817              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'make_lumo_guess'
    2818              : 
    2819              :       INTEGER                                            :: handle, ispin, nao, nelec_spin(2), &
    2820              :                                                             nlumo(2), nocc(2), nspins
    2821              :       LOGICAL                                            :: do_os
    2822           20 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: evals
    2823              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    2824              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct, lumo_struct
    2825              :       TYPE(cp_fm_type)                                   :: amatrix, bmatrix, evecs, work_fm
    2826           20 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s
    2827              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2828              : 
    2829           20 :       NULLIFY (matrix_ks, matrix_s, para_env, blacs_env)
    2830           20 :       NULLIFY (lumo_struct, fm_struct)
    2831              : 
    2832           20 :       CALL timeset(routineN, handle)
    2833              : 
    2834           20 :       do_os = xas_tdp_control%do_uks .OR. xas_tdp_control%do_roks
    2835            2 :       nspins = 1; IF (do_os) nspins = 2
    2836           62 :       ALLOCATE (xas_tdp_env%lumo_evecs(nspins))
    2837           62 :       ALLOCATE (xas_tdp_env%lumo_evals(nspins))
    2838              :       CALL get_qs_env(qs_env, matrix_ks=matrix_ks, matrix_s=matrix_s, nelectron_spin=nelec_spin, &
    2839           20 :                       para_env=para_env, blacs_env=blacs_env)
    2840           20 :       CALL dbcsr_get_info(matrix_s(1)%matrix, nfullrows_total=nao)
    2841              : 
    2842           20 :       IF (do_os) THEN
    2843            6 :          nlumo = nao - nelec_spin
    2844            2 :          nocc = nelec_spin
    2845              :       ELSE
    2846           54 :          nlumo = nao - nelec_spin(1)/2
    2847           54 :          nocc = nelec_spin(1)/2
    2848              :       END IF
    2849              : 
    2850           62 :       ALLOCATE (xas_tdp_env%ot_prec(nspins))
    2851              : 
    2852           42 :       DO ispin = 1, nspins
    2853              : 
    2854              :          !Going through fm to diagonalize
    2855              :          CALL cp_fm_struct_create(fm_struct, para_env=para_env, context=blacs_env, &
    2856           22 :                                   nrow_global=nao, ncol_global=nao)
    2857           22 :          CALL cp_fm_create(amatrix, fm_struct)
    2858           22 :          CALL cp_fm_create(bmatrix, fm_struct)
    2859           22 :          CALL cp_fm_create(evecs, fm_struct)
    2860           22 :          CALL cp_fm_create(work_fm, fm_struct)
    2861           66 :          ALLOCATE (evals(nao))
    2862           66 :          ALLOCATE (xas_tdp_env%lumo_evals(ispin)%array(nlumo(ispin)))
    2863              : 
    2864           22 :          CALL copy_dbcsr_to_fm(matrix_ks(ispin)%matrix, amatrix)
    2865           22 :          CALL copy_dbcsr_to_fm(matrix_s(1)%matrix, bmatrix)
    2866              : 
    2867              :          !The actual diagonalization through Cholesky decomposition
    2868           22 :          CALL cp_fm_geeig(amatrix, bmatrix, evecs, evals, work_fm)
    2869              : 
    2870              :          !Storing results
    2871              :          CALL cp_fm_struct_create(lumo_struct, para_env=para_env, context=blacs_env, &
    2872           22 :                                   nrow_global=nao, ncol_global=nlumo(ispin))
    2873           22 :          CALL cp_fm_create(xas_tdp_env%lumo_evecs(ispin), lumo_struct)
    2874              : 
    2875              :          CALL cp_fm_to_fm_submat(evecs, xas_tdp_env%lumo_evecs(ispin), nrow=nao, &
    2876              :                                  ncol=nlumo(ispin), s_firstrow=1, s_firstcol=nocc(ispin) + 1, &
    2877           22 :                                  t_firstrow=1, t_firstcol=1)
    2878              : 
    2879         1098 :          xas_tdp_env%lumo_evals(ispin)%array(1:nlumo(ispin)) = evals(nocc(ispin) + 1:nao)
    2880              : 
    2881           22 :          CALL build_ot_spin_prec(evecs, evals, ispin, xas_tdp_env, xas_tdp_control, qs_env)
    2882              : 
    2883              :          !clean-up
    2884           22 :          CALL cp_fm_release(amatrix)
    2885           22 :          CALL cp_fm_release(bmatrix)
    2886           22 :          CALL cp_fm_release(evecs)
    2887           22 :          CALL cp_fm_release(work_fm)
    2888           22 :          CALL cp_fm_struct_release(fm_struct)
    2889           22 :          CALL cp_fm_struct_release(lumo_struct)
    2890           64 :          DEALLOCATE (evals)
    2891              :       END DO
    2892              : 
    2893           20 :       CALL timestop(handle)
    2894              : 
    2895           60 :    END SUBROUTINE make_lumo_guess
    2896              : 
    2897              : ! **************************************************************************************************
    2898              : !> \brief Builds a preconditioner for the OT eigensolver, based on some heurstics that prioritize
    2899              : !>        LUMOs with lower eigenvalues
    2900              : !> \param evecs all the ground state eigenvectors
    2901              : !> \param evals all the ground state eigenvalues
    2902              : !> \param ispin ...
    2903              : !> \param xas_tdp_env ...
    2904              : !> \param xas_tdp_control ...
    2905              : !> \param qs_env ...
    2906              : !> \note assumes that the preconditioner matrix array is allocated
    2907              : ! **************************************************************************************************
    2908           22 :    SUBROUTINE build_ot_spin_prec(evecs, evals, ispin, xas_tdp_env, xas_tdp_control, qs_env)
    2909              : 
    2910              :       TYPE(cp_fm_type), INTENT(IN)                       :: evecs
    2911              :       REAL(dp), DIMENSION(:)                             :: evals
    2912              :       INTEGER                                            :: ispin
    2913              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    2914              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    2915              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2916              : 
    2917              :       CHARACTER(len=*), PARAMETER :: routineN = 'build_ot_spin_prec'
    2918              : 
    2919              :       INTEGER                                            :: handle, nao, nelec_spin(2), nguess, &
    2920              :                                                             nocc, nspins
    2921              :       LOGICAL                                            :: do_os
    2922              :       REAL(dp)                                           :: shift
    2923              :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: scaling
    2924              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
    2925              :       TYPE(cp_fm_type)                                   :: fm_prec, work_fm
    2926           22 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
    2927              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2928              : 
    2929           22 :       NULLIFY (fm_struct, para_env, matrix_s)
    2930              : 
    2931           22 :       CALL timeset(routineN, handle)
    2932              : 
    2933           22 :       do_os = xas_tdp_control%do_uks .OR. xas_tdp_control%do_roks
    2934           22 :       CALL get_qs_env(qs_env, para_env=para_env, nelectron_spin=nelec_spin, matrix_s=matrix_s)
    2935           22 :       CALL cp_fm_get_info(evecs, nrow_global=nao, matrix_struct=fm_struct)
    2936           22 :       CALL cp_fm_create(fm_prec, fm_struct)
    2937           66 :       ALLOCATE (scaling(nao))
    2938           22 :       nocc = nelec_spin(1)/2
    2939           22 :       nspins = 1
    2940           22 :       IF (do_os) THEN
    2941            4 :          nocc = nelec_spin(ispin)
    2942            4 :          nspins = 2
    2943              :       END IF
    2944              : 
    2945              :       !rough estimate of the number of required evals
    2946           22 :       nguess = nao - nocc
    2947           22 :       IF (xas_tdp_control%n_excited > 0 .AND. xas_tdp_control%n_excited < nguess) THEN
    2948            4 :          nguess = xas_tdp_control%n_excited/nspins
    2949           18 :       ELSE IF (xas_tdp_control%e_range > 0.0_dp) THEN
    2950          514 :          nguess = COUNT(evals(nocc + 1:nao) - evals(nocc + 1) .LE. xas_tdp_control%e_range)
    2951              :       END IF
    2952              : 
    2953              :       !Give max weight to the first LUMOs
    2954          540 :       scaling(nocc + 1:nocc + nguess) = 100.0_dp
    2955              :       !Then gradually decrease weight
    2956           22 :       shift = evals(nocc + 1) - 0.01_dp
    2957          602 :       scaling(nocc + nguess:nao) = 1.0_dp/(evals(nocc + nguess:nao) - shift)
    2958              :       !HOMOs do not matter, but need well behaved matrix
    2959          616 :       scaling(1:nocc) = 1.0_dp
    2960              : 
    2961              :       !Building the precond as an fm
    2962           22 :       CALL cp_fm_create(work_fm, fm_struct)
    2963              : 
    2964           22 :       CALL cp_fm_copy_general(evecs, work_fm, para_env)
    2965           22 :       CALL cp_fm_column_scale(work_fm, scaling)
    2966              : 
    2967           22 :       CALL parallel_gemm('N', 'T', nao, nao, nao, 1.0_dp, work_fm, evecs, 0.0_dp, fm_prec)
    2968              : 
    2969              :       !Copy into dbcsr format
    2970           22 :       ALLOCATE (xas_tdp_env%ot_prec(ispin)%matrix)
    2971           22 :       CALL dbcsr_create(xas_tdp_env%ot_prec(ispin)%matrix, template=matrix_s(1)%matrix, name="OT_PREC")
    2972           22 :       CALL copy_fm_to_dbcsr(fm_prec, xas_tdp_env%ot_prec(ispin)%matrix)
    2973           22 :       CALL dbcsr_filter(xas_tdp_env%ot_prec(ispin)%matrix, xas_tdp_control%eps_filter)
    2974              : 
    2975           22 :       CALL cp_fm_release(work_fm)
    2976           22 :       CALL cp_fm_release(fm_prec)
    2977              : 
    2978           22 :       CALL timestop(handle)
    2979              : 
    2980           88 :    END SUBROUTINE build_ot_spin_prec
    2981              : 
    2982              : ! **************************************************************************************************
    2983              : !> \brief Prints GW2X corrected ionization potentials to main output file, including SOC splitting
    2984              : !> \param donor_state ...
    2985              : !> \param xas_tdp_env ...
    2986              : !> \param xas_tdp_control ...
    2987              : !> \param qs_env ...
    2988              : ! **************************************************************************************************
    2989           30 :    SUBROUTINE print_xps(donor_state, xas_tdp_env, xas_tdp_control, qs_env)
    2990              : 
    2991              :       TYPE(donor_state_type), POINTER                    :: donor_state
    2992              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    2993              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    2994              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2995              : 
    2996              :       INTEGER                                            :: ido_mo, ispin, nspins, output_unit
    2997           30 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: IPs, soc_shifts
    2998              : 
    2999           30 :       output_unit = cp_logger_get_default_io_unit()
    3000              : 
    3001           30 :       nspins = 1; IF (xas_tdp_control%do_uks .OR. xas_tdp_control%do_roks) nspins = 2
    3002              : 
    3003          120 :       ALLOCATE (IPs(SIZE(donor_state%gw2x_evals, 1), SIZE(donor_state%gw2x_evals, 2)))
    3004          106 :       IPs(:, :) = donor_state%gw2x_evals(:, :)
    3005              : 
    3006              :       !IPs in PBCs cannot be trusted because of a lack of a potential reference
    3007           30 :       IF (.NOT. xas_tdp_control%is_periodic) THEN
    3008              : 
    3009              :          !Apply SOC splitting
    3010           26 :          IF (donor_state%ndo_mo > 1) THEN
    3011              :             CALL get_soc_splitting(soc_shifts, donor_state, xas_tdp_env, xas_tdp_control, qs_env)
    3012           20 :             IPs(:, :) = IPs(:, :) + soc_shifts
    3013              : 
    3014            4 :             IF (output_unit > 0) THEN
    3015              :                WRITE (output_unit, FMT="(/,T5,A,F23.6)") &
    3016            2 :                   "Ionization potentials for XPS (GW2X + SOC): ", -IPs(1, 1)*evolt
    3017              : 
    3018            4 :                DO ispin = 1, nspins
    3019           10 :                   DO ido_mo = 1, donor_state%ndo_mo
    3020              : 
    3021            6 :                      IF (ispin == 1 .AND. ido_mo == 1) CYCLE
    3022              : 
    3023              :                      WRITE (output_unit, FMT="(T5,A,F23.6)") &
    3024            8 :                         "                                            ", -IPs(ido_mo, ispin)*evolt
    3025              : 
    3026              :                   END DO
    3027              :                END DO
    3028              :             END IF
    3029              : 
    3030              :          ELSE
    3031              : 
    3032              :             ! No SOC, only 1 donor MO per spin
    3033           22 :             IF (output_unit > 0) THEN
    3034              :                WRITE (output_unit, FMT="(/,T5,A,F29.6)") &
    3035           11 :                   "Ionization potentials for XPS (GW2X): ", -IPs(1, 1)*evolt
    3036              : 
    3037           11 :                IF (nspins == 2) THEN
    3038              :                   WRITE (output_unit, FMT="(T5,A,F29.6)") &
    3039            2 :                      "                                      ", -IPs(1, 2)*evolt
    3040              :                END IF
    3041              :             END IF
    3042              : 
    3043              :          END IF
    3044              :       END IF
    3045              : 
    3046           30 :    END SUBROUTINE print_xps
    3047              : 
    3048              : ! **************************************************************************************************
    3049              : !> \brief Prints the excitation energies and the oscillator strengths for a given donor_state in a file
    3050              : !> \param donor_state the donor_state to print
    3051              : !> \param xas_tdp_env ...
    3052              : !> \param xas_tdp_control ...
    3053              : !> \param xas_tdp_section ...
    3054              : ! **************************************************************************************************
    3055           68 :    SUBROUTINE print_xas_tdp_to_file(donor_state, xas_tdp_env, xas_tdp_control, xas_tdp_section)
    3056              : 
    3057              :       TYPE(donor_state_type), POINTER                    :: donor_state
    3058              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    3059              :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    3060              :       TYPE(section_vals_type), POINTER                   :: xas_tdp_section
    3061              : 
    3062              :       INTEGER                                            :: i, output_unit, xas_tdp_unit
    3063              :       TYPE(cp_logger_type), POINTER                      :: logger
    3064              : 
    3065           68 :       NULLIFY (logger)
    3066           68 :       logger => cp_get_default_logger()
    3067              : 
    3068              :       xas_tdp_unit = cp_print_key_unit_nr(logger, xas_tdp_section, "PRINT%SPECTRUM", &
    3069              :                                           extension=".spectrum", file_position="APPEND", &
    3070           68 :                                           file_action="WRITE", file_form="FORMATTED")
    3071              : 
    3072           68 :       output_unit = cp_logger_get_default_io_unit()
    3073              : 
    3074           68 :       IF (output_unit > 0) THEN
    3075              :          WRITE (output_unit, FMT="(/,T5,A,/)") &
    3076           34 :             "Calculations done: "
    3077              :       END IF
    3078              : 
    3079           68 :       IF (xas_tdp_control%do_spin_cons) THEN
    3080            8 :          IF (xas_tdp_unit > 0) THEN
    3081              : 
    3082              : !           Printing the general donor state information
    3083              :             WRITE (xas_tdp_unit, FMT="(A,/,A,A,A/,A,I5,A,I5,A,A,/,A)") &
    3084            4 :                "==================================================================================", &
    3085            4 :                "XAS TDP open-shell spin-conserving (no SOC) excitations for DONOR STATE: ", &
    3086            4 :                xas_tdp_env%state_type_char(donor_state%state_type), ",", &
    3087            4 :                "from EXCITED ATOM: ", donor_state%at_index, ", of KIND (index/symbol): ", &
    3088            4 :                donor_state%kind_index, "/", TRIM(donor_state%at_symbol), &
    3089            8 :                "=================================================================================="
    3090              : 
    3091              : !           Simply dump the excitation energies/ oscillator strength as they come
    3092              : 
    3093            4 :             IF (xas_tdp_control%do_quad) THEN
    3094              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3095            0 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)   fosc quadrupole (a.u.)"
    3096            0 :                DO i = 1, SIZE(donor_state%sc_evals)
    3097              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F25.6)") &
    3098            0 :                      i, donor_state%sc_evals(i)*evolt, donor_state%osc_str(i, 4), &
    3099            0 :                      donor_state%quad_osc_str(i)
    3100              :                END DO
    3101            4 :             ELSE IF (xas_tdp_control%xyz_dip) THEN
    3102              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3103            0 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)   x-component   y-component   z-component"
    3104            0 :                DO i = 1, SIZE(donor_state%sc_evals)
    3105              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F14.6,F14.6,F14.6)") &
    3106            0 :                      i, donor_state%sc_evals(i)*evolt, donor_state%osc_str(i, 4), &
    3107            0 :                      donor_state%osc_str(i, 1), donor_state%osc_str(i, 2), donor_state%osc_str(i, 3)
    3108              :                END DO
    3109            4 :             ELSE IF (xas_tdp_control%spin_dip) THEN
    3110              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3111            0 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)    alpha-comp     beta-comp"
    3112            0 :                DO i = 1, SIZE(donor_state%sc_evals)
    3113              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F14.6,F14.6)") &
    3114            0 :                      i, donor_state%sc_evals(i)*evolt, donor_state%osc_str(i, 4), &
    3115            0 :                      donor_state%alpha_osc(i, 4), donor_state%beta_osc(i, 4)
    3116              :                END DO
    3117              :             ELSE
    3118              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3119            4 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)"
    3120          108 :                DO i = 1, SIZE(donor_state%sc_evals)
    3121              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6)") &
    3122          108 :                      i, donor_state%sc_evals(i)*evolt, donor_state%osc_str(i, 4)
    3123              :                END DO
    3124              :             END IF
    3125              : 
    3126            4 :             WRITE (xas_tdp_unit, FMT="(A,/)") " "
    3127              :          END IF !xas_tdp_unit > 0
    3128              : 
    3129            8 :          IF (output_unit > 0) THEN
    3130              :             WRITE (output_unit, FMT="(T5,A,F17.6)") &
    3131            4 :                "First spin-conserving XAS excitation energy (eV): ", donor_state%sc_evals(1)*evolt
    3132              :          END IF
    3133              : 
    3134              :       END IF ! do_spin_cons
    3135              : 
    3136           68 :       IF (xas_tdp_control%do_spin_flip) THEN
    3137            2 :          IF (xas_tdp_unit > 0) THEN
    3138              : 
    3139              : !           Printing the general donor state information
    3140              :             WRITE (xas_tdp_unit, FMT="(A,/,A,A,A/,A,I5,A,I5,A,A,/,A)") &
    3141            1 :                "==================================================================================", &
    3142            1 :                "XAS TDP open-shell spin-flip (no SOC) excitations for DONOR STATE: ", &
    3143            1 :                xas_tdp_env%state_type_char(donor_state%state_type), ",", &
    3144            1 :                "from EXCITED ATOM: ", donor_state%at_index, ", of KIND (index/symbol): ", &
    3145            1 :                donor_state%kind_index, "/", TRIM(donor_state%at_symbol), &
    3146            2 :                "=================================================================================="
    3147              : 
    3148              : !           Simply dump the excitation energies/ oscillator strength as they come
    3149              : 
    3150            1 :             IF (xas_tdp_control%do_quad) THEN
    3151              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3152            0 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)   fosc quadrupole (a.u.)"
    3153            0 :                DO i = 1, SIZE(donor_state%sf_evals)
    3154              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F25.6)") &
    3155            0 :                      i, donor_state%sf_evals(i)*evolt, 0.0_dp, 0.0_dp !spin-forbidden !
    3156              :                END DO
    3157            1 :             ELSE IF (xas_tdp_control%xyz_dip) THEN
    3158              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3159            0 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)   x-component   y-component   z-component"
    3160            0 :                DO i = 1, SIZE(donor_state%sf_evals)
    3161              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F14.6,F14.6,F14.6)") &
    3162            0 :                      i, donor_state%sf_evals(i)*evolt, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp
    3163              :                END DO
    3164            1 :             ELSE IF (xas_tdp_control%spin_dip) THEN
    3165              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3166            0 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)    alpha-comp     beta-comp"
    3167            0 :                DO i = 1, SIZE(donor_state%sf_evals)
    3168              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F14.6,F14.6)") &
    3169            0 :                      i, donor_state%sf_evals(i)*evolt, 0.0_dp, 0.0_dp, 0.0_dp
    3170              :                END DO
    3171              :             ELSE
    3172              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3173            1 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)"
    3174           13 :                DO i = 1, SIZE(donor_state%sf_evals)
    3175              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6)") &
    3176           13 :                      i, donor_state%sf_evals(i)*evolt, 0.0_dp
    3177              :                END DO
    3178              :             END IF
    3179              : 
    3180            1 :             WRITE (xas_tdp_unit, FMT="(A,/)") " "
    3181              :          END IF !xas_tdp_unit
    3182              : 
    3183            2 :          IF (output_unit > 0) THEN
    3184              :             WRITE (output_unit, FMT="(T5,A,F23.6)") &
    3185            1 :                "First spin-flip XAS excitation energy (eV): ", donor_state%sf_evals(1)*evolt
    3186              :          END IF
    3187              :       END IF ! do_spin_flip
    3188              : 
    3189           68 :       IF (xas_tdp_control%do_singlet) THEN
    3190           60 :          IF (xas_tdp_unit > 0) THEN
    3191              : 
    3192              : !           Printing the general donor state information
    3193              :             WRITE (xas_tdp_unit, FMT="(A,/,A,A,A/,A,I5,A,I5,A,A,/,A)") &
    3194           30 :                "==================================================================================", &
    3195           30 :                "XAS TDP singlet excitations (no SOC) for DONOR STATE: ", &
    3196           30 :                xas_tdp_env%state_type_char(donor_state%state_type), ",", &
    3197           30 :                "from EXCITED ATOM: ", donor_state%at_index, ", of KIND (index/symbol): ", &
    3198           30 :                donor_state%kind_index, "/", TRIM(donor_state%at_symbol), &
    3199           60 :                "=================================================================================="
    3200              : 
    3201              : !           Simply dump the excitation energies/ oscillator strength as they come
    3202              : 
    3203           30 :             IF (xas_tdp_control%do_quad) THEN
    3204              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3205            0 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)   fosc quadrupole (a.u.)"
    3206            0 :                DO i = 1, SIZE(donor_state%sg_evals)
    3207              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F25.6)") &
    3208            0 :                      i, donor_state%sg_evals(i)*evolt, donor_state%osc_str(i, 4), &
    3209            0 :                      donor_state%quad_osc_str(i)
    3210              :                END DO
    3211           30 :             ELSE IF (xas_tdp_control%xyz_dip) THEN
    3212              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3213            0 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)   x-component   y-component   z-component"
    3214            0 :                DO i = 1, SIZE(donor_state%sg_evals)
    3215              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F14.6,F14.6,F14.6)") &
    3216            0 :                      i, donor_state%sg_evals(i)*evolt, donor_state%osc_str(i, 4), &
    3217            0 :                      donor_state%osc_str(i, 1), donor_state%osc_str(i, 2), donor_state%osc_str(i, 3)
    3218              :                END DO
    3219              :             ELSE
    3220              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3221           30 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)"
    3222          438 :                DO i = 1, SIZE(donor_state%sg_evals)
    3223              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6)") &
    3224          438 :                      i, donor_state%sg_evals(i)*evolt, donor_state%osc_str(i, 4)
    3225              :                END DO
    3226              :             END IF
    3227              : 
    3228           30 :             WRITE (xas_tdp_unit, FMT="(A,/)") " "
    3229              :          END IF !xas_tdp_unit
    3230              : 
    3231           60 :          IF (output_unit > 0) THEN
    3232              :             WRITE (output_unit, FMT="(T5,A,F25.6)") &
    3233           30 :                "First singlet XAS excitation energy (eV): ", donor_state%sg_evals(1)*evolt
    3234              :          END IF
    3235              :       END IF ! do_singlet
    3236              : 
    3237           68 :       IF (xas_tdp_control%do_triplet) THEN
    3238            2 :          IF (xas_tdp_unit > 0) THEN
    3239              : 
    3240              : !           Printing the general donor state information
    3241              :             WRITE (xas_tdp_unit, FMT="(A,/,A,A,A/,A,I5,A,I5,A,A,/,A)") &
    3242            1 :                "==================================================================================", &
    3243            1 :                "XAS TDP triplet excitations (no SOC) for DONOR STATE: ", &
    3244            1 :                xas_tdp_env%state_type_char(donor_state%state_type), ",", &
    3245            1 :                "from EXCITED ATOM: ", donor_state%at_index, ", of KIND (index/symbol): ", &
    3246            1 :                donor_state%kind_index, "/", TRIM(donor_state%at_symbol), &
    3247            2 :                "=================================================================================="
    3248              : 
    3249              : !           Simply dump the excitation energies/ oscillator strength as they come
    3250              : 
    3251            1 :             IF (xas_tdp_control%do_quad) THEN
    3252              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3253            0 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)   fosc quadrupole (a.u.)"
    3254            0 :                DO i = 1, SIZE(donor_state%tp_evals)
    3255              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F25.6)") &
    3256            0 :                      i, donor_state%tp_evals(i)*evolt, 0.0_dp, 0.0_dp !spin-forbidden !
    3257              :                END DO
    3258            1 :             ELSE IF (xas_tdp_control%xyz_dip) THEN
    3259              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3260            0 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)   x-component   y-component   z-component"
    3261            0 :                DO i = 1, SIZE(donor_state%tp_evals)
    3262              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F14.6,F14.6,F14.6)") &
    3263            0 :                      i, donor_state%tp_evals(i)*evolt, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp
    3264              :                END DO
    3265            1 :             ELSE IF (xas_tdp_control%spin_dip) THEN
    3266              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3267            0 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)    alpha-comp     beta-comp"
    3268            0 :                DO i = 1, SIZE(donor_state%tp_evals)
    3269              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F14.6,F14.6)") &
    3270            0 :                      i, donor_state%tp_evals(i)*evolt, 0.0_dp, 0.0_dp, 0.0_dp
    3271              :                END DO
    3272              :             ELSE
    3273              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3274            1 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)"
    3275           13 :                DO i = 1, SIZE(donor_state%tp_evals)
    3276              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6)") &
    3277           13 :                      i, donor_state%tp_evals(i)*evolt, 0.0_dp
    3278              :                END DO
    3279              :             END IF
    3280              : 
    3281            1 :             WRITE (xas_tdp_unit, FMT="(A,/)") " "
    3282              :          END IF !xas_tdp_unit
    3283              : 
    3284            2 :          IF (output_unit > 0) THEN
    3285              :             WRITE (output_unit, FMT="(T5,A,F25.6)") &
    3286            1 :                "First triplet XAS excitation energy (eV): ", donor_state%tp_evals(1)*evolt
    3287              :          END IF
    3288              :       END IF ! do_triplet
    3289              : 
    3290           68 :       IF (xas_tdp_control%do_soc .AND. donor_state%state_type == xas_2p_type) THEN
    3291            4 :          IF (xas_tdp_unit > 0) THEN
    3292              : 
    3293              : !           Printing the general donor state information
    3294              :             WRITE (xas_tdp_unit, FMT="(A,/,A,A,A/,A,I5,A,I5,A,A,/,A)") &
    3295            2 :                "==================================================================================", &
    3296            2 :                "XAS TDP  excitations after spin-orbit coupling for DONOR STATE: ", &
    3297            2 :                xas_tdp_env%state_type_char(donor_state%state_type), ",", &
    3298            2 :                "from EXCITED ATOM: ", donor_state%at_index, ", of KIND (index/symbol): ", &
    3299            2 :                donor_state%kind_index, "/", TRIM(donor_state%at_symbol), &
    3300            4 :                "=================================================================================="
    3301              : 
    3302              : !           Simply dump the excitation energies/ oscillator strength as they come
    3303            2 :             IF (xas_tdp_control%do_quad) THEN
    3304              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3305            0 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)   fosc quadrupole (a.u.)"
    3306            0 :                DO i = 1, SIZE(donor_state%soc_evals)
    3307              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F25.6)") &
    3308            0 :                      i, donor_state%soc_evals(i)*evolt, donor_state%soc_osc_str(i, 4), &
    3309            0 :                      donor_state%soc_quad_osc_str(i)
    3310              :                END DO
    3311            2 :             ELSE IF (xas_tdp_control%xyz_dip) THEN
    3312              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3313            0 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)   x-component   y-component   z-component"
    3314            0 :                DO i = 1, SIZE(donor_state%soc_evals)
    3315              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F14.6,F14.6,F14.6)") &
    3316            0 :                      i, donor_state%soc_evals(i)*evolt, donor_state%soc_osc_str(i, 4), &
    3317            0 :                      donor_state%soc_osc_str(i, 1), donor_state%soc_osc_str(i, 2), donor_state%soc_osc_str(i, 3)
    3318              :                END DO
    3319              :             ELSE
    3320              :                WRITE (xas_tdp_unit, FMT="(T3,A)") &
    3321            2 :                   " Index     Excitation energy (eV)    fosc dipole (a.u.)"
    3322           74 :                DO i = 1, SIZE(donor_state%soc_evals)
    3323              :                   WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6)") &
    3324           74 :                      i, donor_state%soc_evals(i)*evolt, donor_state%soc_osc_str(i, 4)
    3325              :                END DO
    3326              :             END IF
    3327              : 
    3328            2 :             WRITE (xas_tdp_unit, FMT="(A,/)") " "
    3329              :          END IF !xas_tdp_unit
    3330              : 
    3331            4 :          IF (output_unit > 0) THEN
    3332              :             WRITE (output_unit, FMT="(T5,A,F29.6)") &
    3333            2 :                "First SOC XAS excitation energy (eV): ", donor_state%soc_evals(1)*evolt
    3334              :          END IF
    3335              :       END IF !do_soc
    3336              : 
    3337           68 :       CALL cp_print_key_finished_output(xas_tdp_unit, logger, xas_tdp_section, "PRINT%SPECTRUM")
    3338              : 
    3339           68 :    END SUBROUTINE print_xas_tdp_to_file
    3340              : 
    3341              : ! **************************************************************************************************
    3342              : !> \brief Prints the donor_state and excitation_type info into a RESTART file for cheap PDOS and/or
    3343              : !>        CUBE printing without expensive computation
    3344              : !> \param ex_type singlet, triplet, etc.
    3345              : !> \param donor_state ...
    3346              : !> \param xas_tdp_section ...
    3347              : !> \param qs_env ...
    3348              : ! **************************************************************************************************
    3349           76 :    SUBROUTINE write_donor_state_restart(ex_type, donor_state, xas_tdp_section, qs_env)
    3350              : 
    3351              :       INTEGER, INTENT(IN)                                :: ex_type
    3352              :       TYPE(donor_state_type), POINTER                    :: donor_state
    3353              :       TYPE(section_vals_type), POINTER                   :: xas_tdp_section
    3354              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    3355              : 
    3356              :       CHARACTER(len=*), PARAMETER :: routineN = 'write_donor_state_restart'
    3357              : 
    3358              :       CHARACTER(len=default_path_length)                 :: filename
    3359              :       CHARACTER(len=default_string_length)               :: domo, excite, my_middle
    3360              :       INTEGER                                            :: ex_atom, handle, ispin, nao, ndo_mo, &
    3361              :                                                             nex, nspins, output_unit, rst_unit, &
    3362              :                                                             state_type
    3363           72 :       INTEGER, DIMENSION(:, :), POINTER                  :: mo_indices
    3364              :       LOGICAL                                            :: do_print
    3365           72 :       REAL(dp), DIMENSION(:), POINTER                    :: lr_evals
    3366              :       TYPE(cp_fm_type), POINTER                          :: lr_coeffs
    3367              :       TYPE(cp_logger_type), POINTER                      :: logger
    3368           72 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
    3369              :       TYPE(section_vals_type), POINTER                   :: print_key
    3370              : 
    3371           72 :       NULLIFY (logger, lr_coeffs, lr_evals, print_key, mos)
    3372              : 
    3373              :       !Initialization
    3374          144 :       logger => cp_get_default_logger()
    3375           72 :       do_print = .FALSE.
    3376           72 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, xas_tdp_section, &
    3377              :                                            "PRINT%RESTART", used_print_key=print_key), cp_p_file)) do_print = .TRUE.
    3378              : 
    3379           70 :       IF (.NOT. do_print) RETURN
    3380              : 
    3381            2 :       CALL timeset(routineN, handle)
    3382              : 
    3383            2 :       output_unit = cp_logger_get_default_io_unit()
    3384              : 
    3385              :       !Get general info
    3386            2 :       SELECT CASE (ex_type)
    3387              :       CASE (tddfpt_spin_cons)
    3388            0 :          lr_evals => donor_state%sc_evals
    3389            0 :          lr_coeffs => donor_state%sc_coeffs
    3390            0 :          excite = "spincons"
    3391            0 :          nspins = 2
    3392              :       CASE (tddfpt_spin_flip)
    3393            0 :          lr_evals => donor_state%sf_evals
    3394            0 :          lr_coeffs => donor_state%sf_coeffs
    3395            0 :          excite = "spinflip"
    3396            0 :          nspins = 2
    3397              :       CASE (tddfpt_singlet)
    3398            2 :          lr_evals => donor_state%sg_evals
    3399            2 :          lr_coeffs => donor_state%sg_coeffs
    3400            2 :          excite = "singlet"
    3401            2 :          nspins = 1
    3402              :       CASE (tddfpt_triplet)
    3403            0 :          lr_evals => donor_state%tp_evals
    3404            0 :          lr_coeffs => donor_state%tp_coeffs
    3405            0 :          excite = "triplet"
    3406            2 :          nspins = 1
    3407              :       END SELECT
    3408              : 
    3409            4 :       SELECT CASE (donor_state%state_type)
    3410              :       CASE (xas_1s_type)
    3411            2 :          domo = "1s"
    3412              :       CASE (xas_2s_type)
    3413            0 :          domo = "2s"
    3414              :       CASE (xas_2p_type)
    3415            2 :          domo = "2p"
    3416              :       END SELECT
    3417              : 
    3418            2 :       ndo_mo = donor_state%ndo_mo
    3419            2 :       nex = SIZE(lr_evals)
    3420            2 :       CALL cp_fm_get_info(lr_coeffs, nrow_global=nao)
    3421            2 :       state_type = donor_state%state_type
    3422            2 :       ex_atom = donor_state%at_index
    3423            2 :       mo_indices => donor_state%mo_indices
    3424              : 
    3425              :       !Opening restart file
    3426            2 :       rst_unit = -1
    3427            2 :       my_middle = 'xasat'//TRIM(ADJUSTL(cp_to_string(ex_atom)))//'_'//TRIM(domo)//'_'//TRIM(excite)
    3428              :       rst_unit = cp_print_key_unit_nr(logger, xas_tdp_section, "PRINT%RESTART", extension=".rst", &
    3429              :                                       file_status="REPLACE", file_action="WRITE", &
    3430            2 :                                       file_form="UNFORMATTED", middle_name=TRIM(my_middle))
    3431              : 
    3432              :       filename = cp_print_key_generate_filename(logger, print_key, middle_name=TRIM(my_middle), &
    3433            2 :                                                 extension=".rst", my_local=.FALSE.)
    3434              : 
    3435            2 :       IF (output_unit > 0) THEN
    3436              :          WRITE (UNIT=output_unit, FMT="(/,T5,A,/T5,A,A,A)") &
    3437            1 :             "Linear-response orbitals and excitation energies are written in: ", &
    3438            2 :             '"', TRIM(filename), '"'
    3439              :       END IF
    3440              : 
    3441              :       !Writing
    3442            2 :       IF (rst_unit > 0) THEN
    3443            1 :          WRITE (rst_unit) ex_atom, state_type, ndo_mo, ex_type
    3444            1 :          WRITE (rst_unit) nao, nex, nspins
    3445            1 :          WRITE (rst_unit) mo_indices(:, :)
    3446            1 :          WRITE (rst_unit) lr_evals(:)
    3447              :       END IF
    3448            2 :       CALL cp_fm_write_unformatted(lr_coeffs, rst_unit)
    3449              : 
    3450              :       !The MOs as well (because the may have been localized)
    3451            2 :       CALL get_qs_env(qs_env, mos=mos)
    3452            4 :       DO ispin = 1, nspins
    3453            4 :          CALL cp_fm_write_unformatted(mos(ispin)%mo_coeff, rst_unit)
    3454              :       END DO
    3455              : 
    3456              :       !closing
    3457            2 :       CALL cp_print_key_finished_output(rst_unit, logger, xas_tdp_section, "PRINT%RESTART")
    3458              : 
    3459            2 :       CALL timestop(handle)
    3460              : 
    3461           72 :    END SUBROUTINE write_donor_state_restart
    3462              : 
    3463              : ! **************************************************************************************************
    3464              : !> \brief Reads donor_state info from a restart file
    3465              : !> \param donor_state the pre-allocated donor_state
    3466              : !> \param ex_type the excitations stored in this specific file
    3467              : !> \param filename the restart file to read from
    3468              : !> \param qs_env ...
    3469              : ! **************************************************************************************************
    3470            2 :    SUBROUTINE read_donor_state_restart(donor_state, ex_type, filename, qs_env)
    3471              : 
    3472              :       TYPE(donor_state_type), POINTER                    :: donor_state
    3473              :       INTEGER, INTENT(OUT)                               :: ex_type
    3474              :       CHARACTER(len=*), INTENT(IN)                       :: filename
    3475              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    3476              : 
    3477              :       CHARACTER(len=*), PARAMETER :: routineN = 'read_donor_state_restart'
    3478              : 
    3479              :       INTEGER                                            :: handle, ispin, nao, nex, nspins, &
    3480              :                                                             output_unit, read_params(7), rst_unit
    3481            2 :       INTEGER, DIMENSION(:, :), POINTER                  :: mo_indices
    3482              :       LOGICAL                                            :: file_exists
    3483            2 :       REAL(dp), DIMENSION(:), POINTER                    :: lr_evals
    3484              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    3485              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
    3486              :       TYPE(cp_fm_type), POINTER                          :: lr_coeffs
    3487            2 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
    3488              :       TYPE(mp_comm_type)                                 :: group
    3489              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    3490              : 
    3491            2 :       NULLIFY (lr_evals, lr_coeffs, para_env, fm_struct, blacs_env, mos)
    3492              : 
    3493            2 :       CALL timeset(routineN, handle)
    3494              : 
    3495            2 :       output_unit = cp_logger_get_default_io_unit()
    3496            2 :       CPASSERT(ASSOCIATED(donor_state))
    3497            2 :       CALL get_qs_env(qs_env, para_env=para_env, blacs_env=blacs_env)
    3498            2 :       group = para_env
    3499              : 
    3500            2 :       file_exists = .FALSE.
    3501            2 :       rst_unit = -1
    3502              : 
    3503            2 :       IF (para_env%is_source()) THEN
    3504              : 
    3505            1 :          INQUIRE (FILE=filename, EXIST=file_exists)
    3506            1 :          IF (.NOT. file_exists) CPABORT("Trying to read non-existing XAS_TDP restart file")
    3507              : 
    3508              :          CALL open_file(file_name=TRIM(filename), file_action="READ", file_form="UNFORMATTED", &
    3509            1 :                         file_position="REWIND", file_status="OLD", unit_number=rst_unit)
    3510              :       END IF
    3511              : 
    3512            2 :       IF (output_unit > 0) THEN
    3513              :          WRITE (UNIT=output_unit, FMT="(/,T5,A,/,T5,A,A,A)") &
    3514            1 :             "Reading linear-response orbitals and excitation energies from file: ", &
    3515            2 :             '"', filename, '"'
    3516              :       END IF
    3517              : 
    3518              :       !read general params
    3519            2 :       IF (rst_unit > 0) THEN
    3520            1 :          READ (rst_unit) read_params(1:4)
    3521            1 :          READ (rst_unit) read_params(5:7)
    3522              :       END IF
    3523            2 :       CALL group%bcast(read_params)
    3524            2 :       donor_state%at_index = read_params(1)
    3525            2 :       donor_state%state_type = read_params(2)
    3526            2 :       donor_state%ndo_mo = read_params(3)
    3527            2 :       ex_type = read_params(4)
    3528            2 :       nao = read_params(5)
    3529            2 :       nex = read_params(6)
    3530            2 :       nspins = read_params(7)
    3531              : 
    3532            8 :       ALLOCATE (mo_indices(donor_state%ndo_mo, nspins))
    3533            2 :       IF (rst_unit > 0) THEN
    3534            1 :          READ (rst_unit) mo_indices(1:donor_state%ndo_mo, 1:nspins)
    3535              :       END IF
    3536           10 :       CALL group%bcast(mo_indices)
    3537            2 :       donor_state%mo_indices => mo_indices
    3538              : 
    3539              :       !read evals
    3540            6 :       ALLOCATE (lr_evals(nex))
    3541            2 :       IF (rst_unit > 0) READ (rst_unit) lr_evals(1:nex)
    3542           78 :       CALL group%bcast(lr_evals)
    3543              : 
    3544              :       !read evecs
    3545              :       CALL cp_fm_struct_create(fm_struct, context=blacs_env, para_env=para_env, &
    3546            2 :                                nrow_global=nao, ncol_global=nex*donor_state%ndo_mo*nspins)
    3547            2 :       ALLOCATE (lr_coeffs)
    3548            2 :       CALL cp_fm_create(lr_coeffs, fm_struct)
    3549            2 :       CALL cp_fm_read_unformatted(lr_coeffs, rst_unit)
    3550            2 :       CALL cp_fm_struct_release(fm_struct)
    3551              : 
    3552              :       !read MO coeffs and replace in qs_env
    3553            2 :       CALL get_qs_env(qs_env, mos=mos)
    3554            4 :       DO ispin = 1, nspins
    3555            4 :          CALL cp_fm_read_unformatted(mos(ispin)%mo_coeff, rst_unit)
    3556              :       END DO
    3557              : 
    3558              :       !closing file
    3559            2 :       IF (para_env%is_source()) THEN
    3560            1 :          CALL close_file(unit_number=rst_unit)
    3561              :       END IF
    3562              : 
    3563              :       !case study on excitation type
    3564            2 :       SELECT CASE (ex_type)
    3565              :       CASE (tddfpt_spin_cons)
    3566            0 :          donor_state%sc_evals => lr_evals
    3567            0 :          donor_state%sc_coeffs => lr_coeffs
    3568              :       CASE (tddfpt_spin_flip)
    3569            0 :          donor_state%sf_evals => lr_evals
    3570            0 :          donor_state%sf_coeffs => lr_coeffs
    3571              :       CASE (tddfpt_singlet)
    3572            2 :          donor_state%sg_evals => lr_evals
    3573            2 :          donor_state%sg_coeffs => lr_coeffs
    3574              :       CASE (tddfpt_triplet)
    3575            0 :          donor_state%tp_evals => lr_evals
    3576            2 :          donor_state%tp_coeffs => lr_coeffs
    3577              :       END SELECT
    3578              : 
    3579            2 :       CALL timestop(handle)
    3580              : 
    3581            4 :    END SUBROUTINE read_donor_state_restart
    3582              : 
    3583              : ! **************************************************************************************************
    3584              : !> \brief Checks whether this is a restart calculation and runs it if so
    3585              : !> \param rst_filename the file to read for restart
    3586              : !> \param xas_tdp_section ...
    3587              : !> \param qs_env ...
    3588              : ! **************************************************************************************************
    3589            4 :    SUBROUTINE restart_calculation(rst_filename, xas_tdp_section, qs_env)
    3590              : 
    3591              :       CHARACTER(len=*), INTENT(IN)                       :: rst_filename
    3592              :       TYPE(section_vals_type), POINTER                   :: xas_tdp_section
    3593              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    3594              : 
    3595              :       INTEGER                                            :: ex_type
    3596              :       TYPE(donor_state_type), POINTER                    :: donor_state
    3597              :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
    3598              : 
    3599            2 :       NULLIFY (xas_tdp_env, donor_state)
    3600              : 
    3601              :       !create a donor_state that we fill with the information we read
    3602            2 :       ALLOCATE (donor_state)
    3603            2 :       CALL donor_state_create(donor_state)
    3604            2 :       CALL read_donor_state_restart(donor_state, ex_type, rst_filename, qs_env)
    3605              : 
    3606              :       !create a dummy xas_tdp_env and compute the post XAS_TDP stuff
    3607            2 :       CALL xas_tdp_env_create(xas_tdp_env)
    3608            2 :       CALL xas_tdp_post(ex_type, donor_state, xas_tdp_env, xas_tdp_section, qs_env)
    3609              : 
    3610              :       !clean-up
    3611            2 :       CALL xas_tdp_env_release(xas_tdp_env)
    3612            2 :       CALL free_ds_memory(donor_state)
    3613            2 :       DEALLOCATE (donor_state%mo_indices)
    3614            2 :       DEALLOCATE (donor_state)
    3615              : 
    3616            2 :    END SUBROUTINE restart_calculation
    3617              : 
    3618              : END MODULE xas_tdp_methods
        

Generated by: LCOV version 2.0-1