LCOV - code coverage report
Current view: top level - src - rixs_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:51fc4cd) Lines: 99.1 % 234 232
Test Date: 2026-02-04 06:28:27 Functions: 100.0 % 4 4

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Methods for Resonant Inelastic XRAY Scattering (RIXS) calculations
      10              : !> \author BSG (02.2025)
      11              : ! **************************************************************************************************
      12              : MODULE rixs_methods
      13              :    USE bibliography,                    ONLY: VazdaCruz2021,&
      14              :                                               cite_reference
      15              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      16              :    USE cp_control_types,                ONLY: dft_control_type,&
      17              :                                               rixs_control_create,&
      18              :                                               rixs_control_release,&
      19              :                                               rixs_control_type
      20              :    USE cp_control_utils,                ONLY: read_rixs_control
      21              :    USE cp_dbcsr_api,                    ONLY: dbcsr_p_type,&
      22              :                                               dbcsr_type
      23              :    USE cp_dbcsr_operations,             ONLY: cp_dbcsr_sm_fm_multiply
      24              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      25              :                                               cp_fm_struct_release,&
      26              :                                               cp_fm_struct_type
      27              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      28              :                                               cp_fm_get_info,&
      29              :                                               cp_fm_get_submatrix,&
      30              :                                               cp_fm_release,&
      31              :                                               cp_fm_to_fm,&
      32              :                                               cp_fm_to_fm_submat,&
      33              :                                               cp_fm_type
      34              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      35              :                                               cp_logger_get_default_io_unit,&
      36              :                                               cp_logger_type
      37              :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      38              :                                               cp_print_key_unit_nr
      39              :    USE header,                          ONLY: rixs_header
      40              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      41              :                                               section_vals_type
      42              :    USE kinds,                           ONLY: dp
      43              :    USE message_passing,                 ONLY: mp_para_env_type
      44              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      45              :    USE physcon,                         ONLY: evolt
      46              :    USE qs_environment_types,            ONLY: get_qs_env,&
      47              :                                               qs_environment_type
      48              :    USE qs_tddfpt2_methods,              ONLY: tddfpt
      49              :    USE rixs_types,                      ONLY: rixs_env_create,&
      50              :                                               rixs_env_release,&
      51              :                                               rixs_env_type,&
      52              :                                               tddfpt2_valence_type
      53              :    USE xas_tdp_methods,                 ONLY: xas_tdp
      54              :    USE xas_tdp_types,                   ONLY: donor_state_type,&
      55              :                                               xas_tdp_env_type
      56              : #include "./base/base_uses.f90"
      57              : 
      58              :    IMPLICIT NONE
      59              :    PRIVATE
      60              : 
      61              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'rixs_methods'
      62              : 
      63              :    PUBLIC :: rixs, rixs_core
      64              : 
      65              : CONTAINS
      66              : 
      67              : ! **************************************************************************************************
      68              : !> \brief Driver for RIXS calculations.
      69              : !> \param qs_env the inherited qs_environment
      70              : !> \author BSG
      71              : ! **************************************************************************************************
      72              : 
      73           14 :    SUBROUTINE rixs(qs_env)
      74              : 
      75              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      76              : 
      77              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'rixs'
      78              : 
      79              :       INTEGER                                            :: handle, output_unit
      80              :       TYPE(dft_control_type), POINTER                    :: dft_control
      81              :       TYPE(section_vals_type), POINTER                   :: rixs_section, tddfp2_section, &
      82              :                                                             xas_tdp_section
      83              : 
      84           14 :       CALL timeset(routineN, handle)
      85              : 
      86           14 :       NULLIFY (rixs_section)
      87           14 :       rixs_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%RIXS")
      88           14 :       output_unit = cp_logger_get_default_io_unit()
      89              : 
      90           14 :       qs_env%do_rixs = .TRUE.
      91              : 
      92           14 :       CALL cite_reference(VazdaCruz2021)
      93              : 
      94           14 :       CALL get_qs_env(qs_env, dft_control=dft_control)
      95              : 
      96           14 :       xas_tdp_section => section_vals_get_subs_vals(rixs_section, "XAS_TDP")
      97           14 :       tddfp2_section => section_vals_get_subs_vals(rixs_section, "TDDFPT")
      98              : 
      99           14 :       CALL rixs_core(rixs_section, qs_env)
     100              : 
     101           14 :       IF (output_unit > 0) THEN
     102              :          WRITE (UNIT=output_unit, FMT="(/,(T2,A79))") &
     103            7 :             "*******************************************************************************", &
     104            7 :             "!    Normal termination of Resonant Inelastic X-RAY Scattering calculation    !", &
     105           14 :             "*******************************************************************************"
     106              :       END IF
     107              : 
     108           14 :       CALL timestop(handle)
     109              : 
     110           14 :    END SUBROUTINE rixs
     111              : 
     112              : ! **************************************************************************************************
     113              : !> \brief Perform RIXS calculation.
     114              : !> \param rixs_section ...
     115              : !> \param qs_env ...
     116              : ! **************************************************************************************************
     117           14 :    SUBROUTINE rixs_core(rixs_section, qs_env)
     118              : 
     119              :       TYPE(section_vals_type), POINTER                   :: rixs_section
     120              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     121              : 
     122              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'rixs_core'
     123              : 
     124              :       INTEGER :: ax, c_nstates, current_state_index, fstate, handle, iatom, ispin, istate, &
     125              :          nactive_max, nao, ncol, nex_atoms, nocc, nspins, output_unit, td_state, v_nstates
     126           14 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: nactive
     127              :       LOGICAL                                            :: do_sc, do_sg, roks, uks
     128           14 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: w_i0, w_if
     129           14 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: dip_block, mu_i0
     130           14 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: mu_if
     131              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     132              :       TYPE(cp_fm_struct_type), POINTER :: core_evect_struct, cRc_struct, dip_0_struct, &
     133              :          dip_f_struct, gs_coeff_struct, i_dip_0_struct, i_dip_f_struct, Rc_struct
     134              :       TYPE(cp_fm_type)                                   :: dip_0
     135           14 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: core_evects, cRc, dip_f, i_dip_0, &
     136           14 :                                                             i_dip_f, Rc, state_gs_coeffs
     137           14 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: local_gs_coeffs, mo_coeffs
     138           14 :       TYPE(cp_fm_type), DIMENSION(:, :), POINTER         :: valence_evects
     139              :       TYPE(cp_fm_type), POINTER                          :: target_ex_coeffs
     140           14 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: dipmat, matrix_s
     141              :       TYPE(dft_control_type), POINTER                    :: dft_control
     142              :       TYPE(donor_state_type), POINTER                    :: current_state
     143              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     144              :       TYPE(rixs_control_type), POINTER                   :: rixs_control
     145              :       TYPE(rixs_env_type), POINTER                       :: rixs_env
     146              :       TYPE(tddfpt2_valence_type), POINTER                :: valence_state
     147              :       TYPE(xas_tdp_env_type), POINTER                    :: core_state
     148              : 
     149           14 :       NULLIFY (rixs_control, dft_control, rixs_env)
     150           14 :       NULLIFY (valence_state, core_state)
     151           14 :       NULLIFY (para_env, blacs_env)
     152           14 :       NULLIFY (local_gs_coeffs, mo_coeffs, valence_evects)
     153           14 :       NULLIFY (dipmat, dip_0_struct, i_dip_0_struct, dip_f_struct, i_dip_f_struct, &
     154           14 :                core_evect_struct, gs_coeff_struct)
     155              : 
     156           28 :       output_unit = cp_logger_get_default_io_unit()
     157              : 
     158              :       CALL get_qs_env(qs_env, &
     159              :                       dft_control=dft_control, &
     160              :                       matrix_s=matrix_s, &
     161              :                       para_env=para_env, &
     162           14 :                       blacs_env=blacs_env)
     163           14 :       CALL rixs_control_create(rixs_control)
     164           14 :       CALL read_rixs_control(rixs_control, rixs_section, dft_control%qs_control)
     165              : 
     166              :       ! create rixs_env
     167           14 :       CALL rixs_env_create(rixs_env)
     168              : 
     169              :       ! first, xas_tdp calculation
     170           14 :       CALL xas_tdp(qs_env, rixs_env)
     171              : 
     172           14 :       do_sg = rixs_control%xas_tdp_control%do_singlet
     173           14 :       do_sc = rixs_control%xas_tdp_control%do_spin_cons
     174              : 
     175           14 :       IF (rixs_control%xas_tdp_control%check_only) THEN
     176            0 :          CPWARN("CHECK_ONLY run for XAS_TDP requested, RIXS and TDDFPT will not be performed.")
     177              :       ELSE
     178              : 
     179              :          ! then, tddfpt calculation
     180           14 :          CALL tddfpt(qs_env, calc_forces=.FALSE., rixs_env=rixs_env)
     181              : 
     182           14 :          IF (output_unit > 0) THEN
     183            7 :             CALL rixs_header(output_unit)
     184              :          END IF
     185              : 
     186              :          ! timings for rixs only, excluding xas_tdp and tddft calls
     187           14 :          CALL timeset(routineN, handle)
     188              : 
     189           14 :          IF (do_sg) THEN ! singlet
     190              :             nspins = 1
     191            4 :          ELSE IF (do_sc) THEN ! spin-conserving
     192              :             nspins = 2
     193              :          ELSE
     194            0 :             CPABORT("RIXS only implemented for singlet and spin-conserving excitations")
     195              :          END IF
     196              : 
     197           14 :          IF (output_unit > 0) THEN
     198            7 :             IF (dft_control%uks) THEN
     199            1 :                uks = .TRUE.
     200            1 :                WRITE (UNIT=output_unit, FMT="(T2,A)") "RIXS| Unrestricted Open-Shell Kohn-Sham"
     201            6 :             ELSE IF (dft_control%roks) THEN
     202            1 :                roks = .TRUE.
     203            1 :                WRITE (UNIT=output_unit, FMT="(T2,A)") "RIXS| Restricted Open-Shell Kohn-Sham"
     204              :             END IF
     205              :          END IF
     206              : 
     207           14 :          core_state => rixs_env%core_state
     208           14 :          valence_state => rixs_env%valence_state
     209              : 
     210              :          ! gs coefficients from tddfpt
     211           14 :          mo_coeffs => valence_state%mos_active
     212              :          ! localised gs coefficients from xas_tdp
     213           14 :          local_gs_coeffs => core_state%mo_coeff
     214           14 :          valence_evects => valence_state%evects
     215              : 
     216              :          ! res tddft
     217              :          IF (.NOT. roks) THEN
     218              :             CALL cp_fm_get_info(matrix=local_gs_coeffs(1), ncol_global=nocc)
     219              :             CALL cp_fm_get_info(matrix=mo_coeffs(1), ncol_global=ncol)
     220              :             IF (ncol /= nocc) THEN
     221              :                CPABORT("RIXS with restricted space excitations NYI")
     222              :             END IF
     223              :          END IF
     224              : 
     225           14 :          IF (rixs_control%xas_tdp_control%do_loc) THEN
     226            2 :             IF (output_unit > 0) THEN
     227              :                WRITE (UNIT=output_unit, FMT="(T2,A)") &
     228            1 :                   "RIXS| Found localised XAS_TDP orbitals"
     229              :                WRITE (UNIT=output_unit, FMT="(T2,A)") &
     230            1 :                   "RIXS| Rotating TDDFPT vectors..."
     231              :             END IF
     232            2 :             CALL rotate_vectors(valence_state%evects, local_gs_coeffs, mo_coeffs, matrix_s(1)%matrix, output_unit)
     233              :          END IF
     234              : 
     235              :          ! find max nactive for open-shell cases
     236           28 :          ALLOCATE (nactive(nspins))
     237           32 :          DO ispin = 1, nspins
     238           32 :             CALL cp_fm_get_info(matrix=mo_coeffs(ispin), nrow_global=nao, ncol_global=nactive(ispin))
     239              :          END DO
     240           32 :          nactive_max = MAXVAL(nactive)
     241              : 
     242           14 :          nex_atoms = core_state%nex_atoms
     243           14 :          v_nstates = valence_state%nstates
     244           14 :          c_nstates = core_state%nstates
     245              : 
     246           14 :          IF (rixs_control%core_states > 0) THEN
     247            4 :             rixs_control%core_states = MIN(rixs_control%core_states, c_nstates)
     248              :          ELSE
     249           10 :             rixs_control%core_states = c_nstates
     250              :          END IF
     251           14 :          c_nstates = rixs_control%core_states
     252              : 
     253           14 :          IF (rixs_control%valence_states > 0) THEN
     254            2 :             rixs_control%valence_states = MIN(rixs_control%valence_states, v_nstates)
     255              :          ELSE
     256           12 :             rixs_control%valence_states = v_nstates
     257              :          END IF
     258           14 :          v_nstates = rixs_control%valence_states
     259              : 
     260           14 :          IF (output_unit > 0) THEN
     261              :             WRITE (UNIT=output_unit, FMT="(T2,A,I5,A,I5)") &
     262            7 :                "RIXS| Using ", c_nstates, " core states out of ", core_state%nstates
     263              :             WRITE (UNIT=output_unit, FMT="(T2,A,I5,A,I5,/)") &
     264            7 :                "RIXS| Using ", v_nstates, " valence states out of ", valence_state%nstates
     265              :          END IF
     266              : 
     267           14 :          dipmat => core_state%dipmat
     268              : 
     269           78 :          ALLOCATE (core_evects(nspins), state_gs_coeffs(nspins))
     270          154 :          ALLOCATE (dip_block(1, nspins), mu_i0(4, c_nstates), mu_if(4, c_nstates, v_nstates), w_i0(c_nstates), w_if(v_nstates))
     271           60 :          w_if(:) = valence_state%evals(1:v_nstates)*evolt
     272           46 :          ALLOCATE (i_dip_0(nspins))
     273           78 :          ALLOCATE (dip_f(nspins), i_dip_f(nspins))
     274           78 :          ALLOCATE (Rc(nspins), cRc(nspins))
     275              : 
     276              :          CALL cp_fm_struct_create(core_evect_struct, para_env=para_env, context=blacs_env, &
     277           14 :                                   nrow_global=nao, ncol_global=c_nstates)
     278              :          CALL cp_fm_struct_create(gs_coeff_struct, para_env=para_env, context=blacs_env, &
     279           14 :                                   nrow_global=nao, ncol_global=1)
     280              : 
     281              :          ! looping over ex_atoms and ex_kinds is enough as excited atoms have to be unique
     282           14 :          current_state_index = 1
     283           30 :          DO iatom = 1, nex_atoms
     284           16 :             current_state => core_state%donor_states(current_state_index)
     285           16 :             IF (output_unit > 0) THEN
     286              :                WRITE (UNIT=output_unit, FMT="(T2,A,A,A,I3,A,A)") &
     287            8 :                   "RIXS| Calculating dipole moment from core-excited state ", &
     288            8 :                   core_state%state_type_char(current_state%state_type), " for atom ", &
     289           16 :                   current_state%at_index, " of kind ", TRIM(current_state%at_symbol)
     290              :             END IF
     291              : 
     292          846 :             mu_i0 = 0.0_dp
     293         2786 :             mu_if = 0.0_dp
     294              : 
     295           16 :             IF (do_sg) THEN ! singlet
     296           12 :                target_ex_coeffs => current_state%sg_coeffs
     297          130 :                w_i0(:) = current_state%sg_evals(1:c_nstates)*evolt
     298            4 :             ELSE IF (do_sc) THEN ! spin-conserving
     299            4 :                target_ex_coeffs => current_state%sc_coeffs
     300           52 :                w_i0(:) = current_state%sc_evals(1:c_nstates)*evolt
     301              :             END IF
     302              : 
     303              :             ! reshape sc and sg coeffs (separate spins to columns)
     304           36 :             DO ispin = 1, nspins
     305           20 :                CALL cp_fm_create(core_evects(ispin), core_evect_struct)
     306              :                CALL cp_fm_to_fm_submat(msource=target_ex_coeffs, mtarget=core_evects(ispin), s_firstrow=1, &
     307           36 :                                        s_firstcol=(c_nstates*(ispin - 1) + 1), t_firstrow=1, t_firstcol=1, nrow=nao, ncol=c_nstates)
     308              :             END DO
     309           36 :             DO ispin = 1, nspins
     310           20 :                CALL cp_fm_create(state_gs_coeffs(ispin), gs_coeff_struct)
     311           16 :                IF (roks) THEN
     312              :                   ! store same coeffs for both spins, easier later on
     313              :                   CALL cp_fm_to_fm_submat(msource=current_state%gs_coeffs, mtarget=state_gs_coeffs(ispin), s_firstrow=1, &
     314           20 :                                           s_firstcol=1, t_firstrow=1, t_firstcol=1, nrow=nao, ncol=1)
     315              :                ELSE
     316              :                   CALL cp_fm_to_fm_submat(msource=current_state%gs_coeffs, mtarget=state_gs_coeffs(ispin), s_firstrow=1, &
     317              :                                           s_firstcol=ispin, t_firstrow=1, t_firstcol=1, nrow=nao, ncol=1)
     318              :                END IF
     319              :             END DO
     320              : 
     321              :             ! initialise matrices for i->0
     322              :             CALL cp_fm_struct_create(dip_0_struct, para_env=para_env, context=blacs_env, &
     323           16 :                                      nrow_global=nao, ncol_global=1)
     324           16 :             CALL cp_fm_create(dip_0, dip_0_struct)
     325              :             CALL cp_fm_struct_create(i_dip_0_struct, para_env=para_env, context=blacs_env, &
     326           16 :                                      nrow_global=c_nstates, ncol_global=1)
     327           36 :             DO ispin = 1, nspins
     328           36 :                CALL cp_fm_create(i_dip_0(ispin), i_dip_0_struct)
     329              :             END DO
     330              : 
     331              :             ! initialise matrices for i->f
     332           36 :             DO ispin = 1, nspins
     333              :                CALL cp_fm_struct_create(dip_f_struct, para_env=para_env, context=blacs_env, &
     334           20 :                                         nrow_global=nao, ncol_global=nactive(ispin))
     335              :                CALL cp_fm_struct_create(i_dip_f_struct, para_env=para_env, context=blacs_env, &
     336           20 :                                         nrow_global=c_nstates, ncol_global=nactive(ispin))
     337           20 :                CALL cp_fm_create(dip_f(ispin), dip_f_struct)
     338           20 :                CALL cp_fm_create(i_dip_f(ispin), i_dip_f_struct)
     339           20 :                CALL cp_fm_struct_release(i_dip_f_struct)
     340           36 :                CALL cp_fm_struct_release(dip_f_struct)
     341              :             END DO
     342              : 
     343              :             ! initialise cRc
     344           36 :             DO ispin = 1, nspins
     345              :                CALL cp_fm_struct_create(Rc_struct, para_env=para_env, context=blacs_env, &
     346           20 :                                         nrow_global=nao, ncol_global=nactive(ispin))
     347              :                CALL cp_fm_struct_create(cRc_struct, para_env=para_env, context=blacs_env, &
     348           20 :                                         nrow_global=nactive(ispin), ncol_global=nactive(ispin))
     349           20 :                CALL cp_fm_create(Rc(ispin), Rc_struct)
     350           20 :                CALL cp_fm_create(cRc(ispin), cRc_struct)
     351           20 :                CALL cp_fm_struct_release(cRc_struct)
     352           36 :                CALL cp_fm_struct_release(Rc_struct)
     353              :             END DO
     354              : 
     355              :             ! 0 -> i
     356           64 :             DO ax = 1, 3
     357              : 
     358              :                ! i*R*0
     359          108 :                DO ispin = 1, nspins
     360           60 :                   CALL cp_dbcsr_sm_fm_multiply(dipmat(ax)%matrix, state_gs_coeffs(ispin), dip_0, ncol=1)
     361          108 :                   CALL parallel_gemm('T', 'N', c_nstates, 1, nao, 1.0_dp, core_evects(ispin), dip_0, 0.0_dp, i_dip_0(ispin))
     362              :                END DO
     363              : 
     364          562 :                DO istate = 1, c_nstates
     365         1782 :                   dip_block = 0.0_dp
     366         1140 :                   DO ispin = 1, nspins
     367              :                      CALL cp_fm_get_submatrix(fm=i_dip_0(ispin), target_m=dip_block, start_row=istate, &
     368          642 :                                               start_col=1, n_rows=1, n_cols=1)
     369         1140 :                      mu_i0(ax, istate) = mu_i0(ax, istate) + dip_block(1, 1)
     370              :                   END DO ! ispin
     371          546 :                   mu_i0(4, istate) = mu_i0(4, istate) + mu_i0(ax, istate)**2
     372              :                END DO ! istate
     373              : 
     374              :             END DO ! ax
     375              : 
     376              :             ! i -> f
     377           66 :             DO td_state = 1, v_nstates
     378              : 
     379           50 :                IF (output_unit > 0) THEN
     380              :                   WRITE (UNIT=output_unit, FMT="(T9,A,I3,A,F10.4)") &
     381           25 :                      "to valence-excited state ", td_state, " with energy ", w_if(td_state)
     382              :                END IF
     383              : 
     384          216 :                DO ax = 1, 3
     385              : 
     386          360 :                   DO ispin = 1, nspins
     387              : 
     388              :                      ! 1) build c^T*R*c
     389          210 :                      CALL cp_dbcsr_sm_fm_multiply(dipmat(ax)%matrix, mo_coeffs(ispin), Rc(ispin), ncol=nactive(ispin))
     390              :                      CALL parallel_gemm('T', 'N', nactive(ispin), nactive(ispin), nao, 1.0_dp, mo_coeffs(ispin), &
     391          210 :                                         Rc(ispin), 0.0_dp, cRc(ispin))
     392              : 
     393              :                      ! 2) build dip_f (X*dip = X*c^T*R*c)
     394              :                      CALL parallel_gemm('N', 'N', nao, nactive(ispin), nactive(ispin), 1.0_dp, valence_evects(ispin, td_state), &
     395          210 :                                         cRc(ispin), 0.0_dp, dip_f(ispin))
     396              : 
     397              :                      ! 3) build i_dip_f (Y*dip_f = Y^T*X*c^T*R*c)
     398              :                      CALL parallel_gemm('T', 'N', c_nstates, nactive(ispin), nao, 1.0_dp, core_evects(ispin), &
     399          360 :                                         dip_f(ispin), 0.0_dp, i_dip_f(ispin))
     400              : 
     401              :                   END DO
     402              : 
     403         1832 :                   DO istate = 1, c_nstates
     404         9696 :                      DO fstate = 1, nactive_max
     405        31392 :                         dip_block = 0.0_dp
     406        21360 :                         DO ispin = 1, nspins
     407        19728 :                            IF (fstate <= nactive(ispin)) THEN
     408              :                               CALL cp_fm_get_submatrix(fm=i_dip_f(ispin), target_m=dip_block, start_row=istate, &
     409        10944 :                                                        start_col=fstate, n_rows=1, n_cols=1)
     410        10944 :                               mu_if(ax, istate, td_state) = mu_if(ax, istate, td_state) + dip_block(1, 1)
     411              :                            END IF
     412              :                         END DO ! ispin
     413              :                      END DO ! fstate (tddft)
     414         1782 :                      mu_if(4, istate, td_state) = mu_if(4, istate, td_state) + mu_if(ax, istate, td_state)**2
     415              :                   END DO ! istate (core)
     416              : 
     417              :                END DO ! ax
     418              : 
     419              :             END DO ! td_state
     420              : 
     421           16 :             IF (output_unit > 0) THEN
     422            8 :                WRITE (UNIT=output_unit, FMT="(/,T2,A,/)") "RIXS| Printing spectrum to file"
     423              :             END IF
     424           16 :             CALL print_rixs_to_file(current_state, mu_i0, mu_if, w_i0, w_if, rixs_env, rixs_section, rixs_control)
     425              : 
     426           16 :             current_state_index = current_state_index + 1
     427              : 
     428              :             ! cleanup
     429           36 :             DO ispin = 1, nspins
     430           20 :                CALL cp_fm_release(core_evects(ispin))
     431           20 :                CALL cp_fm_release(state_gs_coeffs(ispin))
     432           20 :                CALL cp_fm_release(i_dip_0(ispin))
     433           20 :                CALL cp_fm_release(i_dip_f(ispin))
     434           20 :                CALL cp_fm_release(dip_f(ispin))
     435           20 :                CALL cp_fm_release(Rc(ispin))
     436           36 :                CALL cp_fm_release(cRc(ispin))
     437              :             END DO
     438           16 :             CALL cp_fm_struct_release(i_dip_0_struct)
     439           16 :             CALL cp_fm_struct_release(dip_0_struct)
     440           46 :             CALL cp_fm_release(dip_0)
     441              : 
     442              :          END DO ! iatom
     443              : 
     444              :          NULLIFY (current_state)
     445              : 
     446              :          ! cleanup
     447           14 :          CALL cp_fm_struct_release(core_evect_struct)
     448           28 :          CALL cp_fm_struct_release(gs_coeff_struct)
     449              : 
     450              :       END IF
     451              : 
     452              :       ! more cleanup
     453           14 :       CALL rixs_control_release(rixs_control)
     454           14 :       CALL rixs_env_release(rixs_env)
     455           14 :       NULLIFY (valence_state, core_state)
     456              : 
     457           14 :       CALL timestop(handle)
     458              : 
     459           28 :    END SUBROUTINE rixs_core
     460              : 
     461              : ! **************************************************************************************************
     462              : !> \brief Rotate vectors. Returns rotated mo_occ and evects.
     463              : !> \param evects ...
     464              : !> \param mo_ref ...
     465              : !> \param mo_occ ...
     466              : !> \param overlap_matrix ...
     467              : !> \param unit_nr ...
     468              : ! **************************************************************************************************
     469              : 
     470            2 :    SUBROUTINE rotate_vectors(evects, mo_ref, mo_occ, overlap_matrix, unit_nr)
     471              :       TYPE(cp_fm_type), DIMENSION(:, :)                  :: evects
     472              :       TYPE(cp_fm_type), DIMENSION(:)                     :: mo_ref, mo_occ
     473              :       TYPE(dbcsr_type), POINTER                          :: overlap_matrix
     474              :       INTEGER                                            :: unit_nr
     475              : 
     476              :       INTEGER                                            :: ispin, istate, ncol, nrow, nspins, &
     477              :                                                             nstates
     478              :       REAL(kind=dp)                                      :: diff
     479              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     480              :       TYPE(cp_fm_struct_type), POINTER                   :: emat_struct
     481              :       TYPE(cp_fm_type)                                   :: emat, rotated_mo_coeffs, smo
     482              :       TYPE(cp_fm_type), POINTER                          :: current_evect
     483              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     484              : 
     485            2 :       NULLIFY (emat_struct, para_env, blacs_env, current_evect)
     486              : 
     487            2 :       nspins = SIZE(evects, DIM=1)
     488            4 :       DO ispin = 1, nspins
     489              : 
     490              :          CALL cp_fm_get_info(matrix=mo_occ(ispin), nrow_global=nrow, ncol_global=ncol, &
     491            2 :                              para_env=para_env, context=blacs_env)
     492            2 :          CALL cp_fm_create(smo, mo_occ(ispin)%matrix_struct)
     493              : 
     494              :          ! rotate mo_occ
     495              :          ! smo = matrix_s x mo_occ
     496            2 :          CALL cp_dbcsr_sm_fm_multiply(overlap_matrix, mo_occ(ispin), smo, ncol, alpha=1.0_dp, beta=0.0_dp)
     497              :          CALL cp_fm_struct_create(emat_struct, nrow_global=ncol, ncol_global=ncol, &
     498            2 :                                   para_env=para_env, context=blacs_env)
     499            2 :          CALL cp_fm_create(emat, emat_struct)
     500              :          ! emat = mo_ref^T x smo
     501            2 :          CALL parallel_gemm('T', 'N', ncol, ncol, nrow, 1.0_dp, mo_ref(ispin), smo, 0.0_dp, emat)
     502            2 :          CALL cp_fm_create(rotated_mo_coeffs, mo_occ(ispin)%matrix_struct)
     503              :          ! rotated_mo_coeffs = cpmos x emat
     504            2 :          CALL parallel_gemm('N', 'N', nrow, ncol, ncol, 1.0_dp, mo_occ(ispin), emat, 0.0_dp, rotated_mo_coeffs)
     505              : 
     506           77 :          diff = MAXVAL(ABS(rotated_mo_coeffs%local_data - mo_occ(ispin)%local_data))
     507            2 :          IF (unit_nr > 0) THEN
     508            1 :             WRITE (unit_nr, FMT="(T9,A,I2,A,F10.6,/)") "For spin ", ispin, ": Max difference between orbitals = ", diff
     509              :          END IF
     510              : 
     511            2 :          CALL cp_fm_to_fm(rotated_mo_coeffs, mo_occ(ispin))
     512              : 
     513            2 :          nstates = SIZE(evects, DIM=2)
     514            8 :          DO istate = 1, nstates
     515            2 :             ASSOCIATE (current_evect => evects(ispin, istate))
     516            6 :                CALL parallel_gemm('N', 'N', nrow, ncol, ncol, 1.0_dp, current_evect, emat, 0.0_dp, smo)
     517            6 :                CALL cp_fm_to_fm(smo, current_evect)
     518              :             END ASSOCIATE
     519              :          END DO
     520              : 
     521            2 :          CALL cp_fm_struct_release(emat_struct)
     522            2 :          CALL cp_fm_release(smo)
     523            2 :          CALL cp_fm_release(emat)
     524           10 :          CALL cp_fm_release(rotated_mo_coeffs)
     525              : 
     526              :       END DO ! ispin
     527              : 
     528            2 :    END SUBROUTINE rotate_vectors
     529              : 
     530              : !**************************************************************************************************
     531              : !> \brief Print RIXS spectrum.
     532              : !> \param donor_state ...
     533              : !> \param mu_i0 ...
     534              : !> \param mu_if ...
     535              : !> \param w_i0 ...
     536              : !> \param w_if ...
     537              : !> \param rixs_env ...
     538              : !> \param rixs_section ...
     539              : !> \param rixs_control ...
     540              : ! **************************************************************************************************
     541           16 :    SUBROUTINE print_rixs_to_file(donor_state, mu_i0, mu_if, w_i0, w_if, &
     542              :                                  rixs_env, rixs_section, rixs_control)
     543              : 
     544              :       TYPE(donor_state_type), POINTER                    :: donor_state
     545              :       REAL(dp), DIMENSION(:, :)                          :: mu_i0
     546              :       REAL(dp), DIMENSION(:, :, :)                       :: mu_if
     547              :       REAL(dp), DIMENSION(:)                             :: w_i0, w_if
     548              :       TYPE(rixs_env_type), POINTER                       :: rixs_env
     549              :       TYPE(section_vals_type), POINTER                   :: rixs_section
     550              :       TYPE(rixs_control_type), POINTER                   :: rixs_control
     551              : 
     552              :       INTEGER                                            :: f, i, output_unit, rixs_unit
     553              :       TYPE(cp_logger_type), POINTER                      :: logger
     554              : 
     555           16 :       NULLIFY (logger)
     556           16 :       logger => cp_get_default_logger()
     557              : 
     558              :       rixs_unit = cp_print_key_unit_nr(logger, rixs_section, "PRINT%SPECTRUM", &
     559              :                                        extension=".rixs", file_position="APPEND", &
     560           16 :                                        file_action="WRITE", file_form="FORMATTED")
     561              : 
     562           16 :       output_unit = cp_logger_get_default_io_unit()
     563              : 
     564           16 :       IF (rixs_unit > 0) THEN
     565              : 
     566              :          WRITE (rixs_unit, FMT="(A,/,T2,A,A,A,I3,A,A,A/,A)") &
     567            8 :             "=====================================================================================", &
     568            8 :             "Excitation from ground-state (", &
     569            8 :             rixs_env%core_state%state_type_char(donor_state%state_type), " for atom ", &
     570            8 :             donor_state%at_index, " of kind ", TRIM(donor_state%at_symbol), &
     571            8 :             ") to core-excited state i ", &
     572           16 :             "====================================================================================="
     573              : 
     574              :          WRITE (rixs_unit, FMT="(T3,A)") &
     575            8 :             "w_0i (eV)            mu^x_0i (a.u.)  mu^y_0i (a.u.)  mu^z_0i (a.u.)  mu^2_0i (a.u.)"
     576           91 :          DO i = 1, rixs_control%core_states
     577              :             WRITE (rixs_unit, FMT="(T2,F10.4,T26,E12.5,T42,E12.5,T58,E12.5,T74,E12.5)") &
     578           91 :                w_i0(i), mu_i0(1, i), mu_i0(2, i), mu_i0(3, i), mu_i0(4, i)
     579              :          END DO
     580              : 
     581              :          WRITE (rixs_unit, FMT="(A,/,T2,A,/,A)") &
     582            8 :             "=====================================================================================", &
     583            8 :             "Emission from core-excited state i to valence-excited state f ", &
     584           16 :             "====================================================================================="
     585              : 
     586              :          WRITE (rixs_unit, FMT="(T3,A)") &
     587            8 :             "w_0i (eV) w_if (eV)  mu^x_if (a.u.)  mu^y_if (a.u.)  mu^z_if (a.u.)  mu^2_if (a.u.)"
     588              : 
     589           91 :          DO i = 1, rixs_control%core_states
     590          363 :             DO f = 1, rixs_control%valence_states
     591              :                WRITE (rixs_unit, FMT="(T2,F10.4,T14,F8.4,T26,E12.5,T42,E12.5,T58,E12.5,T74,E12.5)") &
     592          355 :                   w_i0(i), w_if(f), mu_if(1, i, f), mu_if(2, i, f), mu_if(3, i, f), mu_if(4, i, f)
     593              :             END DO
     594              :          END DO
     595              : 
     596              :       END IF
     597              : 
     598           16 :       CALL cp_print_key_finished_output(rixs_unit, logger, rixs_section, "PRINT%SPECTRUM")
     599              : 
     600           16 :    END SUBROUTINE print_rixs_to_file
     601              : 
     602              : END MODULE rixs_methods
        

Generated by: LCOV version 2.0-1