LCOV - code coverage report
Current view: top level - src/nonlinear_optics - nlo_T1_T2_band_transition.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:123285f) Lines: 97.8 % 90 88
Test Date: 2026-11-04 00:58:17 Functions: 66.7 % 6 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 Smooth band transition between population and coherence relaxation times.
      10              : ! **************************************************************************************************
      11              : MODULE nlo_T1_T2_band_transition
      12              :    USE ieee_arithmetic,                 ONLY: ieee_is_finite
      13              :    USE kinds,                           ONLY: dp
      14              :    USE mathconstants,                   ONLY: gaussi,&
      15              :                                               pi
      16              :    USE nlo_derivatives,                 ONLY: derivatives_index,&
      17              :                                               nlo_derivative_count,&
      18              :                                               nlo_derivative_indices,&
      19              :                                               nlo_n_derivatives
      20              : #include "../base/base_uses.f90"
      21              : 
      22              :    IMPLICIT NONE
      23              : 
      24              :    PRIVATE
      25              : 
      26              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'nlo_T1_T2_band_transition'
      27              : 
      28              :    PUBLIC :: nlo_band_transition_type, nlo_band_transition_prepare, &
      29              :              nlo_band_transition_correction, &
      30              :              nlo_band_transition_rate
      31              : 
      32              :    TYPE :: nlo_band_transition_type
      33              :       REAL(dp), ALLOCATABLE     :: energies(:), pair_rate(:, :)
      34              :       REAL(dp)                  :: width = 0.0_dp, rate_difference = 0.0_dp
      35              :       COMPLEX(dp), ALLOCATABLE  :: integration_points(:), integration_weights(:)
      36              :    END TYPE nlo_band_transition_type
      37              : 
      38              : CONTAINS
      39              : 
      40              : ! **************************************************************************************************
      41              : !> \brief Prepare Γ_H(X)=γ₂X+(γ₁−γ₂)exp[−(ad_H/w)²]X, ad_H(X)=[H,X].
      42              : !> \param energies Band energies in Hartree
      43              : !> \param width Energy scale of the smooth transition in Hartree
      44              : !> \param rate1 Population damping energy in Hartree
      45              : !> \param rate2 Coherence damping energy in Hartree
      46              : !> \param relaxation Prepared band transition state
      47              : !> \note Central rates use EXP exactly. Positive grades use Cauchy's formula
      48              : !>       on two horizontal contours and Gauss-Hermite integration. The contour
      49              : !>       shifts and factors are generated from the Hermite Jacobi matrix; no
      50              : !>       fitted or tabulated coefficients enter the relaxation model.
      51              : !>       Taylor derivatives follow analytically from the resolvent equation.
      52              : !>       Contour points share one workspace; lower grades are reconstructed
      53              : !>       once per requested grade from the already solved physical density.
      54              : ! **************************************************************************************************
      55            5 :    SUBROUTINE nlo_band_transition_prepare(energies, width, rate1, rate2, relaxation)
      56              :       REAL(dp), INTENT(IN)                               :: energies(:), width, rate1, rate2
      57              :       TYPE(nlo_band_transition_type), INTENT(INOUT)      :: relaxation
      58              : 
      59              :       INTEGER                                            :: iband, jband, nband
      60              :       REAL(dp)                                           :: difference, gaussian
      61              : 
      62              :       IF (.NOT. ALL(ieee_is_finite(energies)) .OR. .NOT. ieee_is_finite(width) .OR. &
      63              :           .NOT. ieee_is_finite(rate1) .OR. .NOT. ieee_is_finite(rate2) .OR. &
      64          135 :           width <= 0.0_dp .OR. rate1 <= 0.0_dp .OR. rate2 < rate1) THEN
      65            0 :          CPABORT('Invalid NLO band-transition relaxation parameters.')
      66              :       END IF
      67            5 :       IF (ALLOCATED(relaxation%pair_rate)) DEALLOCATE (relaxation%pair_rate)
      68            5 :       IF (ALLOCATED(relaxation%energies)) DEALLOCATE (relaxation%energies)
      69           15 :       ALLOCATE (relaxation%energies(SIZE(energies)))
      70          135 :       relaxation%energies(:) = energies
      71            5 :       relaxation%width = width
      72            5 :       relaxation%rate_difference = rate1 - rate2
      73            5 :       CALL nlo_gaussian_quadrature(relaxation%integration_points, relaxation%integration_weights)
      74            5 :       nband = SIZE(energies)
      75            5 :       CPASSERT(nband >= 2)
      76           20 :       ALLOCATE (relaxation%pair_rate(nband, nband))
      77          135 :       DO jband = 1, nband
      78         3515 :          DO iband = 1, nband
      79         3380 :             difference = energies(iband) - energies(jband)
      80         3380 :             gaussian = 0.0_dp
      81         3380 :             IF (width >= ABS(difference)/26.0_dp) gaussian = EXP(-(difference/width)**2)
      82         3510 :             relaxation%pair_rate(iband, jband) = rate1 + (rate2 - rate1)*(1.0_dp - gaussian)
      83              :          END DO
      84              :       END DO
      85            5 :    END SUBROUTINE nlo_band_transition_prepare
      86              : 
      87              : ! **************************************************************************************************
      88              : !> \brief Return the central relaxation rate for one band pair.
      89              : !> \param relaxation Prepared band transition state
      90              : !> \param iband First band index
      91              : !> \param jband Second band index
      92              : !> \return Central damping rate of the selected band pair
      93              : ! **************************************************************************************************
      94        47320 :    FUNCTION nlo_band_transition_rate(relaxation, iband, jband) RESULT(rate)
      95              :       TYPE(nlo_band_transition_type), INTENT(IN)         :: relaxation
      96              :       INTEGER, INTENT(IN)                                :: iband, jband
      97              :       REAL(dp)                                           :: rate
      98              : 
      99        47320 :       CPASSERT(ALLOCATED(relaxation%pair_rate))
     100        47320 :       CPASSERT(iband >= 1)
     101        47320 :       CPASSERT(iband <= SIZE(relaxation%pair_rate, 1))
     102        47320 :       CPASSERT(jband >= 1)
     103        47320 :       CPASSERT(jband <= SIZE(relaxation%pair_rate, 2))
     104        47320 :       rate = relaxation%pair_rate(iband, jband)
     105        47320 :    END FUNCTION nlo_band_transition_rate
     106              : 
     107              : ! **************************************************************************************************
     108              : !> \brief Sum relaxation corrections for one complete Cartesian Taylor grade.
     109              : !> \param relaxation Prepared band transition state
     110              : !> \param hamiltonian Hamiltonian Taylor coefficients in the band basis
     111              : !> \param density Physical Taylor coefficients; only lower grades are read
     112              : !> \param grade Requested total Cartesian derivative order, between one and four
     113              : !> \param correction Corrections of this grade in nlo_derivative_indices order
     114              : !> \note For Y_l=(ad_H−w z_l)⁻¹ρ and R_l,α=−Σ_{0<β≤α}[H_β,Y_l,α−β],
     115              : !>       Y_l,α=(ρ_α+R_l,α)/(Δε−w z_l). Only grades below the requested grade
     116              : !>       are needed in R_l,α. Reconstruct them for one contour point, accumulate
     117              : !>       all corrections of the requested grade, then reuse the workspace.
     118              : !>       No band-sized array carries a contour-point dimension. At grade four,
     119              : !>       20 lower-grade matrices replace 35 matrices for each of 96 points.
     120              : ! **************************************************************************************************
     121           10 :    SUBROUTINE nlo_band_transition_correction(relaxation, hamiltonian, density, grade, correction)
     122              :       TYPE(nlo_band_transition_type), INTENT(IN)         :: relaxation
     123              :       COMPLEX(dp), INTENT(IN)                            :: hamiltonian(:, :, :), density(:, :, :)
     124              :       INTEGER, INTENT(IN)                                :: grade
     125              :       COMPLEX(dp), INTENT(OUT)                           :: correction(:, :, :)
     126              : 
     127              :       COMPLEX(dp)                                        :: weight
     128           10 :       COMPLEX(dp), ALLOCATABLE                           :: inverse(:, :), lower_density(:, :, :), &
     129           10 :                                                             matrix_term(:, :), remainder(:, :)
     130              :       INTEGER :: alpha(3, nlo_n_derivatives), ia, iband, ibeta, igamma, ipoint, jband, nband, &
     131              :          ncoeff, nlower, partner(nlo_n_derivatives, nlo_n_derivatives)
     132              : 
     133           10 :       CPASSERT(grade >= 1 .AND. grade <= 4)
     134           10 :       CPASSERT(ALLOCATED(relaxation%pair_rate))
     135           10 :       nband = SIZE(relaxation%pair_rate, 1)
     136           10 :       nlower = nlo_derivative_count(grade - 1)
     137           10 :       ncoeff = nlo_derivative_count(grade)
     138           10 :       CPASSERT(SIZE(hamiltonian, 1) == nband)
     139           10 :       CPASSERT(SIZE(hamiltonian, 2) == nband)
     140           10 :       CPASSERT(SIZE(hamiltonian, 3) >= ncoeff)
     141           10 :       CPASSERT(SIZE(density, 1) == nband)
     142           10 :       CPASSERT(SIZE(density, 2) == nband)
     143           10 :       CPASSERT(SIZE(density, 3) >= nlower)
     144           10 :       CPASSERT(SIZE(correction, 1) == nband)
     145           10 :       CPASSERT(SIZE(correction, 2) == nband)
     146           10 :       CPASSERT(SIZE(correction, 3) == ncoeff - nlower)
     147              :       ALLOCATE (inverse(nband, nband), lower_density(nband, nband, nlower), &
     148          120 :                 remainder(nband, nband), matrix_term(nband, nband))
     149           10 :       CALL nlo_derivative_indices(alpha)
     150           10 :       partner = 0
     151          121 :       DO ia = 2, ncoeff
     152         1255 :          DO ibeta = 2, ia
     153         4647 :             partner(ibeta, ia) = derivatives_index(alpha, alpha(:, ia) - alpha(:, ibeta))
     154              :          END DO
     155              :       END DO
     156        45705 :       correction = CMPLX(0.0_dp, 0.0_dp, dp)
     157          970 :       DO ipoint = 1, SIZE(relaxation%integration_points)
     158        25920 :          DO jband = 1, nband
     159       674880 :             DO iband = 1, nband
     160              :                inverse(iband, jband) = 1.0_dp/ &
     161              :                                        (relaxation%energies(iband) - relaxation%energies(jband) - &
     162       673920 :                                         relaxation%width*relaxation%integration_points(ipoint))
     163              :             END DO
     164              :          END DO
     165          960 :          weight = relaxation%width*relaxation%integration_weights(ipoint)
     166        12586 :          DO ia = 1, ncoeff
     167        11616 :             remainder = CMPLX(0.0_dp, 0.0_dp, dp)
     168       120480 :             DO ibeta = 2, ia
     169       108864 :                igamma = partner(ibeta, ia)
     170       108864 :                IF (igamma == 0) CYCLE
     171    647515296 :                matrix_term(:, :) = MATMUL(hamiltonian(:, :, ibeta), lower_density(:, :, igamma))
     172     24903072 :                remainder(:, :) = remainder - matrix_term
     173    647515296 :                matrix_term(:, :) = MATMUL(lower_density(:, :, igamma), hamiltonian(:, :, ibeta))
     174     24988128 :                remainder(:, :) = remainder + matrix_term
     175              :             END DO
     176      8166048 :             remainder(:, :) = remainder*inverse
     177        12576 :             IF (ia <= nlower) THEN
     178      3779328 :                lower_density(:, :, ia) = density(:, :, ia)*inverse + remainder
     179              :             ELSE
     180      4386720 :                correction(:, :, ia - nlower) = correction(:, :, ia - nlower) + weight*remainder
     181              :             END IF
     182              :          END DO
     183              :       END DO
     184        45705 :       correction = CMPLX(relaxation%rate_difference, 0.0_dp, dp)*correction
     185           10 :    END SUBROUTINE nlo_band_transition_correction
     186              : 
     187              : ! **************************************************************************************************
     188              : !> \brief Generate integration points and weights for the Gaussian matrix function.
     189              : !> \param points Complex contour integration points
     190              : !> \param weights Weights for the complex contour integration
     191              : !> \note f(x)=exp(-x²) equals the difference of Cauchy integrals on the
     192              : !>       lines Im(z)=±h. Along each line, f(x±ih)=exp(h²)exp(-x²)exp(∓2ixh).
     193              : !>       Eigenvalues of the Hermite Jacobi matrix are quadrature nodes; the
     194              : !>       squared first-row eigenvector entries determine quadrature weights.
     195              : !>       The numerical rule uses 48 nodes per line at height h=2.5. These
     196              : !>       choices resolve f and its first four derivatives to about 2e-14
     197              : !>       scaled absolute error in checks over −10≤x≤10; they are not model
     198              : !>       parameters. Points and weights belong to the calling transition state.
     199              : ! **************************************************************************************************
     200            5 :    SUBROUTINE nlo_gaussian_quadrature(points, weights)
     201              :       COMPLEX(dp), ALLOCATABLE, INTENT(OUT)              :: points(:), weights(:)
     202              : 
     203              :       INTEGER, PARAMETER                                 :: n_hermite = 48
     204              :       REAL(dp), PARAMETER                                :: height = 2.5_dp
     205              : 
     206              :       COMPLEX(dp)                                        :: factor
     207              :       INTEGER                                            :: info, ipoint
     208              :       REAL(dp)                                           :: jacobi(n_hermite, n_hermite), &
     209              :                                                             nodes(n_hermite), quadrature_weight, &
     210              :                                                             work(3*n_hermite), x
     211              : 
     212            5 :       ALLOCATE (points(2*n_hermite), weights(2*n_hermite))
     213            5 :       jacobi = 0.0_dp
     214          240 :       DO ipoint = 1, n_hermite - 1
     215          235 :          jacobi(ipoint, ipoint + 1) = SQRT(REAL(ipoint, dp)/2.0_dp)
     216          240 :          jacobi(ipoint + 1, ipoint) = jacobi(ipoint, ipoint + 1)
     217              :       END DO
     218            5 :       CALL dsyev('V', 'U', n_hermite, jacobi, n_hermite, nodes, work, SIZE(work), info)
     219            5 :       IF (info /= 0) CPABORT('NLO Gaussian contour quadrature failed.')
     220          245 :       DO ipoint = 1, n_hermite
     221          240 :          x = nodes(ipoint)
     222          240 :          quadrature_weight = SQRT(pi)*jacobi(1, ipoint)**2
     223          240 :          factor = quadrature_weight*EXP(height**2)/(2.0_dp*pi*gaussi)
     224          240 :          points(ipoint) = CMPLX(x, -height, dp)
     225          240 :          points(ipoint + n_hermite) = CMPLX(x, height, dp)
     226          240 :          weights(ipoint) = -factor*EXP(2.0_dp*gaussi*x*height)
     227          245 :          weights(ipoint + n_hermite) = factor*EXP(-2.0_dp*gaussi*x*height)
     228              :       END DO
     229            5 :    END SUBROUTINE nlo_gaussian_quadrature
     230              : 
     231            0 : END MODULE nlo_T1_T2_band_transition
        

Generated by: LCOV version 2.0-1